Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
426b0bf
feat: implement initial solution to incorporating DefaultFileMonitor …
VinterSallad Feb 27, 2024
c2370b8
fix: address issues with concurrency in DefaultFileUpdateMonitor (Jab…
VinterSallad Feb 28, 2024
4eaf252
feat: improve logic for when filemonitor is added (JabRef#10585)
VinterSallad Feb 28, 2024
b4fa3a9
fix: revert the changes to DefaultFileUpdateMonitor and implement alt…
VinterSallad Feb 28, 2024
3e0f7a5
fix: refactor listener handling into methods (JabRef#10585)
VinterSallad Feb 29, 2024
3e7fb9e
feat: implement initial to listen a directory recursively (JabRef#10585)
roxannecvl Feb 29, 2024
14880ac
fix : refactor of listenerOnDirectory (JabRef#10585)
roxannecvl Feb 29, 2024
6c1bb03
Fix : If a change happens in an old directory, reload is no longer tr…
roxannecvl Feb 29, 2024
ce93345
fix: setListener started later and update to refreshLatexDirectory
MercuriaL01 Mar 1, 2024
71ea781
feat : implement proper shutdown (#10585)
rachedkko Mar 2, 2024
59797e5
fix : add one more test to improve the branch coverage (#10585)
rachedkko Mar 2, 2024
ba8adec
fix : add a remove listener method (#10585)
rachedkko Mar 3, 2024
fdd6750
fix : update the close method (#10585)
rachedkko Mar 3, 2024
dc161ca
fix : update the close method (#10585)
rachedkko Mar 3, 2024
ad19f5a
fix : add a shutdown method (#10585)
rachedkko Mar 3, 2024
8ff512e
fix : no override for the close method (#10585)
rachedkko Mar 3, 2024
afb4c09
fix : checkstyle (#10585)
rachedkko Mar 3, 2024
7f3b5f2
fix : checkstyle (#10585)
rachedkko Mar 3, 2024
653660e
fix : checkstyle (#10585)
rachedkko Mar 3, 2024
6f2982d
fix : checkstyle (#10585)
rachedkko Mar 3, 2024
2fd55bb
fix : checkstyle (#10585)
rachedkko Mar 3, 2024
2ea59b5
Update src/main/java/org/jabref/gui/entryeditor/LatexCitationsTabView…
VinterSallad Mar 3, 2024
07423e8
fix : delete wrong testcase
rachedkko Mar 3, 2024
f3d3b90
Merge branch 'latexcitation-filemonitor-issue-10585' of github.com:ra…
rachedkko Mar 3, 2024
51848ad
fix: Added addListenerForDirectory method to interface
Emiesce Mar 3, 2024
7d1aa43
fix: Changed @param comment to match method parameter
Emiesce Mar 3, 2024
0eff465
fix : add a close method
rachedkko Mar 3, 2024
c3e9b13
fix : add a closeAllTabs method
rachedkko Mar 3, 2024
ac4950e
fix : make close an override method
rachedkko Mar 3, 2024
9318193
fix : call closeAllTabs for proper shutdown
rachedkko Mar 3, 2024
271e62c
Merge branch 'latexcitation-filemonitor-issue-10585' of github.com:ra…
rachedkko Mar 3, 2024
632f250
fix : delete incorrect method
rachedkko Mar 3, 2024
d0c1e0c
fix : make closeAllTabs public
rachedkko Mar 3, 2024
794291c
fix : stylefix
rachedkko Mar 3, 2024
79027ee
fix: Added suggested test case
Emiesce Mar 3, 2024
968bcf6
fix: Added suggested test case
Emiesce Mar 3, 2024
d670888
refactor: Moved searchAndParse and searchDirectory method to new Cita…
Emiesce Mar 4, 2024
c0b171e
fix: stylecheck fix
Emiesce Mar 4, 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
8 changes: 4 additions & 4 deletions src/main/java/org/jabref/gui/JabRefExecutorService.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,12 @@ public static void gracefullyShutdown(ExecutorService executorService) {
try {
// This is non-blocking. See https://stackoverflow.com/a/57383461/873282.
executorService.shutdown();
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
LOGGER.debug("One minute passed, {} still not completed. Trying forced shutdown.", executorService.toString());
if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
LOGGER.debug("10 seconds, {} still not completed. Trying forced shutdown.", executorService.toString());
// those threads will be interrupted in their current task
executorService.shutdownNow();
if (executorService.awaitTermination(60, TimeUnit.SECONDS)) {
LOGGER.debug("One minute passed again - forced shutdown of {} worked.", executorService.toString());
if (executorService.awaitTermination(10, TimeUnit.SECONDS)) {
LOGGER.debug("10 seconds passed again - forced shutdown of {} worked.", executorService.toString());
} else {
LOGGER.error("{} did not terminate", executorService.toString());
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/jabref/gui/LibraryTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,7 @@ private void onCloseRequest(Event event) {
* Perform necessary cleanup when this Library is closed.
*/
private void onClosed(Event event) {
entryEditor.closeAllTabs();
if (dataLoadingTask != null) {
dataLoadingTask.cancel();
}
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -442,4 +442,11 @@ public void nextPreviewStyle() {
public void previousPreviewStyle() {
this.entryEditorTabs.forEach(EntryEditorTab::previousPreviewStyle);
}

/**
* Close all tabs that needs proper closing
*/
public void closeAllTabs() {
tabs.forEach(EntryEditorTab::close);
}
}
7 changes: 7 additions & 0 deletions src/main/java/org/jabref/gui/entryeditor/EntryEditorTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,11 @@ protected void nextPreviewStyle() {
protected void previousPreviewStyle() {
// do nothing by default
}

/**
* Close the tab - should be overriden if a EntryEditorTab has any actions to perform on close
*/
protected void close() {
// Do nothing by default
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,9 @@ protected void bindToEntry(BibEntry entry) {
public boolean shouldShow(BibEntry entry) {
return viewModel.shouldShow();
}

@Override
public void close() {
viewModel.shutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Future;
import java.util.stream.Stream;

import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyListWrapper;
import javafx.beans.property.SimpleObjectProperty;
Expand All @@ -18,16 +20,19 @@

import org.jabref.gui.AbstractViewModel;
import org.jabref.gui.DialogService;
import org.jabref.gui.Globals;
import org.jabref.gui.util.BackgroundTask;
import org.jabref.gui.util.DefaultFileUpdateMonitor;
import org.jabref.gui.util.DirectoryDialogConfiguration;
import org.jabref.gui.util.TaskExecutor;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.texparser.DefaultLatexParser;
import org.jabref.logic.texparser.CitationFinder;
import org.jabref.logic.util.io.FileUtil;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.texparser.Citation;
import org.jabref.model.texparser.LatexParserResult;
import org.jabref.model.util.FileUpdateListener;
import org.jabref.preferences.PreferencesService;

import org.slf4j.Logger;
Expand All @@ -42,8 +47,14 @@ enum Status {
ERROR
}

enum Action {
ADD,
REMOVE,
}

private static final Logger LOGGER = LoggerFactory.getLogger(LatexCitationsTabViewModel.class);
private static final String TEX_EXT = ".tex";
private final CitationFinder citationFinder;
private final BibDatabaseContext databaseContext;
private final PreferencesService preferencesService;
private final TaskExecutor taskExecutor;
Expand All @@ -55,6 +66,9 @@ enum Status {
private Future<?> searchTask;
private LatexParserResult latexParserResult;
private BibEntry currentEntry;
private final DefaultFileUpdateMonitor fileUpdateMonitor;
private boolean hasListener;
private final Map<Path, FileUpdateListener> listeners = new HashMap<>();

public LatexCitationsTabViewModel(BibDatabaseContext databaseContext,
PreferencesService preferencesService,
Expand All @@ -69,6 +83,10 @@ public LatexCitationsTabViewModel(BibDatabaseContext databaseContext,
this.citationList = FXCollections.observableArrayList();
this.status = new SimpleObjectProperty<>(Status.IN_PROGRESS);
this.searchError = new SimpleStringProperty("");

this.fileUpdateMonitor = (DefaultFileUpdateMonitor) Globals.getFileUpdateMonitor();
this.hasListener = false;
this.citationFinder = new CitationFinder();
}

public void init(BibEntry entry) {
Expand All @@ -79,6 +97,7 @@ public void init(BibEntry entry) {

if (citeKey.isPresent()) {
startSearch(citeKey.get());
updateListener(directory.get());
} else {
searchError.set(Localization.lang("Selected entry does not have an associated citation key."));
status.set(Status.ERROR);
Expand All @@ -102,7 +121,7 @@ public StringProperty searchErrorProperty() {
}

private void startSearch(String citeKey) {
searchTask = BackgroundTask.wrap(() -> searchAndParse(citeKey))
searchTask = BackgroundTask.wrap(() -> citationFinder.searchAndParse(databaseContext, preferencesService, directory, citeKey))
.onRunning(() -> status.set(Status.IN_PROGRESS))
.onSuccess(result -> {
citationList.setAll(result);
Expand All @@ -124,58 +143,82 @@ private void cancelSearch() {
searchTask.cancel(true);
}

private Collection<Citation> searchAndParse(String citeKey) throws IOException {
// we need to check whether the user meanwhile set the LaTeX file directory or the database changed locations
Path newDirectory = databaseContext.getMetaData().getLatexFileDirectory(preferencesService.getFilePreferences().getUserAndHost())
.orElse(FileUtil.getInitialDirectory(databaseContext, preferencesService.getFilePreferences().getWorkingDirectory()));

if (latexParserResult == null || !newDirectory.equals(directory.get())) {
directory.set(newDirectory);

if (!newDirectory.toFile().exists()) {
throw new IOException("Current search directory does not exist: %s".formatted(newDirectory));
private void updateListener(Path path) {
if (!hasListener) {
try {
listenerOnDirectory(path, Action.ADD);
hasListener = true;
} catch (IOException e) {
LOGGER.error("Could add listener", e);
}

List<Path> texFiles = searchDirectory(newDirectory);
LOGGER.debug("Found tex files: {}", texFiles);
latexParserResult = new DefaultLatexParser().parse(texFiles);
}

return latexParserResult.getCitationsByKey(citeKey);
}

/**
* @param directory the directory to search for. It is recursively searched.
*/
private List<Path> searchDirectory(Path directory) {
LOGGER.debug("Searching directory {}", directory);
private void updateListener(Path oldPath, Path newPath) {
try {
return Files.walk(directory)
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(TEX_EXT))
.toList();
listenerOnDirectory(newPath, Action.ADD);
listenerOnDirectory(oldPath, Action.REMOVE);
} catch (IOException e) {
LOGGER.error("Could update listener", e);
}
}

private void listenerOnDirectory(Path path, Action action) throws IOException {
try (Stream<Path> paths = Files.walk(path)) {
paths.filter(curPath -> !Files.isRegularFile(curPath))
.forEach(curDir -> {
try {
if (action == Action.ADD) {
FileUpdateListener newListener = this::refreshLatexDirectory;
listeners.put(curDir, newListener);
fileUpdateMonitor.addListenerForDirectory(curDir, newListener);
} else if (action == Action.REMOVE) {
FileUpdateListener oldListener = listeners.remove(curDir);
fileUpdateMonitor.removeListener(curDir, oldListener);
}
} catch (IOException e) {
LOGGER.error("Could not find file", e);
}
});
} catch (IOException e) {
LOGGER.error("Error while searching files", e);
return List.of();
LOGGER.error("Could not create a Stream<Path>", e);
}
}

public void setLatexDirectory() {
DirectoryDialogConfiguration directoryDialogConfiguration = new DirectoryDialogConfiguration.Builder()
.withInitialDirectory(directory.get()).build();

dialogService.showDirectorySelectionDialog(directoryDialogConfiguration).ifPresent(selectedDirectory ->
databaseContext.getMetaData().setLatexFileDirectory(preferencesService.getFilePreferences().getUserAndHost(), selectedDirectory.toAbsolutePath()));
dialogService.showDirectorySelectionDialog(directoryDialogConfiguration).ifPresent(selectedDirectory -> {
databaseContext.getMetaData().setLatexFileDirectory(preferencesService.getFilePreferences().getUserAndHost(), selectedDirectory.toAbsolutePath());
updateListener(directory.get(), selectedDirectory);
});

init(currentEntry);
}

public void refreshLatexDirectory() {
latexParserResult = null;
init(currentEntry);
Platform.runLater(() -> {
cancelSearch();
init(currentEntry);
});
}

public boolean shouldShow() {
return preferencesService.getEntryEditorPreferences().shouldShowLatexCitationsTab();
}

public void shutdown() {
// remove listeners
if (hasListener) {
try {
listenerOnDirectory(directory.get(), Action.REMOVE);
hasListener = false;
} catch (IOException e) {
LOGGER.error("Could not remove listener", e);
}
}
fileUpdateMonitor.shutdown();
}
}
29 changes: 26 additions & 3 deletions src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
Expand All @@ -32,8 +34,8 @@ public class DefaultFileUpdateMonitor implements Runnable, FileUpdateMonitor {

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

Comment thread
VinterSallad marked this conversation as resolved.
private final Multimap<Path, FileUpdateListener> listeners = ArrayListMultimap.create(20, 4);
private volatile WatchService watcher;
final Multimap<Path, FileUpdateListener> listeners = ArrayListMultimap.create(20, 4);
volatile WatchService watcher;
private final AtomicBoolean notShutdown = new AtomicBoolean(true);
private final AtomicReference<Optional<JabRefException>> filesystemMonitorFailure = new AtomicReference<>(Optional.empty());

Expand Down Expand Up @@ -82,7 +84,12 @@ public boolean isActive() {
}

private void notifyAboutChange(Path path) {
listeners.get(path).forEach(FileUpdateListener::fileUpdated);
Collection<FileUpdateListener> fileUpdateListeners = Collections.emptyList();
while ((path != null) && (fileUpdateListeners.isEmpty())) {
fileUpdateListeners = listeners.get(path);
path = path.getParent();
}
fileUpdateListeners.forEach(FileUpdateListener::fileUpdated);
}

@Override
Expand All @@ -97,6 +104,22 @@ public void addListenerForFile(Path file, FileUpdateListener listener) throws IO
}
}

/**
* Add a new directory to monitor.
*
* @param directory The directory to monitor.
* @throws IOException if the directory does not exist.
*/
public void addListenerForDirectory(Path directory, FileUpdateListener listener) throws IOException {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Add the method also to the interface so that there is no need to cast in LatexCitationsViewModel

// This function was created because it makes more sense to call addListenerForDirectory when
// the Path is a directory and not a file, even though it does the same thing as addListenerForFile.
// The function addListenerForFile works for directories as well. We have to listen to the parent
// directory in this case too otherwise if a new file is created in the child directory, no

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is wrong. You really need to update the DefaultFileMonitorImplementation.

Here a test case that notifications for new files works:

diff --git a/src/main/java/org/jabref/gui/JabRefExecutorService.java b/src/main/java/org/jabref/gui/JabRefExecutorService.java
index 90c3b31bda..74eb0bbea5 100644
--- a/src/main/java/org/jabref/gui/JabRefExecutorService.java
+++ b/src/main/java/org/jabref/gui/JabRefExecutorService.java
@@ -184,12 +184,12 @@ public class JabRefExecutorService {
         try {
             // This is non-blocking. See https://stackoverflow.com/a/57383461/873282.
             executorService.shutdown();
-            if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
-                LOGGER.debug("One minute passed, {} still not completed. Trying forced shutdown.", executorService.toString());
+            if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
+                LOGGER.debug("10 seconds, {} still not completed. Trying forced shutdown.", executorService.toString());
                 // those threads will be interrupted in their current task
                 executorService.shutdownNow();
-                if (executorService.awaitTermination(60, TimeUnit.SECONDS)) {
-                    LOGGER.debug("One minute passed again - forced shutdown of {} worked.", executorService.toString());
+                if (executorService.awaitTermination(10, TimeUnit.SECONDS)) {
+                    LOGGER.debug("10 seconds passed again - forced shutdown of {} worked.", executorService.toString());
                 } else {
                     LOGGER.error("{} did not terminate", executorService.toString());
                 }
diff --git a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java
index 0090539a96..bcb88189ef 100644
--- a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java
+++ b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java
@@ -8,6 +8,8 @@ import java.nio.file.StandardWatchEventKinds;
 import java.nio.file.WatchEvent;
 import java.nio.file.WatchKey;
 import java.nio.file.WatchService;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Optional;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
@@ -32,8 +34,8 @@ public class DefaultFileUpdateMonitor implements Runnable, FileUpdateMonitor {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(DefaultFileUpdateMonitor.class);
 
-    private final Multimap<Path, FileUpdateListener> listeners = ArrayListMultimap.create(20, 4);
-    private volatile WatchService watcher;
+    volatile WatchService watcher;
+    final Multimap<Path, FileUpdateListener> listeners = ArrayListMultimap.create(20, 4);
     private final AtomicBoolean notShutdown = new AtomicBoolean(true);
     private final AtomicReference<Optional<JabRefException>> filesystemMonitorFailure = new AtomicReference<>(Optional.empty());
 
@@ -82,7 +84,12 @@ public class DefaultFileUpdateMonitor implements Runnable, FileUpdateMonitor {
     }
 
     private void notifyAboutChange(Path path) {
-        listeners.get(path).forEach(FileUpdateListener::fileUpdated);
+        Collection<FileUpdateListener> fileUpdateListeners = Collections.emptyList();
+        while ((path != null) && (fileUpdateListeners.isEmpty())) {
+            fileUpdateListeners = listeners.get(path);
+            path = path.getParent();
+        }
+        fileUpdateListeners.forEach(FileUpdateListener::fileUpdated);
     }
 
     @Override
@@ -126,6 +133,7 @@ public class DefaultFileUpdateMonitor implements Runnable, FileUpdateMonitor {
             if (watcher != null) {
                 watcher.close();
             }
+            Thread.currentThread().interrupt();
         } catch (IOException e) {
             LOGGER.error("error closing watcher", e);
         }
diff --git a/src/test/java/org/jabref/gui/util/DefaultFileUpdateMonitorTest.java b/src/test/java/org/jabref/gui/util/DefaultFileUpdateMonitorTest.java
new file mode 100644
index 0000000000..95c6235738
--- /dev/null
+++ b/src/test/java/org/jabref/gui/util/DefaultFileUpdateMonitorTest.java
@@ -0,0 +1,40 @@
+package org.jabref.gui.util;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardWatchEventKinds;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.jabref.gui.JabRefExecutorService;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class DefaultFileUpdateMonitorTest {
+
+    @Test
+    void demonstrateListenerForDirectory(@TempDir Path rootPath) throws Exception {
+        DefaultFileUpdateMonitor fileUpdateMonitor = new DefaultFileUpdateMonitor();
+        JabRefExecutorService.INSTANCE.executeInterruptableTask(fileUpdateMonitor, "FileUpdateMonitor");
+        while (fileUpdateMonitor.watcher == null) {
+            Thread.sleep(100);
+            Thread.yield();
+        }
+        rootPath.register(fileUpdateMonitor.watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);
+        final AtomicBoolean called = new AtomicBoolean(false);
+        fileUpdateMonitor.listeners.put(rootPath, () -> {
+            called.set(true);
+        });
+        Files.createFile(rootPath.resolve("test.txt"));
+        int callCount = 0;
+        while ((callCount < 10) && (!called.get())) {
+            Thread.sleep(100);
+            Thread.yield();
+            callCount++;
+        }
+        JabRefExecutorService.INSTANCE.shutdownEverything();
+        assertTrue(called.get());
+    }
+}

Maybe, you should add the Path of the changed file to FileUpdateListener.

Other approach: implement other classes handling directories and ensure that DefaultFileUpdateMonitor handles files only.

// event will be triggered as the path linked to the event doesn't match any paths in the MultiMap.

addListenerForFile(directory, listener);
}

@Override
public void removeListener(Path path, FileUpdateListener listener) {
listeners.remove(path, listener);
Expand Down
62 changes: 62 additions & 0 deletions src/main/java/org/jabref/logic/texparser/CitationFinder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.jabref.logic.texparser;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;

import javafx.beans.property.ObjectProperty;

import org.jabref.gui.entryeditor.LatexCitationsTabViewModel;
import org.jabref.logic.util.io.FileUtil;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.texparser.Citation;
import org.jabref.model.texparser.LatexParserResult;
import org.jabref.preferences.PreferencesService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CitationFinder {

private static final Logger LOGGER = LoggerFactory.getLogger(LatexCitationsTabViewModel.class);
private static final String TEX_EXT = ".tex";
private LatexParserResult latexParserResult;

public Collection<Citation> searchAndParse(BibDatabaseContext databaseContext, PreferencesService preferencesService, ObjectProperty<Path> directory, String citeKey) throws IOException {
// we need to check whether the user meanwhile set the LaTeX file directory or the database changed locations
Path newDirectory = databaseContext.getMetaData().getLatexFileDirectory(preferencesService.getFilePreferences().getUserAndHost())
.orElse(FileUtil.getInitialDirectory(databaseContext, preferencesService.getFilePreferences().getWorkingDirectory()));

if (latexParserResult == null || !newDirectory.equals(directory.get())) {
directory.set(newDirectory);

if (!newDirectory.toFile().exists()) {
throw new IOException("Current search directory does not exist: %s".formatted(newDirectory));
}

List<Path> texFiles = searchDirectory(newDirectory);
LOGGER.debug("Found tex files: {}", texFiles);
latexParserResult = new DefaultLatexParser().parse(texFiles);
}

return latexParserResult.getCitationsByKey(citeKey);
}

/**
* @param directory the directory to search for. It is recursively searched.
*/
private List<Path> searchDirectory(Path directory) {
LOGGER.debug("Searching directory {}", directory);
try {
return Files.walk(directory)
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(TEX_EXT))
.toList();
} catch (IOException e) {
LOGGER.error("Error while searching files", e);
return List.of();
}
}
}
Loading