Skip to content
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

CSL4LibreOffice - E [Add re-distribution of numeric CSL citations] #11712

Merged
merged 54 commits into from
Sep 7, 2024
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
170fc68
Initial commit
subhramit Aug 30, 2024
73f7be8
Semi-fix: 0-based index
subhramit Aug 30, 2024
bed501a
Merge branch 'main' into numberings
subhramit Aug 30, 2024
5d7d4cd
add method for getting multiple citations
Siedlerchr Sep 6, 2024
4f3e0d2
Merge branch 'main' into numberings
subhramit Sep 6, 2024
5f9dbf0
Use XTextRangeCompare
subhramit Sep 6, 2024
1041246
Fix update order
subhramit Sep 6, 2024
345af08
Remove dead code, undo ai refactor changes
subhramit Sep 6, 2024
1f4b761
Fix remaining order issues, Remove dead code, undo ai refactor changes
subhramit Sep 6, 2024
78f0b6d
Restore exceptions: UpdateCSLBibliography
subhramit Sep 6, 2024
fbe8327
Refine
subhramit Sep 6, 2024
0f4667f
Fix checkstyle
subhramit Sep 6, 2024
300fee9
Remove experiment
subhramit Sep 6, 2024
5a9a904
Fix OOBibBase.java exceptions
subhramit Sep 6, 2024
d862b25
Fix OpenOfficePanel.java exceptions
subhramit Sep 6, 2024
3ab9297
Fix adapter exception indent
subhramit Sep 6, 2024
797d044
Fix adapter exception order
subhramit Sep 6, 2024
079a251
Restore javadoc
subhramit Sep 6, 2024
3c05da3
Restore javadoc, remove dead code
subhramit Sep 6, 2024
3ba0f96
Remove dead code
subhramit Sep 6, 2024
1162a2a
Improve implementation (general changes)
subhramit Sep 6, 2024
26b4889
Change printStackTrace->Logger
subhramit Sep 6, 2024
c01925f
Fix readExistingMarks()
subhramit Sep 6, 2024
f2caf8e
Remove logs
subhramit Sep 6, 2024
52c0d20
Finish CSLReferenceMarkManager
subhramit Sep 6, 2024
62e8e77
Merge branch 'main' into numberings-2
subhramit Sep 6, 2024
8f49698
openRewrite
subhramit Sep 6, 2024
36b0d57
Merge remote-tracking branch 'origin/numberings-2' into numberings-2
subhramit Sep 6, 2024
4850a60
fix unit test (std streams -> logger)
subhramit Sep 6, 2024
b4e3209
Redundant log
subhramit Sep 6, 2024
3a227f0
Safety, refactoring
subhramit Sep 6, 2024
17fe8de
Add log
subhramit Sep 6, 2024
400b7fc
Better log
subhramit Sep 6, 2024
bf406d9
Change log level (non-breaking)
subhramit Sep 6, 2024
774bc48
Add handling for multiple entries
subhramit Sep 7, 2024
23255b7
Better log
subhramit Sep 7, 2024
4703178
Restore javadoc
subhramit Sep 7, 2024
e5b84ab
Restore javadoc
subhramit Sep 7, 2024
b1505ae
Use list instead of singleton
subhramit Sep 7, 2024
d8b23e0
Adapt test
subhramit Sep 7, 2024
ec52189
Add comment
subhramit Sep 7, 2024
f9df5a5
Add stricter conditions for update
subhramit Sep 7, 2024
c5e580f
Add stricter conditions for reading
subhramit Sep 7, 2024
06200fd
Make xtextcompare final
subhramit Sep 7, 2024
1f18e4b
Null handling
subhramit Sep 7, 2024
46f7adb
Update javadoc
subhramit Sep 7, 2024
ebd2630
Refactor
subhramit Sep 7, 2024
ffb7bfc
Remove redundant condition
subhramit Sep 7, 2024
6a0c54f
Fix non-numeric side effect
subhramit Sep 7, 2024
ef11cef
Enhance implementation
subhramit Sep 7, 2024
39592bc
Add newline
subhramit Sep 7, 2024
85cd488
Bug fix: no sync in refresh bibliography
subhramit Sep 7, 2024
856c7c5
Merge branch 'main' into numberings-2
Siedlerchr Sep 7, 2024
9db142c
fix logger openrewrite
Siedlerchr Sep 7, 2024
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
28 changes: 14 additions & 14 deletions src/main/java/org/jabref/gui/openoffice/OOBibBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ public OOBibBase(Path loPath, DialogService dialogService)
}

private void initializeCitationAdapter(XTextDocument doc) throws WrappedTargetException, NoSuchElementException {
this.cslCitationOOAdapter = new CSLCitationOOAdapter(doc);
this.cslCitationOOAdapter.readExistingMarks();
this.cslCitationOOAdapter = new CSLCitationOOAdapter(doc);
this.cslCitationOOAdapter.readAndUpdateExistingMarks();
}

public void guiActionSelectDocument(boolean autoSelectForSingle) throws WrappedTargetException, NoSuchElementException {
Expand Down Expand Up @@ -161,9 +161,9 @@ void showDialog(String errorTitle, OOError err) {

OOVoidResult<OOError> collectResults(String errorTitle, List<OOVoidResult<OOError>> results) {
String msg = results.stream()
.filter(OOVoidResult::isError)
.map(e -> e.getError().getLocalizedMessage())
.collect(Collectors.joining("\n\n"));
.filter(OOVoidResult::isError)
.map(e -> e.getError().getLocalizedMessage())
.collect(Collectors.joining("\n\n"));
if (msg.isEmpty()) {
return OOVoidResult.ok();
} else {
Expand Down Expand Up @@ -233,10 +233,10 @@ private static OOVoidResult<OOError> checkRangeOverlaps(XTextDocument doc, OOFro
int maxReportedOverlaps = 10;
try {
return frontend.checkRangeOverlaps(doc,
new ArrayList<>(),
requireSeparation,
maxReportedOverlaps)
.mapError(OOError::from);
new ArrayList<>(),
requireSeparation,
maxReportedOverlaps)
.mapError(OOError::from);
} catch (NoDocumentException ex) {
return OOVoidResult.error(OOError.from(ex).setTitle(errorTitle));
} catch (WrappedTargetException ex) {
Expand Down Expand Up @@ -322,7 +322,7 @@ OOResult<OOFrontend, OOError> getFrontend(XTextDocument doc) {
} catch (NoDocumentException ex) {
return OOResult.error(OOError.from(ex).setTitle(errorTitle));
} catch (WrappedTargetException
| RuntimeException ex) {
| RuntimeException ex) {
return OOResult.error(OOError.fromMisc(ex).setTitle(errorTitle));
}
}
Expand Down Expand Up @@ -601,7 +601,7 @@ public void guiActionInsertEntry(List<BibEntry> entries,
this.cslCitationOOAdapter.insertInTextCitation(cursor.get(), citationStyle, entries, bibDatabaseContext, bibEntryTypesManager);
} else if (citationType == CitationType.INVISIBLE_CIT) {
// "Insert empty citation"
this.cslCitationOOAdapter.insertEmpty(cursor.get(), entries);
this.cslCitationOOAdapter.insertEmpty(cursor.get(), citationStyle, entries);
}

// If "Automatically sync bibliography when inserting citations" is enabled
Expand Down Expand Up @@ -813,7 +813,7 @@ public Optional<BibDatabase> exportCitedHelper(List<BibDatabase> databases, bool
} catch (DisposedException ex) {
OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService);
} catch (WrappedTargetException
| com.sun.star.lang.IllegalArgumentException ex) {
| com.sun.star.lang.IllegalArgumentException ex) {
LOGGER.warn("Problem generating new database.", ex);
OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService);
}
Expand Down Expand Up @@ -881,8 +881,8 @@ public void guiActionUpdateDocument(List<BibDatabase> databases, OOStyle style)
} catch (DisposedException ex) {
OOError.from(ex).setTitle(errorTitle).showErrorDialog(dialogService);
} catch (CreationException
| WrappedTargetException
| com.sun.star.lang.IllegalArgumentException ex) {
| WrappedTargetException
| com.sun.star.lang.IllegalArgumentException ex) {
LOGGER.warn("Could not update JStyle bibliography", ex);
OOError.fromMisc(ex).setTitle(errorTitle).showErrorDialog(dialogService);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private List<String> generateCitations() throws IOException {
}

if (styleSource != null) {
return CitationStyleGenerator.generateCitations(
return CitationStyleGenerator.generateBibliographies(
selectedEntries,
styleSource,
outputFormat,
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/jabref/logic/citationstyle/CSLAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
/**
* Provides an adapter class to CSL. It holds a CSL instance under the hood that is only recreated when
* the style changes.
*
* <p>
* Note on the API: The first call to {@link #makeBibliography} is expensive since the
* CSL instance will be created. As long as the style stays the same, we can reuse this instance. On style-change, the
* engine is re-instantiated. Therefore, the use-case of this class is many calls to {@link #makeBibliography} with the
* same style. Changing the output format is cheap.
*
* <p>
* Note on the implementation:
* The main function {@link #makeBibliography} will enforce
* synchronized calling. The main CSL engine under the hood is not thread-safe. Since this class is usually called from
Expand Down Expand Up @@ -51,7 +51,7 @@ public synchronized List<String> makeBibliography(List<BibEntry> bibEntries, Str
return Arrays.asList(bibliography.getEntries());
}

public synchronized Citation makeInText(List<BibEntry> bibEntries, String style, CitationStyleOutputFormat outputFormat, BibDatabaseContext databaseContext, BibEntryTypesManager entryTypesManager) throws IOException {
public synchronized Citation makeCitation(List<BibEntry> bibEntries, String style, CitationStyleOutputFormat outputFormat, BibDatabaseContext databaseContext, BibEntryTypesManager entryTypesManager) throws IOException {
dataProvider.setData(bibEntries, databaseContext, entryTypesManager);
initialize(style, outputFormat);
cslInstance.registerCitationItems(dataProvider.getIds());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,38 +31,38 @@ private CitationStyleGenerator() {
*
* @implNote the citation is generated using JavaScript which may take some time, better call it from outside the main Thread
*/
protected static String generateCitation(List<BibEntry> bibEntries, CitationStyle style, BibEntryTypesManager entryTypesManager) {
return generateCitation(bibEntries, style.getSource(), entryTypesManager);
protected static String generateBibliography(List<BibEntry> bibEntries, CitationStyle style, BibEntryTypesManager entryTypesManager) {
return generateBibliography(bibEntries, style.getSource(), entryTypesManager);
}

/**
* Generates a Citation based on a given list of entries and a style with a default {@link BibDatabaseContext}
*
* @implNote the citation is generated using JavaScript which may take some time, better call it from outside the main Thread
*/
protected static String generateCitation(List<BibEntry> bibEntries, String style, BibEntryTypesManager entryTypesManager) {
return generateCitation(bibEntries, style, CitationStyleOutputFormat.HTML, new BibDatabaseContext(), entryTypesManager).getFirst();
protected static String generateBibliography(List<BibEntry> bibEntries, String style, BibEntryTypesManager entryTypesManager) {
return generateBibliography(bibEntries, style, CitationStyleOutputFormat.HTML, new BibDatabaseContext(), entryTypesManager).getFirst();
}

/**
* Generates a Citation based on a given list of entries, style, and output format
*
* @implNote the citation is generated using JavaScript which may take some time, better call it from outside the main Thread
*/
public static List<String> generateCitation(List<BibEntry> bibEntries, String style, CitationStyleOutputFormat outputFormat, BibDatabaseContext databaseContext, BibEntryTypesManager entryTypesManager) {
return generateCitations(bibEntries, style, outputFormat, databaseContext, entryTypesManager);
public static List<String> generateBibliography(List<BibEntry> bibEntries, String style, CitationStyleOutputFormat outputFormat, BibDatabaseContext databaseContext, BibEntryTypesManager entryTypesManager) {
return generateBibliographies(bibEntries, style, outputFormat, databaseContext, entryTypesManager);
}

public static Citation generateInText(List<BibEntry> bibEntries, String style, CitationStyleOutputFormat outputFormat, BibDatabaseContext databaseContext, BibEntryTypesManager entryTypesManager) throws IOException {
return CSL_ADAPTER.makeInText(bibEntries, style, outputFormat, databaseContext, entryTypesManager);
public static Citation generateCitation(List<BibEntry> bibEntries, String style, CitationStyleOutputFormat outputFormat, BibDatabaseContext databaseContext, BibEntryTypesManager entryTypesManager) throws IOException {
return CSL_ADAPTER.makeCitation(bibEntries, style, outputFormat, databaseContext, entryTypesManager);
}

/**
* Generates the citation for multiple entries at once.
*
* @implNote The citations are generated using JavaScript which may take some time, better call it from outside the main thread.
*/
public static List<String> generateCitations(List<BibEntry> bibEntries, String style, CitationStyleOutputFormat outputFormat, BibDatabaseContext databaseContext, BibEntryTypesManager entryTypesManager) {
public static List<String> generateBibliographies(List<BibEntry> bibEntries, String style, CitationStyleOutputFormat outputFormat, BibDatabaseContext databaseContext, BibEntryTypesManager entryTypesManager) {
try {
return CSL_ADAPTER.makeBibliography(bibEntries, style, outputFormat, databaseContext, entryTypesManager);
} catch (IllegalArgumentException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public CitationStylePreviewLayout(CitationStyle citationStyle, BibEntryTypesMana

@Override
public String generatePreview(BibEntry entry, BibDatabaseContext databaseContext) {
return CitationStyleGenerator.generateCitation(List.of(entry), citationStyle.getSource(), CitationStyleOutputFormat.HTML, databaseContext, bibEntryTypesManager).getFirst();
return CitationStyleGenerator.generateBibliography(List.of(entry), citationStyle.getSource(), CitationStyleOutputFormat.HTML, databaseContext, bibEntryTypesManager).getFirst();
}

@Override
Expand Down
80 changes: 45 additions & 35 deletions src/main/java/org/jabref/logic/openoffice/ReferenceMark.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jabref.logic.openoffice;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -9,77 +11,85 @@
import org.slf4j.LoggerFactory;

public class ReferenceMark {
public static final String[] PREFIXES = {"JABREF_", "CID_"};

private static final Logger LOGGER = LoggerFactory.getLogger(ReferenceMark.class);

private static final Pattern REFERENCE_MARK_FORMAT = Pattern.compile("^JABREF_(\\w+) CID_(\\w+) (\\w+)$");
private final String name;
private static final Pattern REFERENCE_MARK_FORMAT = Pattern.compile("^((?:JABREF_\\w+ CID_\\w+(?:,\\s*)?)+)(\\s*\\w+)?$");
private static final Pattern ENTRY_PATTERN = Pattern.compile("JABREF_(\\w+) CID_(\\w+)");

private String citationKey;
private Integer citationNumber;
private final String name;
private List<String> citationKeys;
private List<Integer> citationNumbers;
private String uniqueId;

/**
* @param name Format: <code>JABREF_{citationKey} CID_{citationNumber} {uniqueId}</code>
*/
public ReferenceMark(String name) {
this.name = name;
parse(name);
}

Matcher matcher = getMatcher(name);
public ReferenceMark(String name, List<String> citationKeys, List<Integer> citationNumbers, String uniqueId) {
this.name = name;
this.citationKeys = citationKeys;
this.citationNumbers = citationNumbers;
this.uniqueId = uniqueId;
}

private void parse(String name) {
Matcher matcher = REFERENCE_MARK_FORMAT.matcher(name);
if (!matcher.matches()) {
LOGGER.warn("CSLReferenceMark: name={} does not match pattern. Assuming random values", name);
this.citationKey = CUID.randomCUID2(8).toString();
this.citationNumber = 0;
this.uniqueId = this.citationKey;
this.citationKeys = List.of(CUID.randomCUID2(8).toString());
this.citationNumbers = List.of(0);
this.uniqueId = this.citationKeys.getFirst();
return;
}

this.citationKey = matcher.group(1);
this.citationNumber = Integer.parseInt(matcher.group(2));
this.uniqueId = matcher.group(3);
String entriesString = matcher.group(1).trim();
this.uniqueId = matcher.group(2) != null ? matcher.group(2).trim() : CUID.randomCUID2(8).toString();

LOGGER.debug("CSLReferenceMark: citationKey={} citationNumber={} uniqueId={}", getCitationKey(), getCitationNumber(), getUniqueId());
}
this.citationKeys = new ArrayList<>();
this.citationNumbers = new ArrayList<>();

public ReferenceMark(String name, String citationKey, Integer citationNumber, String uniqueId) {
this.name = name;
this.citationKey = citationKey;
this.citationNumber = citationNumber;
this.uniqueId = uniqueId;
}
Matcher entryMatcher = ENTRY_PATTERN.matcher(entriesString);
while (entryMatcher.find()) {
this.citationKeys.add(entryMatcher.group(1));
this.citationNumbers.add(Integer.parseInt(entryMatcher.group(2)));
}

private ReferenceMark(String name, String citationKey, String citationNumber, String uniqueId) {
this(name, citationKey, Integer.parseInt(citationNumber), uniqueId);
}
if (this.citationKeys.isEmpty() || this.citationNumbers.isEmpty()) {
LOGGER.warn("CSLReferenceMark: Failed to parse any entries from name={}. Assuming random values", name);
this.citationKeys = List.of(CUID.randomCUID2(8).toString());
this.citationNumbers = List.of(0);
}

private static Matcher getMatcher(String name) {
return REFERENCE_MARK_FORMAT.matcher(name);
LOGGER.debug("CSLReferenceMark: citationKeys={} citationNumbers={} uniqueId={}", getCitationKeys(), getCitationNumbers(), getUniqueId());
}

public String getName() {
return name;
}

/**
* The BibTeX citation key
* The BibTeX citation keys
*/
public String getCitationKey() {
return citationKey;
public List<String> getCitationKeys() {
return citationKeys;
}

public int getCitationNumber() {
return citationNumber;
public List<Integer> getCitationNumbers() {
return citationNumbers;
}

public String getUniqueId() {
return uniqueId;
}

public static Optional<ReferenceMark> of(String name) {
Matcher matcher = getMatcher(name);
if (!matcher.matches()) {
return Optional.empty();
}

return Optional.of(new ReferenceMark(name, matcher.group(1), matcher.group(2), matcher.group(3)));
ReferenceMark mark = new ReferenceMark(name);
return mark.citationKeys.isEmpty() ? Optional.empty() : Optional.of(mark);
}
}
Loading
Loading