Skip to content

Add Copy markdown to copy citation #13387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b9ab287
fix:Added copy Markdown to copy citation #12552.
tushar-panto Jun 21, 2025
9de6531
Merge branch 'main' into fix-for-issue-12552
tushar-2320 Jun 21, 2025
ad09503
Merge branch 'main' into fix-for-issue-12552
tushar-2320 Jun 21, 2025
84a1dd1
Merge branch 'main' into fix-for-issue-12552
tushar-2320 Jun 22, 2025
8bed13b
Merge branch 'main' into fix-for-issue-12552
tushar-2320 Jun 22, 2025
fae3c18
Merge branch 'main' into fix-for-issue-12552
tushar-2320 Jun 23, 2025
49b035b
fix:Added copy Markdown to copy citation #12552.
tushar-panto Jun 23, 2025
8654adc
Merge branch 'main' into fix-for-issue-12552
tushar-2320 Jun 24, 2025
d582566
fix:Added copy Markdown to copy citation #12552.
tushar-panto Jun 24, 2025
9c32813
Merge remote-tracking branch 'origin/fix-for-issue-12552' into fix-fo…
tushar-panto Jun 24, 2025
508b93d
fix:Added @visibleForTesting in method processMarkdown #12552.
tushar-panto Jun 27, 2025
d131b92
Merge branch 'main' into fix-for-issue-12552
koppor Jul 7, 2025
0553179
Merge branch 'main' into fix-for-issue-12552
tushar-2320 Jul 19, 2025
529c9f0
Merge remote-tracking branch 'origin/fix-for-issue-12552' into fix-fo…
tushar-panto Jul 19, 2025
e805e7e
fix:submodule removal
tushar-panto Jul 19, 2025
7b3fbf7
fix:Added @visibleForTesting in method processMarkdown #12552.
tushar-panto Jul 19, 2025
b3eb93c
Revert submodule changes to match main
tushar-panto Jul 19, 2025
b1811e2
Reset submodule pointers to match main branch
tushar-panto Jul 19, 2025
34b387f
Merge branch 'main' into fix-for-issue-12552
calixtus Jul 20, 2025
756efcf
Merge branch 'main' into fix-for-issue-12552
tushar-2320 Jul 21, 2025
f6b4131
refactor:removed unecessary debugging statements and whitespace strip…
tushar-panto Jul 21, 2025
85dce83
refactor:used List.of instead of Array.asList
tushar-panto Jul 21, 2025
76eae89
Merge branch 'main' into fix-for-issue-12552
tushar-2320 Jul 23, 2025
9071097
Merge branch 'JabRef:main' into fix-for-issue-12552
tushar-2320 Jul 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public enum StandardActions implements Action {
COPY_KEY_AND_LINK(Localization.lang("Copy citation key and link"), KeyBinding.COPY_CITATION_KEY_AND_LINK),
COPY_CITATION_HTML(Localization.lang("Copy citation (html)"), KeyBinding.COPY_PREVIEW),
COPY_CITATION_TEXT(Localization.lang("Copy citation (text)")),
COPY_CITATION_MARKDOWN(Localization.lang("Copy citation (markdown)")),
COPY_CITATION_PREVIEW(Localization.lang("Copy preview"), KeyBinding.COPY_PREVIEW),
EXPORT_TO_CLIPBOARD(Localization.lang("Export to clipboard"), IconTheme.JabRefIcons.EXPORT_TO_CLIPBOARD),
EXPORT_SELECTED_TO_CLIPBOARD(Localization.lang("Export selected entries to clipboard"), IconTheme.JabRefIcons.EXPORT_TO_CLIPBOARD),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ private static Menu createCopySubMenu(ActionFactory factory,
if (previewPreferences.getSelectedPreviewLayout() instanceof CitationStylePreviewLayout) {
copySpecialMenu.getItems().addAll(
factory.createMenuItem(StandardActions.COPY_CITATION_HTML, new CopyCitationAction(CitationStyleOutputFormat.HTML, dialogService, stateManager, clipBoardManager, taskExecutor, preferences, abbreviationRepository)),
factory.createMenuItem(StandardActions.COPY_CITATION_TEXT, new CopyCitationAction(CitationStyleOutputFormat.TEXT, dialogService, stateManager, clipBoardManager, taskExecutor, preferences, abbreviationRepository)));
factory.createMenuItem(StandardActions.COPY_CITATION_TEXT, new CopyCitationAction(CitationStyleOutputFormat.TEXT, dialogService, stateManager, clipBoardManager, taskExecutor, preferences, abbreviationRepository)),
factory.createMenuItem(StandardActions.COPY_CITATION_MARKDOWN, new CopyCitationAction(CitationStyleOutputFormat.MARKDOWN, dialogService, stateManager, clipBoardManager, taskExecutor, preferences, abbreviationRepository)));
} else {
copySpecialMenu.getItems().add(factory.createMenuItem(StandardActions.COPY_CITATION_PREVIEW, new CopyCitationAction(CitationStyleOutputFormat.HTML, dialogService, stateManager, clipBoardManager, taskExecutor, preferences, abbreviationRepository)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import com.airhacks.afterburner.injection.Injector;
import com.google.common.annotations.VisibleForTesting;
import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;

public class ClipboardContentGenerator {

Expand All @@ -45,6 +46,7 @@ public ClipboardContent generate(List<BibEntry> selectedEntries, CitationStyleOu
return switch (outputFormat) {
case HTML -> processHtml(citations);
case TEXT -> processText(citations);
case MARKDOWN -> processMarkdown(citations);
};
} else {
// if it is not a citation style take care of the preview
Expand Down Expand Up @@ -120,6 +122,32 @@ static ClipboardContent processHtml(List<String> citations) {
return content;
}

/**
* Insert each citation into HTML.
* convert HTML to markdown using flexmark.
*/
Comment on lines +125 to +128
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is trivial and simply restates what the code does without providing additional information about the reasoning or important details about the implementation.

@VisibleForTesting
static ClipboardContent processMarkdown(List<String> citations) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method uses string concatenation for multiline HTML template instead of Java text blocks ("""). This makes the code less readable and maintainable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You followed @Siedlerchr's recommendation and did not follow mine to use citeproc-java conversion. (michel-kraemer/citeproc-java@66cad6b)

There needs to be AT LEAST a comment, why citeproc-java could not be used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was unaware of this, good point

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe my comment here #13387 (comment) is of help? Just to try out how to route things to that plugin?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it works for all previews! Not just csl. I see no advantage in using citeproc here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only point is that find citeproc more configurable than flexmark.
flexmark do that only in one line.
in citeproc I think we have to write a function to do that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do case handling

If CSL use citeproc (specialized!, e.g. DOI linked)

If no CSL, use flexmark

String result = "<!DOCTYPE html>" + OS.NEWLINE +
"<html>" + OS.NEWLINE +
" <head>" + OS.NEWLINE +
" <meta charset=\"utf-8\">" + OS.NEWLINE +
" </head>" + OS.NEWLINE +
" <body>" + OS.NEWLINE + OS.NEWLINE;

result += String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations);
result += OS.NEWLINE +
" </body>" + OS.NEWLINE +
"</html>" + OS.NEWLINE;

FlexmarkHtmlConverter converter = FlexmarkHtmlConverter.builder().build();
String markdown = converter.convert(result);

ClipboardContent content = new ClipboardContent();
content.putString(markdown);
return content;
}

private List<String> generateTextBasedPreviewLayoutCitations(List<BibEntry> selectedEntries, BibDatabaseContext bibDatabaseContext) throws IOException {
TextBasedPreviewLayout customPreviewLayout = previewPreferences.getCustomPreviewLayout();
Reader customLayoutReader = Reader.of(customPreviewLayout.getText().replace("__NEWLINE__", "\n"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,32 @@ void processHtmlAsHtml() {
Object actual = htmlTransferable.getHtml();
assertEquals(expected, actual);
}

@Test
void processMarkdownAsMarkdown() {
String expected = "\\[1\\] \n" +
"B. Smith, B. Jones, and J. Williams, \"Title of the test entry,\" *BibTeX Journal*, vol. 34, no. 3, pp. 45--67, Jul. 2016.\n" +
"\n" +
"\\[1\\] \n" +
"B. Smith, B. Jones, and J. Williams, \"Title of the test entry,\" *BibTeX Journal*, vol. 34, no. 3, pp. 45--67, Jul. 2016.\n";

String citation = " <div class=\"csl-entry\">" + OS.NEWLINE +
" <div class=\"csl-left-margin\">[1]</div><div class=\"csl-right-inline\">B. Smith, B. Jones, and J. Williams, “Title of the test entry,” <i>BibTeX Journal</i>, vol. 34, no. 3, pp. 45–67, Jul. 2016.</div>" + OS.NEWLINE +
" </div>" + OS.NEWLINE;

ClipboardContent markdown = ClipboardContentGenerator.processMarkdown(Arrays.asList(citation, citation));
String actual = markdown.getString();

// Print actual output for debugging
System.out.println("=== Actual Markdown Output ===");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for these, on failure assertEquals will show the diff

System.out.println(actual);
System.out.println("=== End ===");

// Normalize both strings to ignore whitespace and formatting issues
String normalizedActual = actual.replaceAll("\\s+", " ").trim();
String normalizedExpected = expected.replaceAll("\\s+", " ").trim();
Copy link
Member

@subhramit subhramit Jul 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are "formatting issues" here specifically?
Given we know the expected string, can we trace where the extra whitespaces might come from in the actual?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually you are right I think I was getting cautious that is why I was removing whitespaces.
but I understood that it overall fails the point of testing.


assertEquals(normalizedExpected, normalizedActual);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
public enum CitationStyleOutputFormat {

HTML("html", OS.NEWLINE + "<br>" + OS.NEWLINE),
TEXT("text", "");
TEXT("text", ""),
MARKDOWN("markdown", "");

private final String format;
private final String lineSeparator;
Expand Down
2 changes: 2 additions & 0 deletions jablib/src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ Copy=Copy
Copy\ title=Copy title
Copy\ citation\ (html)=Copy citation (html)
Copy\ citation\ (text)=Copy citation (text)
Copy\ citation\ (markdown)=Copy citation (markdown)

Copy\ citation\ key=Copy citation key
Copy\ citation\ key\ and\ link=Copy citation key and link
Copy\ citation\ key\ and\ title=Copy citation key and title
Expand Down
Loading