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

Keep enclosing braces of authors #11034

Merged
merged 18 commits into from
Mar 18, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We made the command "Push to TexShop" more robust to allow cite commands with a character before the first slash. [forum#2699](https://discourse.jabref.org/t/push-to-texshop-mac/2699/17?u=siedlerchr)
- We only show the notification "Saving library..." if the library contains more than 2000 entries. [#9803](https://github.com/JabRef/jabref/issues/9803)
- JabRef now keeps previous log files upon start. [#11023](https://github.com/JabRef/jabref/pull/11023)
- When normalizing author names, complete enclosing braces are kept. [#10031](https://github.com/JabRef/jabref/issues/10031)
- We enhanced the dialog for adding new fields in the content selector with a selection box containing a list of standard fields. [#10912](https://github.com/JabRef/jabref/pull/10912)
- We store the citation relations in an LRU cache to avoid bloating the memory and out-of-memory exceptions. [#10958](https://github.com/JabRef/jabref/issues/10958)
- Keywords filed are now displayed as tags. [#10910](https://github.com/JabRef/jabref/pull/10910)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,28 @@ public String toString(Author author) {
if (autoCompLF) {
switch (autoCompleteFirstNameMode) {
case ONLY_ABBREVIATED:
return author.getLastFirst(true);
return author.getFamilyGiven(true);
case ONLY_FULL:
return author.getLastFirst(false);
return author.getFamilyGiven(false);
case BOTH:
return author.getLastFirst(true);
return author.getFamilyGiven(true);
default:
break;
}
}
if (autoCompFF) {
switch (autoCompleteFirstNameMode) {
case ONLY_ABBREVIATED:
return author.getFirstLast(true);
return author.getGivenFamily(true);
case ONLY_FULL:
return author.getFirstLast(false);
return author.getGivenFamily(false);
case BOTH:
return author.getFirstLast(true);
return author.getGivenFamily(true);
default:
break;
}
}
return author.getLastOnly();
return author.getNamePrefixAndFamilyName();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public Stream<Author> getAuthors(BibEntry entry) {

@Override
protected Equivalence<Author> getEquivalence() {
return Equivalence.equals().onResultOf(Author::getLastOnly);
return Equivalence.equals().onResultOf(Author::getNamePrefixAndFamilyName);
}

@Override
Expand All @@ -58,7 +58,7 @@ protected Comparator<Author> getComparator() {

@Override
protected boolean isMatch(Author candidate, AutoCompletionBinding.ISuggestionRequest request) {
return StringUtil.containsIgnoreCase(candidate.getLastFirst(false), request.getUserText());
return StringUtil.containsIgnoreCase(candidate.getFamilyGiven(false), request.getUserText());
}

@Override
Expand Down
12 changes: 4 additions & 8 deletions src/main/java/org/jabref/logic/bst/util/BstNameFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,10 @@ public static String formatName(Author author, String format) {
char type = control.charAt(0);

Optional<String> tokenS = switch (type) {
case 'f' ->
author.getFirst();
case 'v' ->
author.getVon();
case 'l' ->
author.getLast();
case 'j' ->
author.getJr();
case 'f' -> author.getGivenName();
case 'v' -> author.getNamePrefix();
case 'l' -> author.getFamilyName();
case 'j' -> author.getNameSuffix();
default ->
throw new BstVMException("Internal error");
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,17 +526,17 @@ private static AuthorList createAuthorList(String unparsedAuthors) {
return AuthorList.parse(unparsedAuthors).getAuthors().stream()
.map(author -> {
// If the author is an institution, use an institution key instead of the full name
String lastName = author.getLast()
String lastName = author.getFamilyName()
.map(lastPart -> isInstitution(author) ?
generateInstitutionKey(lastPart) :
LatexToUnicodeAdapter.format(lastPart))
.orElse(null);
return new Author(
author.getFirst().map(LatexToUnicodeAdapter::format).orElse(null),
author.getFirstAbbr().map(LatexToUnicodeAdapter::format).orElse(null),
author.getVon().map(LatexToUnicodeAdapter::format).orElse(null),
author.getGivenName().map(LatexToUnicodeAdapter::format).orElse(null),
author.getGivenNameAbbreviated().map(LatexToUnicodeAdapter::format).orElse(null),
author.getNamePrefix().map(LatexToUnicodeAdapter::format).orElse(null),
lastName,
author.getJr().map(LatexToUnicodeAdapter::format).orElse(null));
author.getNameSuffix().map(LatexToUnicodeAdapter::format).orElse(null));
})
.collect(AuthorList.collect());
}
Expand All @@ -548,9 +548,9 @@ private static AuthorList createAuthorList(String unparsedAuthors) {
* @return true if only the last name is present and it contains at least one whitespace character.
*/
private static boolean isInstitution(Author author) {
return author.getFirst().isEmpty() && author.getFirstAbbr().isEmpty() && author.getJr().isEmpty()
&& author.getVon().isEmpty() && author.getLast().isPresent()
&& WHITESPACE.matcher(author.getLast().get()).find();
return author.getGivenName().isEmpty() && author.getGivenNameAbbreviated().isEmpty() && author.getNameSuffix().isEmpty()
&& author.getNamePrefix().isEmpty() && author.getFamilyName().isPresent()
&& WHITESPACE.matcher(author.getFamilyName().get()).find();
}

/**
Expand Down Expand Up @@ -765,7 +765,7 @@ private static String keepLettersAndDigitsOnly(String in) {
private static String firstAuthor(AuthorList authorList) {
return authorList.getAuthors().stream()
.findFirst()
.flatMap(author -> author.getLast().isPresent() ? author.getLast() : author.getVon())
.flatMap(author -> author.getFamilyName().isPresent() ? author.getFamilyName() : author.getNamePrefix())
.orElse("");
}

Expand All @@ -779,7 +779,7 @@ private static String firstAuthor(AuthorList authorList) {
private static String firstAuthorForenameInitials(AuthorList authorList) {
return authorList.getAuthors().stream()
.findFirst()
.flatMap(Author::getFirstAbbr)
.flatMap(Author::getGivenNameAbbreviated)
.map(s -> s.substring(0, 1))
.orElse("");
}
Expand All @@ -793,7 +793,7 @@ private static String firstAuthorForenameInitials(AuthorList authorList) {
*/
private static String firstAuthorVonAndLast(AuthorList authorList) {
return authorList.isEmpty() ? "" :
authorList.getAuthor(0).getLastOnly().replace(" ", "");
authorList.getAuthor(0).getNamePrefixAndFamilyName().replace(" ", "");
}

/**
Expand All @@ -806,7 +806,7 @@ private static String lastAuthor(AuthorList authorList) {
if (authorList.isEmpty()) {
return "";
}
return authorList.getAuthors().get(authorList.getNumberOfAuthors() - 1).getLast().orElse("");
return authorList.getAuthors().get(authorList.getNumberOfAuthors() - 1).getFamilyName().orElse("");
}

/**
Expand All @@ -820,7 +820,7 @@ private static String lastAuthorForenameInitials(AuthorList authorList) {
if (authorList.isEmpty()) {
return "";
}
return authorList.getAuthor(authorList.getNumberOfAuthors() - 1).getFirstAbbr().map(s -> s.substring(0, 1))
return authorList.getAuthor(authorList.getNumberOfAuthors() - 1).getGivenNameAbbreviated().map(s -> s.substring(0, 1))
.orElse("");
}

Expand Down Expand Up @@ -857,7 +857,7 @@ static String authorsAlpha(AuthorList authorList) {
}

if (authorList.getNumberOfAuthors() == 1) {
String[] firstAuthor = authorList.getAuthor(0).getLastOnly()
String[] firstAuthor = authorList.getAuthor(0).getNamePrefixAndFamilyName()
.replaceAll("\\s+", " ").trim().split(" ");
// take first letter of any "prefixes" (e.g. van der Aalst -> vd)
for (int j = 0; j < (firstAuthor.length - 1); j++) {
Expand All @@ -873,7 +873,7 @@ static String authorsAlpha(AuthorList authorList) {
}
List<String> vonAndLastNames = authorList.getAuthors().stream()
.limit(maxAuthors)
.map(Author::getLastOnly)
.map(Author::getNamePrefixAndFamilyName)
.collect(Collectors.toList());
for (String vonAndLast : vonAndLastNames) {
// replace all whitespaces by " "
Expand Down Expand Up @@ -913,7 +913,7 @@ private static String joinAuthorsOnLastName(AuthorList authorList, int maxAuthor
return Optional.of(suffix);
}
} else {
return author.getLast();
return author.getFamilyName();
}
})
.flatMap(Optional::stream)
Expand Down Expand Up @@ -970,7 +970,7 @@ static String authEtal(AuthorList authorList, String delim, String append) {
// exception: If the second author is "and others", then do the appendix handling (in the other branch)
return joinAuthorsOnLastName(authorList, 2, delim, "");
} else {
return authorList.getAuthor(0).getLast().orElse("") + append;
return authorList.getAuthor(0).getFamilyName().orElse("") + append;
}
}

Expand All @@ -990,7 +990,7 @@ private static String authNofMth(AuthorList authorList, int n, int m) {
if (lastAuthor.equals(Author.OTHERS)) {
return "+";
}
String lastName = lastAuthor.getLast()
String lastName = lastAuthor.getFamilyName()
.map(CitationKeyGenerator::removeDefaultUnwantedCharacters).orElse("");
return lastName.length() > n ? lastName.substring(0, n) : lastName;
}
Expand All @@ -1010,7 +1010,7 @@ static String authShort(AuthorList authorList) {
final int numberOfAuthors = authorList.getNumberOfAuthors();

if (numberOfAuthors == 1) {
author.append(authorList.getAuthor(0).getLast().orElse(""));
author.append(authorList.getAuthor(0).getFamilyName().orElse(""));
} else if (numberOfAuthors >= 2) {
for (int i = 0; (i < numberOfAuthors) && (i < 3); i++) {
author.append(authNofMth(authorList, 1, i + 1));
Expand Down
18 changes: 11 additions & 7 deletions src/main/java/org/jabref/logic/exporter/MSBibExporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,37 @@
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;

import org.jspecify.annotations.NonNull;

/**
* TemplateExporter for exporting in MSBIB XML format.
*/
class MSBibExporter extends Exporter {

private final TransformerFactory transformerFactory;

public MSBibExporter() {
super("MSBib", "MS Office 2007", StandardFileType.XML);
transformerFactory = TransformerFactory.newInstance();
}

@Override
public void export(final BibDatabaseContext databaseContext, final Path file,
List<BibEntry> entries) throws SaveException {
Objects.requireNonNull(databaseContext);
Objects.requireNonNull(entries);

public void export(@NonNull BibDatabaseContext databaseContext,
@NonNull Path file,
@NonNull List<BibEntry> entries) throws SaveException {
Objects.requireNonNull(databaseContext); // required by test case
Comment on lines +37 to +40
Copy link
Member

Choose a reason for hiding this comment

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

This is somekind of silly, isn't it?

Copy link
Member Author

Choose a reason for hiding this comment

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

Future work would be to introduce JSPecify more globally - but I did not want to escalate the PR here.

if (entries.isEmpty()) {
return;
}

MSBibDatabase msBibDatabase = new MSBibDatabase(databaseContext.getDatabase(), entries);

// forcing to use UTF8 output format for some problems with xml export in other encodings
// forcing to use UTF8 output format for some problems with XML export in other encodings
try (AtomicFileWriter ps = new AtomicFileWriter(file, StandardCharsets.UTF_8)) {
try {
DOMSource source = new DOMSource(msBibDatabase.getDomForExport());
StreamResult result = new StreamResult(ps);
Transformer trans = TransformerFactory.newInstance().newTransformer();
Transformer trans = transformerFactory.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.transform(source, result);
} catch (TransformerException | IllegalArgumentException | TransformerFactoryConfigurationError e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The inverse operation is "somehow" contained in {@link org.jabref.logic.openoffice.style.OOPreFormatter}
*/
public class HtmlToLatexFormatter extends Formatter implements LayoutFormatter {

private static final Logger LOGGER = LoggerFactory.getLogger(HtmlToLatexFormatter.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package org.jabref.logic.formatter.bibtexfields;

import java.util.Objects;

import org.jabref.logic.cleanup.Formatter;
import org.jabref.logic.l10n.Localization;

import org.jspecify.annotations.NullMarked;

@NullMarked
public class RemoveBracesFormatter extends Formatter {

@Override
Expand All @@ -19,8 +20,6 @@ public String getKey() {

@Override
public String format(String value) {
Objects.requireNonNull(value);

String formatted = value;
while ((formatted.length() >= 2) && (formatted.charAt(0) == '{') && (formatted.charAt(formatted.length() - 1)
== '}')) {
Expand Down Expand Up @@ -50,7 +49,7 @@ public String getExampleInput() {

/**
* Check if a string at any point has had more ending } braces than opening { ones.
* Will e.g. return true for the string "DNA} blahblal {EPA"
* Will e.g. return true for the string "DNA} text {EPA"
*
* @param value The string to check.
* @return true if at any index the brace count is negative.
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/org/jabref/logic/importer/AuthorListParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import org.jabref.model.entry.Author;
import org.jabref.model.entry.AuthorList;
import org.jabref.model.strings.StringUtil;

import org.jspecify.annotations.NonNull;

public class AuthorListParser {

// Avoid partition where these values are contained
Expand Down Expand Up @@ -94,9 +95,7 @@ private static StringBuilder buildWithAffix(Collection<Integer> indexArray, List
* @param listOfNames the String containing the person names to be parsed
* @return a parsed list of persons
*/
public AuthorList parse(String listOfNames) {
Objects.requireNonNull(listOfNames);

public AuthorList parse(@NonNull String listOfNames) {
Copy link
Member

@Siedlerchr Siedlerchr Mar 15, 2024

Choose a reason for hiding this comment

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

As I told you before I am not a fan of this NonNull stuff, It servers the same purpose as the Objects.requiresNonNull No benefit here

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I know. We always have that debate :)

I'll collect pros and cons in an ADR.

TL;DR for me. It enables static code analysis for nulls - not some runtime exception stuff. JabRef should not die because of NPEs.

Links - it was approved twice and did not cause any issues yet

// Handling of "and others"
// Remove it from the list; it will be added at the very end of this method as special Author.OTHERS
listOfNames = listOfNames.trim();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/logic/importer/Importer.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public abstract class Importer implements Comparable<Importer> {
* The effect of this method is primarily to avoid unnecessary processing of files when searching for a suitable
* import format. If this method returns false, the import routine will move on to the next import format.
* <p>
* Thus the correct behaviour is to return false if it is certain that the file is not of the suitable type, and
* Thus, the correct behaviour is to return false if it is certain that the file is not of the suitable type, and
* true otherwise. Returning true is the safe choice if not certain.
*/
public abstract boolean isRecognizedFormat(BufferedReader input) throws IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public URL getURLForEntry(BibEntry entry) throws URISyntaxException, MalformedUR
// replace "and" by ";" as citation matching API uses ";" for separation
AuthorList authors = AuthorList.parse(entry.getFieldOrAlias(StandardField.AUTHOR).get());
String authorsWithSemicolon = authors.getAuthors().stream()
.map(author -> author.getLastFirst(false))
.map(author -> author.getFamilyGiven(false))
.collect(Collectors.joining(";"));
uriBuilder.addParameter("a", authorsWithSemicolon);
}
Expand Down
Loading
Loading