From 67d60628e1f10042557533c27989154183224fe9 Mon Sep 17 00:00:00 2001 From: Christoph Date: Wed, 16 Oct 2024 07:03:47 +0200 Subject: [PATCH 01/10] fix not on fx thread (#11974) Fixes https://github.com/JabRef/jabref/issues/11966 --- .../java/org/jabref/gui/undo/CountingUndoManager.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/gui/undo/CountingUndoManager.java b/src/main/java/org/jabref/gui/undo/CountingUndoManager.java index 1e4eaa8981d..6a0c4a557e5 100644 --- a/src/main/java/org/jabref/gui/undo/CountingUndoManager.java +++ b/src/main/java/org/jabref/gui/undo/CountingUndoManager.java @@ -10,13 +10,15 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleIntegerProperty; +import org.jabref.gui.util.UiTaskExecutor; + public class CountingUndoManager extends UndoManager { private int unchangedPoint; /** * Indicates the number of edits aka balance of edits on the stack +1 when an edit is added/redone and -1 when an edit is undoed. - * */ + */ private final IntegerProperty balanceProperty = new SimpleIntegerProperty(0); private final BooleanProperty undoableProperty = new SimpleBooleanProperty(false); private final BooleanProperty redoableProperty = new SimpleBooleanProperty(false); @@ -67,11 +69,11 @@ private void decrementBalance() { } private void updateUndoableStatus() { - undoableProperty.setValue(canUndo()); + UiTaskExecutor.runInJavaFXThread(() -> undoableProperty.setValue(canUndo())); } private void updateRedoableStatus() { - redoableProperty.setValue(canRedo()); + UiTaskExecutor.runInJavaFXThread(() -> redoableProperty.setValue(canRedo())); } public ReadOnlyBooleanProperty getUndoableProperty() { From 19b7c43b27ffc971f36ded4a01cd145cffed6d5b Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 16 Oct 2024 09:10:37 +0200 Subject: [PATCH 02/10] Update github-action-move-issues (#11976) --- .github/workflows/on-labeled.yml | 8 ++++---- .github/workflows/on-unlabeled.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/on-labeled.yml b/.github/workflows/on-labeled.yml index e90a9d32599..84689f7b915 100644 --- a/.github/workflows/on-labeled.yml +++ b/.github/workflows/on-labeled.yml @@ -30,7 +30,7 @@ jobs: Happy coding! 🚀 - name: Move Issue to "Assigned" Column in "Candidates for University Projects" - uses: m7kvqbe1/github-action-move-issues@v1.0.9 + uses: m7kvqbe1/github-action-move-issues@v1.1.1 with: github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} project-url: "https://github.com/orgs/JabRef/projects/3" @@ -38,7 +38,7 @@ jobs: target-column: "Assigned" ignored-columns: "" - name: Move Issue to "Assigned" Column in "Good First Issues" - uses: m7kvqbe1/github-action-move-issues@v1.0.9 + uses: m7kvqbe1/github-action-move-issues@v1.1.1 with: github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} project-url: "https://github.com/orgs/JabRef/projects/5" @@ -53,7 +53,7 @@ jobs: issues: write steps: - name: Move Issue to "Assigned" Column in "Candidates for University Projects" - uses: m7kvqbe1/github-action-move-issues@v1.0.9 + uses: m7kvqbe1/github-action-move-issues@v1.1.1 with: github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} project-url: "https://github.com/orgs/JabRef/projects/3" @@ -61,7 +61,7 @@ jobs: target-column: "Assigned" ignored-columns: "" - name: Move Issue to "Assigned" Column in "Good First Issues" - uses: m7kvqbe1/github-action-move-issues@v1.0.9 + uses: m7kvqbe1/github-action-move-issues@v1.1.1 with: github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} project-url: "https://github.com/orgs/JabRef/projects/5" diff --git a/.github/workflows/on-unlabeled.yml b/.github/workflows/on-unlabeled.yml index aca9773385c..b43210792c9 100644 --- a/.github/workflows/on-unlabeled.yml +++ b/.github/workflows/on-unlabeled.yml @@ -16,7 +16,7 @@ jobs: issues: write steps: - name: Move Issue to "Free to take" Column in "Candidates for University Projects" - uses: m7kvqbe1/github-action-move-issues@feat/default-column-label-remove + uses: m7kvqbe1/github-action-move-issues@v1.1.1 with: github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} project-url: "https://github.com/orgs/JabRef/projects/3" @@ -25,7 +25,7 @@ jobs: ignored-columns: "" default-column: "Free to take" - name: Move Issue to "Free to take" Column in "Good First Issues" - uses: m7kvqbe1/github-action-move-issues@feat/default-column-label-remove + uses: m7kvqbe1/github-action-move-issues@v1.1.1 with: github-token: ${{ secrets.GH_TOKEN_ACTION_MOVE_ISSUE }} project-url: "https://github.com/orgs/JabRef/projects/5" From 55bda9ed52c713e8aa14904489dc79a0c196753d Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 16 Oct 2024 09:44:39 +0200 Subject: [PATCH 03/10] Enable "automerge" label handling on a PR. (#11979) --- .../{on-labeled.yml => on-labeled-issue.yml} | 5 +--- .github/workflows/on-labeled-pr.yml | 23 +++++++++++++++++++ ...n-unlabeled.yml => on-unlabeled-issue.yml} | 5 +--- 3 files changed, 25 insertions(+), 8 deletions(-) rename .github/workflows/{on-labeled.yml => on-labeled-issue.yml} (98%) create mode 100644 .github/workflows/on-labeled-pr.yml rename .github/workflows/{on-unlabeled.yml => on-unlabeled-issue.yml} (93%) diff --git a/.github/workflows/on-labeled.yml b/.github/workflows/on-labeled-issue.yml similarity index 98% rename from .github/workflows/on-labeled.yml rename to .github/workflows/on-labeled-issue.yml index 84689f7b915..d70b37528e9 100644 --- a/.github/workflows/on-labeled.yml +++ b/.github/workflows/on-labeled-issue.yml @@ -1,12 +1,9 @@ -name: On labeled +name: On labeled issue on: issues: types: - labeled - pull_request_target: - types: - - labeled jobs: FirstTimeCodeContribution: diff --git a/.github/workflows/on-labeled-pr.yml b/.github/workflows/on-labeled-pr.yml new file mode 100644 index 00000000000..4ceb3844fe7 --- /dev/null +++ b/.github/workflows/on-labeled-pr.yml @@ -0,0 +1,23 @@ +name: On labeled PR + +on: + pull_request: + types: + - labeled + +jobs: + automerge: + name: Auto Merge + if: "${{ github.event.label.name == 'automerge' }}" + runs-on: ubuntu-latest + steps: + - name: Approve PR + run: gh pr review --approve "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GH_TOKEN_JABREF_MACHINE_PR_APPROVE}} + - name: Merge PR + run: gh pr merge --auto --squash "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GH_TOKEN_UPDATE_GRADLE_WRAPPER}} diff --git a/.github/workflows/on-unlabeled.yml b/.github/workflows/on-unlabeled-issue.yml similarity index 93% rename from .github/workflows/on-unlabeled.yml rename to .github/workflows/on-unlabeled-issue.yml index b43210792c9..0947fd05c2a 100644 --- a/.github/workflows/on-unlabeled.yml +++ b/.github/workflows/on-unlabeled-issue.yml @@ -1,12 +1,9 @@ -name: On unlabeled +name: On unlabeled issue on: issues: types: - unlabeled - pull_request_target: - types: - - unlabeled jobs: FirstTimeCodeContribution_or_Assigned: From 703526328f43acacd72fad85fdeac8f32c58b685 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 16 Oct 2024 09:45:11 +0200 Subject: [PATCH 04/10] Add links to our setup guideline. (#11978) * Add links to our setup guideline. * Add link to PRs (to ensore that not koppors fork is used) * Fix casing --- CONTRIBUTING.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 90f735fa4a3..4623b2bc6aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,7 +53,6 @@ Check out the [documentation for developers](https://devdocs.jabref.org/contribu For improving developer's documentation, go on at the [docs/ subdirectory of JabRef's code](https://github.com/JabRef/jabref/tree/main/docs) and edit the file. GitHub offers a good guide at [Editing files in another user's repository](https://help.github.com/en/github/managing-files-in-a-repository/editing-files-in-another-users-repository). - One can also add [callouts](https://just-the-docs.github.io/just-the-docs-tests/components/callouts/). ## Getting a task assigned @@ -63,20 +62,23 @@ GitHub will then automatically assign you. ## Pull Request Process -1. **Create a new branch** (such as `fix-for-issue-121`). Be sure to create a **separate branch** for each improvement you implement. -2. Work on the **new branch — not the `main` branch.** Refer to our [code how-tos](https://devdocs.jabref.org/code-howtos) if you have questions about your implementation. -3. Create a pull request. For an overview of pull requests, take a look at GitHub's [pull request help documentation](https://help.github.com/articles/about-pull-requests/). +1. Follow the steps at [Pre Condition 3: Code on the local machine](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/pre-03-code.html) to a) create a fork and b) have the fork checked out on your local machine +2. Ensure that you followed the [steps to set up a local workspace](https://devdocs.jabref.org/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/) to have the code running properly in IntelliJ. +3. **Create a new branch** (such as `fix-for-issue-121`). Be sure to create a **separate branch** for each improvement you implement. +4. Work on the **new branch — not the `main` branch.** Refer to our [code how-tos](https://devdocs.jabref.org/code-howtos) if you have questions about your implementation. +5. Create a [pull request to JabRef main repository](https://github.com/JabRef/jabref/pulls). + For an overview on the concept of pull requests, take a look at GitHub's [pull request help documentation](https://help.github.com/articles/about-pull-requests/). 1. Ensure that you followed the requirements listed below. They are not too hard, they merely support the maintainers to focus on supportive feedback than just stating the obvious. 2. For text inspirations, consider [How to write the perfect pull request](https://github.com/blog/1943-how-to-write-the-perfect-pull-request). 3. In case your pull request is not yet complete or not yet ready for review, create a [draft pull request](https://github.blog/2019-02-14-introducing-draft-pull-requests/) instead. -4. Wait for feedback of the developers -5. Address the feedback of the developers -6. After two developers gave their green flag, the pull request will be merged. +6. Wait for feedback of the developers +7. Address the feedback of the developers +8. After two developers gave their green flag, the pull request will be merged. In case you have any questions, please 1. comment on the issue, -2. show up in our [gitter chat](https://gitter.im/JabRef/jabref), or +2. show up in our [Gitter chat](https://gitter.im/JabRef/jabref), or 3. show your current code using a draft pull request and ask questions. We favor looking into your code using a draft pull request, because we can then also load the code into our IDE. From f1f66fa8e557bfa2bdd5f9f10da9556b7d6e583d Mon Sep 17 00:00:00 2001 From: Christoph Date: Wed, 16 Oct 2024 10:02:23 +0200 Subject: [PATCH 05/10] New translations jabref_en.properties (Spanish) (#11980) --- src/main/resources/l10n/JabRef_es.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/l10n/JabRef_es.properties b/src/main/resources/l10n/JabRef_es.properties index 08e245920f2..d725df6a49c 100644 --- a/src/main/resources/l10n/JabRef_es.properties +++ b/src/main/resources/l10n/JabRef_es.properties @@ -195,6 +195,7 @@ Custom\ entry\ types\ found\ in\ file=Se han encontrado tipos de entrada persona Customize\ entry\ types=Tipos de entrada personalizados +Customize\ keyboard\ shortcuts=Personalizar atajos de teclado Cut=Cortar @@ -264,6 +265,8 @@ Dynamically\ group\ entries\ by\ searching\ a\ field\ for\ a\ keyword=Agrupar en Each\ line\ must\ be\ of\ the\ following\ form\:\ 'tab\:field1;field2;...;fieldN'.=Cada línea debe seguir el siguiente formato\: 'tab\:field1;field2;...;fieldN'. +Migrate=Migrar +Keep\ as\ is=Dejar tal cual Edit=Editar Edit\ file\ type=Editar tipo de archivo From e68783b15e97236ed8889ddd967fcac0ddfeb9d9 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 16 Oct 2024 10:16:17 +0200 Subject: [PATCH 06/10] Fix typo (#11981) --- .../intellij-12-build.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-12-build.md b/docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-12-build.md index 96680ba6de1..b67c0f6fb99 100644 --- a/docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-12-build.md +++ b/docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace/intellij-12-build.md @@ -50,7 +50,7 @@ If that does not exist, just select JDK 21. ![Gradle JVM is project SDK](guidelines-intellij-settings-gradle-gradlejvm-is-projectjvm.png) {% endfigure %} -## Enable compiliation by IntelliJ +## Enable compilation by IntelliJ To prepare IntelliJ's build system additional steps are required: From ec2059af58dc7b7793e9f6e0bafc8711140cd2d7 Mon Sep 17 00:00:00 2001 From: Zhenxiong Luo <146911309+KumaLuo@users.noreply.github.com> Date: Wed, 16 Oct 2024 19:19:41 +1100 Subject: [PATCH 07/10] Add compare button to duplicates in Citation relations tab (#11915) * - Added a "Compare" button for duplicate entries in the CitationRelationsTab. - Added localization key for 'Compare with duplicate entries'. * - Implemented functionality to open a "Possible duplicate entries" for comparing and merging duplicate entries. - Updated changelog for compare button feature. * Updated changelog * - Updated localization key for compare button tooltip. - Fixed bug that when adding an entry to the library from Citation Relations Tab by adding the entry's clone instead of itself. - Optimised openPossibleDuplicateEntriesWindow function in CitationRelationsTab.java to show result of undo and redo. - Implemented that After clicking "merge", the current entry will be kept selected - and not the merged entry be selected. * Modified CitationsRelationsTabViewModel and ImportHandler to pass CitationsRelationsTabViewModelTest with clone entries. * - Deleted old code in CitationRelationTab.java which to implement that original entry be selected after citation item merge. - Modified MainTable#clearAndSelect to ensure original entry be selected after citation item merge. - Added some comments. * Optimised citation relations item merge: Added a citation merge flag in MainTable.java to let original entry get selected after merge instead of selecting new merged entry. * Optimised MainTable#clearAndSelect: make the code look more concise. * Fixed bug: As original local entry of citation relation item has been changed to new merged entry, need to refresh selected citation relation item to ensure that the item link to current local entry instead of the old one. * Adapted tool tip of compare button. * - renamed some variables to make them more understandable - fixed wrong position codes: codes that updating citation relation item and setting state of citationMergeMode now be moved into CitationRelationsTab#openPossibleDuplicateEntriesWindow - modified some comments and Java doc * Move statement closer to intended use * Modified the column headings of the merge entries dialog to make them more self-explanatory. --------- Co-authored-by: Oliver Kopp --- CHANGELOG.md | 1 + .../CitationRelationsTab.java | 57 +++++++++++++++++++ .../CitationsRelationsTabViewModel.java | 1 + .../gui/externalfiles/ImportHandler.java | 1 + .../org/jabref/gui/maintable/MainTable.java | 22 +++++-- .../gui/mergeentries/MergeEntriesDialog.java | 8 +++ src/main/resources/l10n/JabRef_en.properties | 4 ++ 7 files changed, 89 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa487a1574a..6ca4820613e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We added a different background color to the search bar to indicate when the search syntax is wrong. [#11658](https://github.com/JabRef/jabref/pull/11658) - We added a setting which always adds the literal "Cited on pages" text before each JStyle citation. [#11691](https://github.com/JabRef/jabref/pull/11732) - We added a new plain citation parser that uses LLMs. [#11825](https://github.com/JabRef/jabref/issues/11825) +- We added a compare button to the duplicates in the citation relations tab to open the "Possible duplicate entries" window. [#11192](https://github.com/JabRef/jabref/issues/11192) - We added automatic browser extension install on Windows for Chrome and Edge. [#6076](https://github.com/JabRef/jabref/issues/6076) - We added a search bar for filtering keyboard shortcuts. [#11686](https://github.com/JabRef/jabref/issues/11686) - By double clicking on a local citation in the Citation Relations Tab you can now jump the the linked entry. [#11955](https://github.com/JabRef/jabref/pull/11955) diff --git a/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java b/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java index 48403a3d16d..a550a0098a7 100644 --- a/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationRelationsTab.java @@ -5,6 +5,7 @@ import java.net.URI; import java.util.Arrays; import java.util.List; +import java.util.Optional; import javax.swing.undo.UndoManager; @@ -39,7 +40,12 @@ import org.jabref.gui.entryeditor.citationrelationtab.semanticscholar.CitationFetcher; import org.jabref.gui.entryeditor.citationrelationtab.semanticscholar.SemanticScholarFetcher; import org.jabref.gui.icon.IconTheme; +import org.jabref.gui.mergeentries.EntriesMergeResult; +import org.jabref.gui.mergeentries.MergeEntriesDialog; import org.jabref.gui.preferences.GuiPreferences; +import org.jabref.gui.undo.NamedCompound; +import org.jabref.gui.undo.UndoableInsertEntries; +import org.jabref.gui.undo.UndoableRemoveEntries; import org.jabref.gui.util.NoSelectionModel; import org.jabref.gui.util.ViewModelListCellFactory; import org.jabref.logic.bibtex.BibEntryWriter; @@ -51,6 +57,7 @@ import org.jabref.logic.os.OS; import org.jabref.logic.util.BackgroundTask; import org.jabref.logic.util.TaskExecutor; +import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.database.BibDatabaseModeDetection; @@ -89,6 +96,8 @@ public class CitationRelationsTab extends EntryEditorTab { private final CitationsRelationsTabViewModel citationsRelationsTabViewModel; private final DuplicateCheck duplicateCheck; private final BibEntryTypesManager entryTypesManager; + private final StateManager stateManager; + private final UndoManager undoManager; public CitationRelationsTab(DialogService dialogService, BibDatabaseContext databaseContext, @@ -104,6 +113,8 @@ public CitationRelationsTab(DialogService dialogService, this.preferences = preferences; this.libraryTab = libraryTab; this.taskExecutor = taskExecutor; + this.undoManager = undoManager; + this.stateManager = stateManager; setText(Localization.lang("Citation relations")); setTooltip(new Tooltip(Localization.lang("Show articles related by citation"))); @@ -238,6 +249,13 @@ private void styleFetchedListView(CheckListView listView) } }); vContainer.getChildren().add(jumpTo); + + Button compareButton = IconTheme.JabRefIcons.MERGE_ENTRIES.asButton(); + compareButton.setTooltip(new Tooltip(Localization.lang("Compare with existing entry"))); + compareButton.setOnMouseClicked(event -> { + openPossibleDuplicateEntriesWindow(entry, listView); + }); + vContainer.getChildren().add(compareButton); } else { ToggleButton addToggle = IconTheme.JabRefIcons.ADD.asToggleButton(); addToggle.setTooltip(new Tooltip(Localization.lang("Select entry"))); @@ -511,4 +529,43 @@ private void importEntries(List entriesToImport, CitationF dialogService.notify(Localization.lang("Number of entries successfully imported") + ": " + entriesToImport.size()); } + + /** + * Function to open possible duplicate entries window to compare duplicate entries + * + * @param citationRelationItem duplicate in the citation relations tab + * @param listView CheckListView to display citations + */ + private void openPossibleDuplicateEntriesWindow(CitationRelationItem citationRelationItem, CheckListView listView) { + BibEntry libraryEntry = citationRelationItem.localEntry(); + BibEntry citationEntry = citationRelationItem.entry(); + String leftHeader = Localization.lang("Library Entry"); + String rightHeader = Localization.lang("Citation Entry"); + + MergeEntriesDialog dialog = new MergeEntriesDialog(libraryEntry, citationEntry, leftHeader, rightHeader, preferences); + dialog.setTitle(Localization.lang("Possible duplicate entries")); + + Optional entriesMergeResult = dialogService.showCustomDialogAndWait(dialog); + entriesMergeResult.ifPresentOrElse(mergeResult -> { + + BibEntry mergedEntry = mergeResult.mergedEntry(); + // update local entry of selected citation relation item + listView.getItems().set(listView.getItems().indexOf(citationRelationItem), new CitationRelationItem(citationRelationItem.entry(), mergedEntry, true)); + + // Merge method is similar to MergeTwoEntriesAction#execute + BibDatabase database = stateManager.getActiveDatabase().get().getDatabase(); + database.removeEntry(mergeResult.originalLeftEntry()); + libraryTab.getMainTable().setCitationMergeMode(true); + database.insertEntry(mergedEntry); + + NamedCompound ce = new NamedCompound(Localization.lang("Merge entries")); + ce.addEdit(new UndoableRemoveEntries(database, mergeResult.originalLeftEntry())); + ce.addEdit(new UndoableInsertEntries(stateManager.getActiveDatabase().get().getDatabase(), mergedEntry)); + ce.end(); + + undoManager.addEdit(ce); + + dialogService.notify(Localization.lang("Merged entries")); + }, () -> dialogService.notify(Localization.lang("Canceled merging entries"))); + } } diff --git a/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationsRelationsTabViewModel.java b/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationsRelationsTabViewModel.java index 7ae52965b8f..630ee2e387e 100644 --- a/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationsRelationsTabViewModel.java +++ b/src/main/java/org/jabref/gui/entryeditor/citationrelationtab/CitationsRelationsTabViewModel.java @@ -64,6 +64,7 @@ private void importCites(List entries, BibEntry existingEntry, ImportH List citeKeys = getExistingEntriesFromCiteField(existingEntry); citeKeys.removeIf(String::isEmpty); + for (BibEntry entryToCite : entries) { if (generateNewKeyOnImport || entryToCite.getCitationKey().isEmpty()) { String key = generator.generateKey(entryToCite); diff --git a/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java b/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java index 669aa9a21bc..8e89ab5026f 100644 --- a/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java +++ b/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java @@ -194,6 +194,7 @@ public void importEntries(List entries) { } public void importCleanedEntries(List entries) { + entries = entries.stream().map(entry -> (BibEntry) entry.clone()).toList(); bibDatabaseContext.getDatabase().insertEntries(entries); generateKeys(entries); setAutomaticFields(entries); diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index 4a94fd56b5f..70285478536 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -82,6 +82,7 @@ public class MainTable extends TableView { private long lastKeyPressTime; private String columnSearchTerm; + private boolean citationMergeMode = false; public MainTable(MainTableDataModel model, LibraryTab libraryTab, @@ -249,11 +250,18 @@ public void listen(EntriesAddedEvent event) { } public void clearAndSelect(BibEntry bibEntry) { - getSelectionModel().clearSelection(); - findEntry(bibEntry).ifPresent(entry -> { - getSelectionModel().select(entry); - scrollTo(entry); - }); + // check if entries merged from citation relations tab + if (citationMergeMode) { + // keep original entry selected and reset citation merge mode + this.citationMergeMode = false; + } else { + // select new entry + getSelectionModel().clearSelection(); + findEntry(bibEntry).ifPresent(entry -> { + getSelectionModel().select(entry); + scrollTo(entry); + }); + } } private void scrollToNextMatchCategory() { @@ -492,4 +500,8 @@ private Optional findEntry(BibEntry entry) { .filter(viewModel -> viewModel.getEntry().equals(entry)) .findFirst(); } + + public void setCitationMergeMode(boolean citationMerge) { + this.citationMergeMode = citationMerge; + } } diff --git a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java index 9613b457991..dc485757be0 100644 --- a/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java +++ b/src/main/java/org/jabref/gui/mergeentries/MergeEntriesDialog.java @@ -23,6 +23,14 @@ public MergeEntriesDialog(BibEntry one, BibEntry two, GuiPreferences preferences init(); } + public MergeEntriesDialog(BibEntry one, BibEntry two, String leftHeader, String rightHeader, GuiPreferences preferences) { + threeWayMergeView = new ThreeWayMergeView(one, two, leftHeader, rightHeader, preferences); + this.one = one; + this.two = two; + + init(); + } + /** * Sets up the dialog */ diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 0d980636e73..cd741f10878 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2797,3 +2797,7 @@ Warning\:\ The\ selected\ directory\ is\ not\ a\ valid\ directory.=Warning: The Currently\ selected\ JStyle\:\ '%0' = Currently selected JStyle: '%0' Currently\ selected\ CSL\ Style\:\ '%0' = Currently selected CSL Style: '%0' Store\ url\ for\ downloaded\ file=Store url for downloaded file + +Compare\ with\ existing\ entry=Compare with existing entry +Library\ Entry=Library Entry +Citation\ Entry=Citation Entry From 0402d0899adff9921c5a9ce53f65aa69fec910e8 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 16 Oct 2024 10:30:43 +0200 Subject: [PATCH 08/10] Fix handling of escapings in bracketed patterns (#11967) * Add references to other tests * Simplify code * Add test for extracting the first word * Relax escaping * Add link to PR * Add tests Refs https://github.com/JabRef/jabref/issues/11367 * Refine CHANGELOG.md * Refine CHANGELOG.md --- CHANGELOG.md | 2 + .../citationkeypattern/BracketedPattern.java | 16 +++++-- .../bibtexfields/RegexFormatter.java | 14 +++++-- .../BracketedPatternTest.java | 42 +++++++++++++++---- .../MakeLabelWithDatabaseTest.java | 20 +++++++-- .../MakeLabelWithoutDatabaseTest.java | 29 ++++++++++++- .../bibtexfields/RegexFormatterTest.java | 6 +++ 7 files changed, 110 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ca4820613e..2a609a8267d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - ⚠️ Renamed command line parameters `embeddBibfileInPdf` to `embedBibFileInPdf`, `writeMetadatatoPdf` to `writeMetadataToPdf`, and `writeXMPtoPdf` to `writeXmpToPdf`. [#11575](https://github.com/JabRef/jabref/pull/11575) - The browse button for a Custom theme now opens in the directory of the current used CSS file. [#11597](https://github.com/JabRef/jabref/pull/11597) - The browse button for a Custom exporter now opens in the directory of the current used exporter file. [#11717](https://github.com/JabRef/jabref/pull/11717) +- ⚠️ We relaxed the escaping requirements for [bracketed patterns](https://docs.jabref.org/setup/citationkeypatterns), which are used for the [citaton key generator](https://docs.jabref.org/advanced/entryeditor#autogenerate-citation-key) and [filename and directory patterns](https://docs.jabref.org/finding-sorting-and-cleaning-entries/filelinks#auto-linking-files). One only needs to write `\"` if a quote sign should be escaped. All other escapings are not necessary (and working) any more. [#11967](https://github.com/JabRef/jabref/pull/11967) - JabRef now uses TLS 1.2 for all HTTPS connections. [#11852](https://github.com/JabRef/jabref/pull/11852) - We improved the display of long messages in the integrity check dialog. [#11619](https://github.com/JabRef/jabref/pull/11619) - We improved the undo/redo buttons in the main toolbar and main menu to be disabled when there is nothing to undo/redo. [#8807](https://github.com/JabRef/jabref/issues/8807) @@ -90,6 +91,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We fixed an issue where unescaped braces in the arXiv fetcher were not treated. [#11704](https://github.com/JabRef/jabref/issues/11704) - We fixed an issue where HTML instead of the fulltext pdf was downloaded when importing arXiv entries. [#4913](https://github.com/JabRef/jabref/issues/4913) - We fixed an issue where the keywords and crossref fields were not properly focused. [#11177](https://github.com/JabRef/jabref/issues/11177) +- We fixed handling of `\"` in [bracketed patterns](https://docs.jabref.org/setup/citationkeypatterns) containing a RegEx. [#11967](https://github.com/JabRef/jabref/pull/11967) - We fixed an issue where the Undo/Redo buttons were active even when all libraries are closed. [#11837](https://github.com/JabRef/jabref/issues/11837) - We fixed an issue where recently opened files were not displayed in the main menu properly. [#9042](https://github.com/JabRef/jabref/issues/9042) - We fixed an issue where the DOI lookup would show an error when a DOI was found for an entry. [#11850](https://github.com/JabRef/jabref/issues/11850) diff --git a/src/main/java/org/jabref/logic/citationkeypattern/BracketedPattern.java b/src/main/java/org/jabref/logic/citationkeypattern/BracketedPattern.java index 0447f748cef..519fcdafd34 100644 --- a/src/main/java/org/jabref/logic/citationkeypattern/BracketedPattern.java +++ b/src/main/java/org/jabref/logic/citationkeypattern/BracketedPattern.java @@ -209,11 +209,10 @@ public static String expandBrackets(String pattern, Character keywordDelimiter, */ public static Function expandBracketContent(Character keywordDelimiter, BibEntry entry, BibDatabase database) { return (String bracket) -> { - String expandedPattern; List fieldParts = parseFieldAndModifiers(bracket); // check whether there is a modifier on the end such as // ":lower": - expandedPattern = getFieldValue(entry, fieldParts.getFirst(), keywordDelimiter, database); + String expandedPattern = getFieldValue(entry, fieldParts.getFirst(), keywordDelimiter, database); if (fieldParts.size() > 1) { // apply modifiers: expandedPattern = applyModifiers(expandedPattern, fieldParts, 1, expandBracketContent(keywordDelimiter, entry, database)); @@ -233,6 +232,7 @@ public static Function expandBracketContent(Character keywordDel public static String expandBrackets(String pattern, Function bracketContentHandler) { Objects.requireNonNull(pattern); StringBuilder expandedPattern = new StringBuilder(); + pattern = pattern.replace("\\\"", "\u0A17"); StringTokenizer parsedPattern = new StringTokenizer(pattern, "\\[]\"", true); while (parsedPattern.hasMoreTokens()) { @@ -254,7 +254,7 @@ public static String expandBrackets(String pattern, Function bra } } - return expandedPattern.toString(); + return expandedPattern.toString().replace("\u0A17", "\\\""); } /** @@ -1140,11 +1140,19 @@ protected static List parseFieldAndModifiers(String arg) { } else if (currentChar == '\\') { if (escaped) { escaped = false; - current.append(currentChar); + // Only : needs to be escaped + // " -> regex("...", "...") - escaping should be passed through to the regex parser + // : -> :abc:def + current.append('\\'); + current.append('\\'); } else { escaped = true; } } else if (escaped) { + if (currentChar != ':') { + // Only : needs to be escaped + current.append('\\'); + } current.append(currentChar); escaped = false; } else { diff --git a/src/main/java/org/jabref/logic/formatter/bibtexfields/RegexFormatter.java b/src/main/java/org/jabref/logic/formatter/bibtexfields/RegexFormatter.java index 26859a82699..97bf67f0cff 100644 --- a/src/main/java/org/jabref/logic/formatter/bibtexfields/RegexFormatter.java +++ b/src/main/java/org/jabref/logic/formatter/bibtexfields/RegexFormatter.java @@ -15,26 +15,34 @@ public class RegexFormatter extends Formatter { public static final String KEY = "regex"; + private static final Logger LOGGER = LoggerFactory.getLogger(RegexFormatter.class); + private static final Pattern ESCAPED_OPENING_CURLY_BRACE = Pattern.compile("\\\\\\{"); private static final Pattern ESCAPED_CLOSING_CURLY_BRACE = Pattern.compile("\\\\\\}"); + /** * Matches text enclosed in curly brackets. The capturing group is used to prevent part of the input from being * replaced. */ private static final Pattern ENCLOSED_IN_CURLY_BRACES = Pattern.compile("\\{.*?}"); + private static final String REGEX_CAPTURING_GROUP = "regex"; private static final String REPLACEMENT_CAPTURING_GROUP = "replacement"; + /** * Matches a valid argument to the constructor. Two capturing groups are used to parse the {@link * RegexFormatter#regex} and {@link RegexFormatter#replacement} used in {@link RegexFormatter#format(String)} */ private static final Pattern CONSTRUCTOR_ARGUMENT = Pattern.compile( "^\\(\"(?<" + REGEX_CAPTURING_GROUP + ">.*?)\" *?, *?\"(?<" + REPLACEMENT_CAPTURING_GROUP + ">.*)\"\\)$"); + // Magic arbitrary unicode char, which will never appear in bibtex files private static final String PLACEHOLDER_FOR_PROTECTED_GROUP = Character.toString('\u0A14'); private static final String PLACEHOLDER_FOR_OPENING_CURLY_BRACE = Character.toString('\u0A15'); private static final String PLACEHOLDER_FOR_CLOSING_CURLY_BRACE = Character.toString('\u0A16'); + private static final String PLACEHOLDER_FOR_QUOTE_SIGN = Character.toString('\u0A17'); + private final String regex; private final String replacement; @@ -46,11 +54,11 @@ public class RegexFormatter extends Formatter { */ public RegexFormatter(String input) { Objects.requireNonNull(input); - input = input.trim(); + input = input.trim().replace("\\\"", PLACEHOLDER_FOR_QUOTE_SIGN); Matcher constructorArgument = CONSTRUCTOR_ARGUMENT.matcher(input); if (constructorArgument.matches()) { - regex = constructorArgument.group(REGEX_CAPTURING_GROUP); - replacement = constructorArgument.group(REPLACEMENT_CAPTURING_GROUP); + regex = constructorArgument.group(REGEX_CAPTURING_GROUP).replace(PLACEHOLDER_FOR_QUOTE_SIGN, "\""); + replacement = constructorArgument.group(REPLACEMENT_CAPTURING_GROUP).replace(PLACEHOLDER_FOR_QUOTE_SIGN, "\""); } else { regex = null; replacement = null; diff --git a/src/test/java/org/jabref/logic/citationkeypattern/BracketedPatternTest.java b/src/test/java/org/jabref/logic/citationkeypattern/BracketedPatternTest.java index 4d1b3649778..e7b9e643db5 100644 --- a/src/test/java/org/jabref/logic/citationkeypattern/BracketedPatternTest.java +++ b/src/test/java/org/jabref/logic/citationkeypattern/BracketedPatternTest.java @@ -25,6 +25,8 @@ /** * Tests based on a BibEntry are contained in {@link CitationKeyGeneratorTest} + * + * "Complete" entries are tested at {@link org.jabref.logic.citationkeypattern.MakeLabelWithDatabaseTest} */ @Execution(ExecutionMode.CONCURRENT) class BracketedPatternTest { @@ -606,14 +608,44 @@ void expandBracketsWithAuthorStartingWithBrackets() { @Test void expandBracketsWithModifierContainingRegexCharacterClass() { BibEntry bibEntry = new BibEntry().withField(StandardField.TITLE, "Wickedness:Managing"); - assertEquals("Wickedness.Managing", BracketedPattern.expandBrackets("[title:regex(\"[:]+\",\".\")]", null, bibEntry, null)); } + @Test + void regExForFirstWord() { + BibEntry bibEntry = new BibEntry().withField(StandardField.TITLE, "First Second Third"); + assertEquals("First", BracketedPattern.expandBrackets("[TITLE:regex(\"(\\w+).*\",\"$1\")]", null, bibEntry, null)); + } + + @Test + void regExWithComma() { + BibEntry bibEntry = new BibEntry().withField(StandardField.TITLE, "First,Second,Third"); + assertEquals("First+Second+Third", BracketedPattern.expandBrackets("[TITLE:regex(\",\",\"+\")]", null, bibEntry, null)); + } + + @Test + void regExWithEscapedQuote() { + BibEntry bibEntry = new BibEntry().withField(StandardField.TITLE, "First\"Second\"Third"); + assertEquals("First+Second+Third", BracketedPattern.expandBrackets("[TITLE:regex(\"\\\"\",\"+\")]", null, bibEntry, null)); + } + + @Test + void regExWithEtAlTwoAuthors() { + // Example from https://docs.jabref.org/setup/citationkeypatterns#modifiers + BibEntry bibEntry = new BibEntry().withField(StandardField.AUTHOR, "First Last and Second Last"); + assertEquals("LastAndLast", BracketedPattern.expandBrackets("[auth.etal:regex(\"\\.etal\",\"EtAl\"):regex(\"\\.\",\"And\")]", null, bibEntry, null)); + } + + @Test + void regExWithEtAlThreeAuthors() { + // Example from https://docs.jabref.org/setup/citationkeypatterns#modifiers + BibEntry bibEntry = new BibEntry().withField(StandardField.AUTHOR, "First Last and Second Last and Third Last"); + assertEquals("LastEtAl", BracketedPattern.expandBrackets("[auth.etal:regex(\"\\.etal\",\"EtAl\"):regex(\"\\.\",\"And\")]", null, bibEntry, null)); + } + @Test void expandBracketsEmptyStringFromEmptyBrackets() { BibEntry bibEntry = new BibEntry(); - assertEquals("", BracketedPattern.expandBrackets("[]", null, bibEntry, null)); } @@ -621,7 +653,6 @@ void expandBracketsEmptyStringFromEmptyBrackets() { void expandBracketsInstitutionAbbreviationFromProvidedAbbreviation() { BibEntry bibEntry = new BibEntry() .withField(StandardField.AUTHOR, "{European Union Aviation Safety Agency ({EUASABRACKET})}"); - assertEquals("EUASABRACKET", BracketedPattern.expandBrackets("[auth]", null, bibEntry, null)); } @@ -629,7 +660,6 @@ void expandBracketsInstitutionAbbreviationFromProvidedAbbreviation() { void expandBracketsInstitutionAbbreviationForAuthorContainingUnion() { BibEntry bibEntry = new BibEntry() .withField(StandardField.AUTHOR, "{European Union Aviation Safety Agency}"); - assertEquals("EUASA", BracketedPattern.expandBrackets("[auth]", null, bibEntry, null)); } @@ -637,7 +667,6 @@ void expandBracketsInstitutionAbbreviationForAuthorContainingUnion() { void expandBracketsLastNameForAuthorStartingWithOnlyLastNameStartingWithLowerCase() { BibEntry bibEntry = new BibEntry() .withField(StandardField.AUTHOR, "{eBay}"); - assertEquals("eBay", BracketedPattern.expandBrackets("[auth]", null, bibEntry, null)); } @@ -645,7 +674,6 @@ void expandBracketsLastNameForAuthorStartingWithOnlyLastNameStartingWithLowerCas void expandBracketsLastNameWithChineseCharacters() { BibEntry bibEntry = new BibEntry() .withField(StandardField.AUTHOR, "杨秀群"); - assertEquals("杨秀群", BracketedPattern.expandBrackets("[auth]", null, bibEntry, null)); } @@ -653,7 +681,6 @@ void expandBracketsLastNameWithChineseCharacters() { void expandBracketsUnmodifiedStringFromLongFirstPageNumber() { BibEntry bibEntry = new BibEntry() .withField(StandardField.PAGES, "2325967120921344"); - assertEquals("2325967120921344", BracketedPattern.expandBrackets("[firstpage]", null, bibEntry, null)); } @@ -661,7 +688,6 @@ void expandBracketsUnmodifiedStringFromLongFirstPageNumber() { void expandBracketsUnmodifiedStringFromLongLastPageNumber() { BibEntry bibEntry = new BibEntry() .withField(StandardField.PAGES, "2325967120921344"); - assertEquals("2325967120921344", BracketedPattern.expandBrackets("[lastpage]", null, bibEntry, null)); } diff --git a/src/test/java/org/jabref/logic/citationkeypattern/MakeLabelWithDatabaseTest.java b/src/test/java/org/jabref/logic/citationkeypattern/MakeLabelWithDatabaseTest.java index 3cafefc7846..724fb72f0d1 100644 --- a/src/test/java/org/jabref/logic/citationkeypattern/MakeLabelWithDatabaseTest.java +++ b/src/test/java/org/jabref/logic/citationkeypattern/MakeLabelWithDatabaseTest.java @@ -14,6 +14,9 @@ import static org.jabref.logic.citationkeypattern.CitationKeyGenerator.DEFAULT_UNWANTED_CHARACTERS; import static org.junit.jupiter.api.Assertions.assertEquals; +/** + * Bracketed patterns themselves are tested at {@link org.jabref.logic.citationkeypattern.BracketedPatternTest}. + */ @Execution(ExecutionMode.CONCURRENT) class MakeLabelWithDatabaseTest { @@ -461,11 +464,22 @@ void generateKeyAuthIniMany() { } @Test - void generateKeyTitleRegexe() { - bibtexKeyPattern.setDefaultValue("[title:regex(\" \",\"-\")]"); + void generateKeyTitleRegex() { + // Note that TITLE is written in upper case to have the verbatim value of the title field + // See https://github.com/JabRef/user-documentation/blob/main/en/setup/citationkeypatterns.md#bibentry-fields for information on that. + // We cannot use "-", because this is in the set of unwanted characters and removed after the RegEx is applied + bibtexKeyPattern.setDefaultValue("[TITLE:regex(\" \",\"X\")]"); // regex(" ", "-") entry.setField(StandardField.TITLE, "Please replace the spaces"); new CitationKeyGenerator(bibtexKeyPattern, database, preferences).generateAndSetKey(entry); - assertEquals(Optional.of("PleaseReplacetheSpaces"), entry.getCitationKey()); + assertEquals(Optional.of("PleaseXreplaceXtheXspaces"), entry.getCitationKey()); + } + + @Test + void generateKeyTitleRegexFirstWord() { + bibtexKeyPattern.setDefaultValue("[TITLE:regex(\"(\\w+).*\",\"$1\")]"); + entry.setField(StandardField.TITLE, "First Second Third"); + new CitationKeyGenerator(bibtexKeyPattern, database, preferences).generateAndSetKey(entry); + assertEquals(Optional.of("First"), entry.getCitationKey()); } @Test diff --git a/src/test/java/org/jabref/logic/citationkeypattern/MakeLabelWithoutDatabaseTest.java b/src/test/java/org/jabref/logic/citationkeypattern/MakeLabelWithoutDatabaseTest.java index b02b69554ff..61d98eccb92 100644 --- a/src/test/java/org/jabref/logic/citationkeypattern/MakeLabelWithoutDatabaseTest.java +++ b/src/test/java/org/jabref/logic/citationkeypattern/MakeLabelWithoutDatabaseTest.java @@ -5,6 +5,7 @@ import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.types.StandardEntryType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -17,12 +18,13 @@ class MakeLabelWithoutDatabaseTest { private CitationKeyGenerator citationKeyGenerator; + private CitationKeyPatternPreferences patternPreferences; @BeforeEach void setUp() { GlobalCitationKeyPatterns keyPattern = new GlobalCitationKeyPatterns(CitationKeyPattern.NULL_CITATION_KEY_PATTERN); keyPattern.setDefaultValue("[auth]"); - CitationKeyPatternPreferences patternPreferences = new CitationKeyPatternPreferences( + patternPreferences = new CitationKeyPatternPreferences( false, false, false, @@ -58,4 +60,29 @@ void makeEditorLabelForFileSearch() { String label = citationKeyGenerator.generateKey(entry); assertEquals("Doe", label); } + + @Test + void bamford_1972_Comprehensive_Reaction_V_7_EN() { + // Example taken from https://github.com/JabRef/jabref/issues/11367#issuecomment-2162250948 + BibEntry entry = new BibEntry(StandardEntryType.Book) + .withCitationKey("Bamford_1972_Comprehensive_Reaction_V_7_EN") + .withField(StandardField.LANGUAGE, "english") + .withField(StandardField.MAINTITLE, "Comprehensive Chemical Kinetics") + .withField(StandardField.TITLE, "Reaction of Metallic Salts and Complexes, and Organometallic Compounds") + .withField(StandardField.VOLUME, "7") + .withField(StandardField.YEAR, "1972") + .withField(StandardField.EDITOR, "Bamford, C. H. and Tipper, C. F. H."); + citationKeyGenerator = new CitationKeyGenerator(GlobalCitationKeyPatterns.fromPattern("[edtr]_[YEAR]_[MAINTITLE:regex(\"(\\w+).*\", \"$1\")]_[TITLE:regex(\"(\\w+).*\", \"$1\")]_V_[VOLUME]_[LANGUAGE:regex(\"english\", \"EN\"):regex(\"french\", \"FR\")]"), new BibDatabase(), patternPreferences); + String label = citationKeyGenerator.generateKey(entry); + assertEquals("Bamford_1972_Comprehensive_Reaction_V_7_EN", label); + } + + @Test + void frenchRegEx() { + BibEntry entry = new BibEntry(StandardEntryType.Book) + .withField(StandardField.LANGUAGE, "french"); + citationKeyGenerator = new CitationKeyGenerator(GlobalCitationKeyPatterns.fromPattern("[LANGUAGE:regex(\"english\", \"EN\"):regex(\"french\", \"FR\")]"), new BibDatabase(), patternPreferences); + String label = citationKeyGenerator.generateKey(entry); + assertEquals("FR", label); + } } diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java index 8cd7b10ab5d..dc478a9cb3d 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/RegexFormatterTest.java @@ -79,4 +79,10 @@ void formatWithSyntaxErrorReturnUnchangedString() { formatter = new RegexFormatter("(\"(\", \"\")"); assertEquals("AaBbCc", formatter.format("AaBbCc")); } + + @Test + void extractFirstWord() { + formatter = new RegexFormatter("(\"(\\w+).*\", \"$1\")"); + assertEquals("First", formatter.format("First Second Third")); + } } From 7a91f7509511403fdfe4fe068a7d4cd887cacc0a Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 16 Oct 2024 11:03:32 +0200 Subject: [PATCH 09/10] Add information on unassignment (#11982) --- .github/workflows/on-labeled-issue.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/on-labeled-issue.yml b/.github/workflows/on-labeled-issue.yml index d70b37528e9..6d2600da58b 100644 --- a/.github/workflows/on-labeled-issue.yml +++ b/.github/workflows/on-labeled-issue.yml @@ -25,6 +25,10 @@ jobs: Having any questions or issues? Feel free to ask here on GitHub. Need help setting up your local workspace? Join the conversation on [JabRef's Gitter chat](https://gitter.im/JabRef/jabref). And don't hesitate to open a (draft) pull request early on to show the direction it is heading towards. This way, you will receive valuable feedback. + ⚠ Note that this issue will become unassigned if it isn't closed within **30 days**. + + 🔧 A maintainer can also add the **`Pinned`** label to prevent it from being unassigned automatically. + Happy coding! 🚀 - name: Move Issue to "Assigned" Column in "Candidates for University Projects" uses: m7kvqbe1/github-action-move-issues@v1.1.1 From c32298e93236b78c115a386b993758b2a7f5764f Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 16 Oct 2024 11:24:32 +0200 Subject: [PATCH 10/10] Rename JabRefCli to JabKit (#11983) --- src/main/java/org/jabref/Launcher.java | 6 +++--- .../cli/{JabRefCli.java => JabKit.java} | 20 +++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) rename src/main/java/org/jabref/cli/{JabRefCli.java => JabKit.java} (94%) diff --git a/src/main/java/org/jabref/Launcher.java b/src/main/java/org/jabref/Launcher.java index caee40d6dae..8806c7892bf 100644 --- a/src/main/java/org/jabref/Launcher.java +++ b/src/main/java/org/jabref/Launcher.java @@ -2,7 +2,7 @@ import java.util.List; -import org.jabref.cli.JabRefCli; +import org.jabref.cli.JabKit; import org.jabref.gui.JabRefGUI; import org.jabref.gui.preferences.GuiPreferences; import org.jabref.gui.preferences.JabRefGuiPreferences; @@ -23,7 +23,7 @@ public class Launcher { public static void main(String[] args) { - JabRefCli.initLogging(args); + JabKit.initLogging(args); // Initialize preferences final JabRefGuiPreferences preferences = JabRefGuiPreferences.getInstance(); @@ -33,7 +33,7 @@ public static void main(String[] args) { DefaultFileUpdateMonitor fileUpdateMonitor = new DefaultFileUpdateMonitor(); HeadlessExecutorService.INSTANCE.executeInterruptableTask(fileUpdateMonitor, "FileUpdateMonitor"); - List uiCommands = JabRefCli.processArguments(args, preferences, fileUpdateMonitor); + List uiCommands = JabKit.processArguments(args, preferences, fileUpdateMonitor); // The method `processArguments` quites the whole JVM if no GUI is needed. PreferencesMigrations.runMigrations(preferences); diff --git a/src/main/java/org/jabref/cli/JabRefCli.java b/src/main/java/org/jabref/cli/JabKit.java similarity index 94% rename from src/main/java/org/jabref/cli/JabRefCli.java rename to src/main/java/org/jabref/cli/JabKit.java index cae415ab61f..72cab155979 100644 --- a/src/main/java/org/jabref/cli/JabRefCli.java +++ b/src/main/java/org/jabref/cli/JabKit.java @@ -37,12 +37,16 @@ import org.slf4j.bridge.SLF4JBridgeHandler; import org.tinylog.configuration.Configuration; -/** - * Entrypoint for a command-line only version of JabRef. - * - * Does not do any preference migrations - */ -public class JabRefCli { +/// Entrypoint for a command-line only version of JabRef. +/// It does not open any dialogs, just parses the command line arguments and outputs text and creates/modifies files. +/// +/// See [Command Line Interface Guidelines](https://clig.dev/) for general guidelines how to design a good CLI interface. +/// +/// It does not open any GUI. +/// For the GUI application see {@link org.jabref.Launcher}. +/// +/// Does not do any preference migrations. +public class JabKit { private static Logger LOGGER; public static void main(String[] args) { @@ -144,7 +148,7 @@ public static void initLogging(String[] args) { try { Files.createDirectories(directory); } catch (IOException e) { - LOGGER = LoggerFactory.getLogger(JabRefCli.class); + LOGGER = LoggerFactory.getLogger(JabKit.class); LOGGER.error("Could not create log directory {}", directory, e); return; } @@ -162,7 +166,7 @@ public static void initLogging(String[] args) { "writerFile.backups", "30"); configuration.forEach(Configuration::set); - LOGGER = LoggerFactory.getLogger(JabRefCli.class); + LOGGER = LoggerFactory.getLogger(JabKit.class); } /**