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

Jump to entry key cli (WIP) #659

Closed
wants to merge 12 commits into from
Closed
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- When in `biblatex` mode, the [integrity check](https://docs.jabref.org/finding-sorting-and-cleaning-entries/checkintegrity) for journal titles now also checks the field `journal`.
- We added support for exporting to Hayagriva YAML format. [#10382](https://github.com/JabRef/jabref/issues/10382)
- We added support for pushing citations to [TeXShop](https://pages.uoregon.edu/koch/texshop/) on macOS [forum#2699](https://discourse.jabref.org/t/push-to-texshop-mac/2699).
- We added ability to jump to an entry in the command line using `-j CITATIONKEY [BIBTEXFILES]`. [koppor#540](https://github.com/koppor/jabref/issues/540)
- We added the 'Bachelor's thesis' type for Biblatex's 'Thesis' EntryType [#10029](https://github.com/JabRef/jabref/issues/10029).

### Changed
Expand Down
48 changes: 33 additions & 15 deletions src/main/java/org/jabref/cli/ArgumentProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.jabref.gui.externalfiles.AutoSetFileLinksUtil;
import org.jabref.gui.undo.NamedCompound;
import org.jabref.logic.JabRefException;
import org.jabref.logic.UiCommand;
import org.jabref.logic.bibtex.FieldPreferences;
import org.jabref.logic.citationkeypattern.CitationKeyGenerator;
import org.jabref.logic.exporter.AtomicFileWriter;
Expand Down Expand Up @@ -64,28 +65,31 @@
import org.slf4j.LoggerFactory;

public class ArgumentProcessor {

private static final Logger LOGGER = LoggerFactory.getLogger(ArgumentProcessor.class);
private final JabRefCLI cli;

// Written once by processArguments()
private List<ParserResult> parserResults = List.of();
public enum Mode { INITIAL_START, REMOTE_START }

private final JabRefCLI cli;

private final Mode startupMode;

private final PreferencesService preferencesService;
private final FileUpdateMonitor fileUpdateMonitor;
private final BibEntryTypesManager entryTypesManager;

private boolean noGUINeeded;
private final List<UiCommand> uiCommands = new ArrayList<>();

/**
* First call the constructor, then call {@link #processArguments()}.
* Afterward, you can access the {@link #getParserResults()} and other getters.
* Afterward, you can access the {@link #getUiCommands()}.
*/
public ArgumentProcessor(String[] args,
Mode startupMode,
PreferencesService preferencesService,
FileUpdateMonitor fileUpdateMonitor,
BibEntryTypesManager entryTypesManager) throws org.apache.commons.cli.ParseException {
BibEntryTypesManager entryTypesManager)
throws org.apache.commons.cli.ParseException {
this.cli = new JabRefCLI(args);
this.startupMode = startupMode;
this.preferencesService = preferencesService;
Expand Down Expand Up @@ -185,19 +189,17 @@ private Optional<ParserResult> importFile(Path file, String importFormat) {
}
}

public List<ParserResult> getParserResults() {
return parserResults;
}

public void processArguments() {
uiCommands.clear();
noGUINeeded = false;

if ((startupMode == Mode.INITIAL_START) && cli.isShowVersion()) {
cli.displayVersion();
}

if ((startupMode == Mode.INITIAL_START) && cli.isHelp()) {
JabRefCLI.printUsage(preferencesService);
noGUINeeded = true;
this.parserResults = Collections.emptyList();
return;
}

Expand All @@ -221,7 +223,6 @@ public void processArguments() {
if (cli.isExportMatches()) {
if (!loaded.isEmpty()) {
if (!exportMatches(loaded)) {
this.parserResults = Collections.emptyList();
return;
}
} else {
Expand Down Expand Up @@ -277,7 +278,13 @@ public void processArguments() {
doAuxImport(loaded);
}

this.parserResults = loaded;
if (!cli.isBlank() && cli.isJumpToKey()) {
jumpToKey(loaded, cli.getJumpToKey());
}

if (!cli.isBlank() && !loaded.isEmpty()) {
uiCommands.add(new UiCommand.OpenDatabases(loaded));
}
}

private void writeMetadataToPdf(List<ParserResult> loaded,
Expand Down Expand Up @@ -773,6 +780,17 @@ private Optional<ParserResult> fetch(String fetchCommand) {
}
}

private void jumpToKey(List<ParserResult> loaded, String citationKey) {
for (ParserResult parserResult : loaded) {
Optional<BibEntry> entry = parserResult.getDatabase().getEntryByCitationKey(citationKey);
if (entry.isPresent()) {
uiCommands.add(new UiCommand.JumpToEntryKey(parserResult, entry.get()));
return;
}
}
System.out.printf("Could not find citation key %s in any library%n", citationKey);
}

public boolean isBlank() {
return cli.isBlank();
}
Expand All @@ -781,7 +799,7 @@ public boolean shouldShutDown() {
return cli.isDisableGui() || cli.isShowVersion() || noGUINeeded;
}

public enum Mode {
INITIAL_START, REMOTE_START
public List<UiCommand> getUiCommands() {
return uiCommands;
}
}
16 changes: 16 additions & 0 deletions src/main/java/org/jabref/cli/JabRefCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ public String getWriteMetadatatoPdf() {
cl.hasOption("embeddBibfileInPdf") ? cl.getOptionValue("embeddBibfileInPdf") : null;
}

public String getJumpToKey() {
return cl.getOptionValue("jumpToKey");
}

public boolean isJumpToKey() {
return cl.hasOption("jumpToKey");
}

private static Options getOptions() {
Options options = new Options();

Expand Down Expand Up @@ -288,6 +296,14 @@ private static Options getOptions() {
.argName("CITEKEY1[,CITEKEY2][,CITEKEYn] | PDF1[,PDF2][,PDFn] | all")
.build());

options.addOption(Option
.builder("j")
.longOpt("jumpToKey")
.desc(String.format("%s: '%s'", Localization.lang("Jump to the entry of the given citation key."), "-j key"))
.hasArg()
.argName("CITATIONKEY")
.build());

return options;
}

Expand Down
13 changes: 12 additions & 1 deletion src/main/java/org/jabref/cli/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.jabref.gui.Globals;
import org.jabref.gui.MainApplication;
import org.jabref.logic.UiCommand;
import org.jabref.logic.journals.JournalAbbreviationLoader;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.net.ProxyAuthenticator;
Expand Down Expand Up @@ -100,7 +103,15 @@ public static void main(String[] args) {
System.exit(0);
}

MainApplication.main(argumentProcessor.getParserResults(), argumentProcessor.isBlank(), preferences, fileUpdateMonitor, ARGUMENTS);
List<UiCommand> uiCommands = new ArrayList<>(argumentProcessor.getUiCommands());
List<String> lastFiles = preferences.getGuiPreferences().getLastFilesOpened();
if (!argumentProcessor.isBlank() && preferences.getWorkspacePreferences().shouldOpenLastEdited() && !lastFiles.isEmpty()) {
for (String file : lastFiles) {
uiCommands.add(new UiCommand.OpenDatabaseFromPath(Path.of(file)));
}
}

MainApplication.main(uiCommands, preferences, fileUpdateMonitor, ARGUMENTS);
} catch (ParseException e) {
LOGGER.error("Problem parsing arguments", e);
JabRefCLI.printUsage(preferences);
Expand Down
128 changes: 128 additions & 0 deletions src/main/java/org/jabref/gui/JabRefFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.nio.file.Path;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -44,6 +45,7 @@
import org.jabref.gui.help.HelpAction;
import org.jabref.gui.importer.ImportEntriesDialog;
import org.jabref.gui.importer.NewEntryAction;
import org.jabref.gui.importer.ParserResultWarningDialog;
import org.jabref.gui.importer.actions.OpenDatabaseAction;
import org.jabref.gui.keyboard.KeyBinding;
import org.jabref.gui.keyboard.KeyBindingRepository;
Expand All @@ -57,11 +59,15 @@
import org.jabref.gui.util.BackgroundTask;
import org.jabref.gui.util.DefaultTaskExecutor;
import org.jabref.gui.util.TaskExecutor;
import org.jabref.logic.UiCommand;
import org.jabref.logic.help.HelpFile;
import org.jabref.logic.importer.ImportCleanup;
import org.jabref.logic.importer.ParserResult;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.shared.DatabaseLocation;
import org.jabref.logic.shared.DatabaseNotSupportedException;
import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException;
import org.jabref.logic.shared.exception.NotASharedDatabaseException;
import org.jabref.logic.undo.AddUndoableActionEvent;
import org.jabref.logic.undo.UndoChangeEvent;
import org.jabref.logic.undo.UndoRedoEvent;
Expand Down Expand Up @@ -960,6 +966,128 @@ public Stage getMainStage() {
return mainStage;
}

public void handleUiCommands(List<UiCommand> uiCommands) {
for (UiCommand uiCommand : uiCommands) {
switch (uiCommand) {
case UiCommand.OpenDatabaseFromPath command ->
getOpenDatabaseAction().openFile(command.path());
case UiCommand.JumpToEntryKey jumpToEntryKey -> {
Optional<LibraryTab> libraryTab = getLibraryTabs().stream()
.filter(tab -> tab.getDatabase()
.equals(jumpToEntryKey.parserResult()
.getDatabase()))
.findFirst();
libraryTab.ifPresent(tab -> {
tab.clearAndSelect(jumpToEntryKey.bibEntry());
showLibraryTab(tab);
});
}
case UiCommand.OpenDatabases command ->
openDatabases(command.parserResults());
}
}
}

private void openDatabases(List<ParserResult> parserResults) {
final List<ParserResult> toOpenTab = new ArrayList<>();

// Remove invalid databases
List<ParserResult> invalidDatabases = parserResults.stream()
.filter(ParserResult::isInvalid)
.toList();
final List<ParserResult> failed = new ArrayList<>(invalidDatabases);
parserResults.removeAll(invalidDatabases);

// passed file (we take the first one) should be focused
Path focusedFile = parserResults.stream()
.findFirst()
.flatMap(ParserResult::getPath)
.orElse(prefs.getGuiPreferences()
.getLastFocusedFile())
.toAbsolutePath();

// Add all bibDatabases databases to the frame:
boolean first = false;
for (ParserResult pr : parserResults) {
// Define focused tab
if (pr.getPath().filter(path -> path.toAbsolutePath().equals(focusedFile)).isPresent()) {
first = true;
}

if (pr.getDatabase().isShared()) {
try {
OpenDatabaseAction.openSharedDatabase(
pr,
this,
dialogService,
prefs,
stateManager,
entryTypesManager,
fileUpdateMonitor,
undoManager,
Globals.TASK_EXECUTOR);
} catch (
SQLException |
DatabaseNotSupportedException |
InvalidDBMSConnectionPropertiesException |
NotASharedDatabaseException e) {

LOGGER.error("Connection error", e);
dialogService.showErrorDialogAndWait(
Localization.lang("Connection error"),
Localization.lang("A local copy will be opened."),
e);
toOpenTab.add(pr);
}
} else if (pr.toOpenTab()) {
// things to be appended to an opened tab should be done after opening all tabs
// add them to the list
toOpenTab.add(pr);
} else {
addTab(pr, first);
first = false;
}
}

// finally add things to the currently opened tab
for (ParserResult parserResult : toOpenTab) {
addTab(parserResult, first);
first = false;
}

for (ParserResult pr : failed) {
String message = Localization.lang("Error opening file '%0'",
pr.getPath().map(Path::toString).orElse("(File name unknown)")) + "\n" +
pr.getErrorMessage();

dialogService.showErrorDialogAndWait(Localization.lang("Error opening file"), message);
}

// Display warnings, if any
int tabNumber = 0;
for (ParserResult pr : parserResults) {
ParserResultWarningDialog.showParserResultWarningDialog(pr, this, tabNumber++);
}

// After adding the databases, go through each and see if
// any post open actions need to be done. For instance, checking
// if we found new entry types that can be imported, or checking
// if the database contents should be modified due to new features
// in this version of JabRef.
// Note that we have to check whether i does not go over getBasePanelCount().
// This is because importToOpen might have been used, which adds to
// loadedDatabases, but not to getBasePanelCount()

for (int i = 0; (i < parserResults.size()) && (i < getBasePanelCount()); i++) {
ParserResult pr = parserResults.get(i);
LibraryTab libraryTab = getLibraryTabAt(i);

OpenDatabaseAction.performPostOpenActions(libraryTab, pr);
}

LOGGER.debug("Finished adding panels");
}

/**
* The action concerned with closing the window.
*/
Expand Down
Loading
Loading