Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions .jbang/JabLsLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/util/LspDiagnosticBuilder.java
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/util/LspDiagnosticHandler.java
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/util/LspIntegrityCheck.java
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/util/LspLinkHandler.java
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/util/LspParserHandler.java
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/util/LspRangeUtil.java
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/util/definition/DefinitionProvider.java
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/util/definition/DefinitionProviderFactory.java
//SOURCES ../jabls/src/main/java/org/jabref/languageserver/util/definition/MarkdownDefinitionProvider.java

// REPOS mavencentral,snapshots=https://central.sonatype.com/repository/maven-snapshots/
// REPOS mavencentral,mavencentralsnapshots=https://central.sonatype.com/repository/maven-snapshots/,s01oss=https://s01.oss.sonatype.org/content/repositories/snapshots/,oss=https://oss.sonatype.org/content/repositories,jitpack=https://jitpack.io,oss2=https://oss.sonatype.org/content/groups/public,ossrh=https://oss.sonatype.org/content/repositories/snapshots
Expand Down
8 changes: 3 additions & 5 deletions jabgui/src/main/java/org/jabref/gui/JabRefGUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -424,20 +424,18 @@ private boolean upperRightIsInBounds(CoreGuiPreferences coreGuiPreferences) {
// Background tasks
public void startBackgroundTasks() {
RemotePreferences remotePreferences = preferences.getRemotePreferences();

CLIMessageHandler cliMessageHandler = new CLIMessageHandler(mainFrame, preferences);
if (remotePreferences.useRemoteServer()) {
remoteListenerServerManager.openAndStart(
new CLIMessageHandler(
mainFrame,
preferences),
cliMessageHandler,
remotePreferences.getPort());
}

if (remotePreferences.enableHttpServer()) {
httpServerManager.start(stateManager, remotePreferences.getHttpServerUri());
}
if (remotePreferences.enableLanguageServer()) {
languageServerController.start(remotePreferences.getLanguageServerPort());
languageServerController.start(cliMessageHandler, remotePreferences.getLanguageServerPort());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,13 @@ public void storeSettings() {
});

UiMessageHandler uiMessageHandler = Injector.instantiateModelOrService(UiMessageHandler.class);
CLIMessageHandler messageHandler = new CLIMessageHandler(uiMessageHandler, preferences);
RemoteListenerServerManager remoteListenerServerManager = Injector.instantiateModelOrService(RemoteListenerServerManager.class);
// stop in all cases, because the port might have changed
remoteListenerServerManager.stop();
if (remoteServerProperty.getValue()) {
remotePreferences.setUseRemoteServer(true);
remoteListenerServerManager.openAndStart(
new CLIMessageHandler(uiMessageHandler, preferences),
remoteListenerServerManager.openAndStart(messageHandler,
remotePreferences.getPort());
} else {
remotePreferences.setUseRemoteServer(false);
Expand Down Expand Up @@ -327,7 +327,7 @@ public void storeSettings() {
languageServerController.stop();
if (enableLanguageServerProperty.getValue()) {
remotePreferences.setEnableLanguageServer(true);
languageServerController.start(remotePreferences.getLanguageServerPort());
languageServerController.start(messageHandler, remotePreferences.getLanguageServerPort());
} else {
remotePreferences.setEnableLanguageServer(false);
languageServerController.stop();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ public void setPath(Path path) {
*
* @param s String Warning text. Must be pre-translated. Only added if there isn't already a dupe.
*/
public void addWarning(String s) {
public void addWarning(@NonNull String s) {
addWarning(Range.NULL_RANGE, s);
}

public void addWarning(Range range, String s) {
public void addWarning(Range range, @NonNull String s) {
warnings.put(range, s);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,56 @@
package org.jabref.languageserver;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

import org.jabref.languageserver.util.LspDiagnosticHandler;
import org.jabref.languageserver.util.LspLinkHandler;
import org.jabref.logic.remote.server.RemoteMessageHandler;

import com.google.gson.JsonArray;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionList;
import org.eclipse.lsp4j.CompletionParams;
import org.eclipse.lsp4j.DefinitionParams;
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
import org.eclipse.lsp4j.DidSaveTextDocumentParams;
import org.eclipse.lsp4j.DocumentLink;
import org.eclipse.lsp4j.DocumentLinkParams;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
import org.eclipse.lsp4j.TextDocumentItem;
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.jspecify.annotations.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BibtexTextDocumentService implements TextDocumentService {

private final LspDiagnosticHandler diagnosticHandler;
private static final Logger LOGGER = LoggerFactory.getLogger(BibtexTextDocumentService.class);

private final LspClientHandler clientHandler;
private final LspDiagnosticHandler diagnosticHandler;
private final LspLinkHandler linkHandler;
private final RemoteMessageHandler messageHandler;
private final Map<String, String> fileUriToLanguageId;
private final Map<String, String> contentCache;
private LanguageClient client;

public BibtexTextDocumentService(@NonNull LspDiagnosticHandler diagnosticHandler) {
public BibtexTextDocumentService(@NonNull RemoteMessageHandler messageHandler, @NonNull LspClientHandler clientHandler, @NonNull LspDiagnosticHandler diagnosticHandler, @NonNull LspLinkHandler linkHandler) {
this.clientHandler = clientHandler;
this.diagnosticHandler = diagnosticHandler;
this.linkHandler = linkHandler;
this.fileUriToLanguageId = new ConcurrentHashMap<>();
this.contentCache = new ConcurrentHashMap<>();
this.messageHandler = messageHandler;
}

public void setClient(LanguageClient client) {
Expand All @@ -33,22 +59,73 @@ public void setClient(LanguageClient client) {

@Override
public void didOpen(DidOpenTextDocumentParams params) {
diagnosticHandler.computeAndPublishDiagnostics(client, params.getTextDocument().getUri(), params.getTextDocument().getText(), params.getTextDocument().getVersion());
TextDocumentItem textDocument = params.getTextDocument();
LOGGER.debug("didOpen {}", textDocument.getUri());
fileUriToLanguageId.putIfAbsent(textDocument.getUri(), textDocument.getLanguageId());

if ("bibtex".equals(textDocument.getLanguageId())) {
diagnosticHandler.computeAndPublishDiagnostics(client, textDocument.getUri(), textDocument.getText(), textDocument.getVersion());
} else {
contentCache.put(textDocument.getUri(), textDocument.getText());
}
}

@Override
public void didChange(DidChangeTextDocumentParams params) {
diagnosticHandler.computeAndPublishDiagnostics(client, params.getTextDocument().getUri(), params.getContentChanges().getFirst().getText(), params.getTextDocument().getVersion());
VersionedTextDocumentIdentifier textDocument = params.getTextDocument();
TextDocumentContentChangeEvent contentChange = params.getContentChanges().getFirst();
LOGGER.debug("didChange {}", textDocument.getUri());
String languageId = fileUriToLanguageId.get(textDocument.getUri());

if ("bibtex".equalsIgnoreCase(languageId)) {
diagnosticHandler.computeAndPublishDiagnostics(client, textDocument.getUri(), contentChange.getText(), textDocument.getVersion());
} else {
contentCache.put(textDocument.getUri(), contentChange.getText());
}
}

@Override
public void didClose(DidCloseTextDocumentParams params) {
fileUriToLanguageId.remove(params.getTextDocument().getUri());
contentCache.remove(params.getTextDocument().getUri());
}

@Override
public void didSave(DidSaveTextDocumentParams params) {
}

@Override
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition(DefinitionParams params) {
if (!clientHandler.isStandalone()) {
return CompletableFuture.completedFuture(Either.forLeft(List.of()));
}
if (fileUriToLanguageId.containsKey(params.getTextDocument().getUri())) {
String fileUri = params.getTextDocument().getUri();
return linkHandler.provideDefinition(fileUriToLanguageId.get(fileUri), fileUri, contentCache.get(fileUri), params.getPosition());
}
return CompletableFuture.completedFuture(Either.forLeft(List.of()));
}

@Override
public CompletableFuture<List<DocumentLink>> documentLink(DocumentLinkParams params) {
if (clientHandler.isStandalone()) {
return CompletableFuture.completedFuture(List.of());
}
String fileUri = params.getTextDocument().getUri();
return linkHandler.provideDocumentLinks(fileUriToLanguageId.get(fileUri), contentCache.get(fileUri));
}

@Override
public CompletableFuture<DocumentLink> documentLinkResolve(DocumentLink params) {
if (clientHandler.isStandalone()) {
return CompletableFuture.completedFuture(null);
}
if (params.getData() instanceof JsonArray data) {
messageHandler.handleCommandLineArguments(new String[] {data.asList().getFirst().getAsString(), data.asList().getLast().getAsString()});
}
return CompletableFuture.completedFuture(null);
}

@Override
public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completion(CompletionParams position) {
return TextDocumentService.super.completion(position);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public BibtexWorkspaceService(LspClientHandler clientHandler, LspDiagnosticHandl
this.diagnosticHandler = diagnosticHandler;
}

// Todo: handle event
@Override
public void didChangeConfiguration(DidChangeConfigurationParams didChangeConfigurationParams) {
if (didChangeConfigurationParams.getSettings() instanceof JsonObject settings) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import java.util.concurrent.CompletableFuture;

import org.jabref.languageserver.util.LspDiagnosticHandler;
import org.jabref.languageserver.util.LspLinkHandler;
import org.jabref.languageserver.util.LspParserHandler;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.preferences.CliPreferences;
import org.jabref.logic.remote.server.RemoteMessageHandler;

import org.eclipse.lsp4j.DocumentLinkOptions;
import org.eclipse.lsp4j.InitializeParams;
import org.eclipse.lsp4j.InitializeResult;
import org.eclipse.lsp4j.MessageParams;
Expand All @@ -27,17 +31,24 @@ public class LspClientHandler implements LanguageServer, LanguageClientAware {
private static final Logger LOGGER = LoggerFactory.getLogger(LspClientHandler.class);

private final LspDiagnosticHandler diagnosticHandler;
private final LspParserHandler parserHandler;
private final LspLinkHandler linkHandler;
private final BibtexWorkspaceService workspaceService;
private final BibtexTextDocumentService textDocumentService;
private final ExtensionSettings settings;
private final RemoteMessageHandler messageHandler;

private LanguageClient client;
private boolean standalone = false;

public LspClientHandler(CliPreferences cliPreferences, JournalAbbreviationRepository abbreviationRepository) {
public LspClientHandler(RemoteMessageHandler messageHandler, CliPreferences cliPreferences, JournalAbbreviationRepository abbreviationRepository) {
this.settings = ExtensionSettings.getDefaultSettings();
this.diagnosticHandler = new LspDiagnosticHandler(this, cliPreferences, abbreviationRepository);
this.parserHandler = new LspParserHandler();
this.diagnosticHandler = new LspDiagnosticHandler(this, parserHandler, cliPreferences, abbreviationRepository);
this.linkHandler = new LspLinkHandler(parserHandler);
this.workspaceService = new BibtexWorkspaceService(this, diagnosticHandler);
this.textDocumentService = new BibtexTextDocumentService(diagnosticHandler);
this.textDocumentService = new BibtexTextDocumentService(messageHandler, this, diagnosticHandler, linkHandler);
this.messageHandler = messageHandler;
}

@Override
Expand All @@ -51,6 +62,11 @@ public CompletableFuture<InitializeResult> initialize(InitializeParams params) {

capabilities.setTextDocumentSync(syncOptions);
capabilities.setWorkspace(new WorkspaceServerCapabilities());
capabilities.setDefinitionProvider(true);

DocumentLinkOptions linkOptions = new DocumentLinkOptions();
linkOptions.setResolveProvider(true);
capabilities.setDocumentLinkProvider(linkOptions);

return CompletableFuture.completedFuture(new InitializeResult(capabilities));
}
Expand Down Expand Up @@ -88,4 +104,12 @@ public void connect(LanguageClient client) {
textDocumentService.setClient(client);
client.logMessage(new MessageParams(MessageType.Warning, "BibtexLSPServer connected."));
}

public void setStandalone(boolean standalone) {
this.standalone = standalone;
}

public boolean isStandalone() {
return standalone;
}
}
26 changes: 21 additions & 5 deletions jabls/src/main/java/org/jabref/languageserver/LspLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
import org.jabref.logic.journals.JournalAbbreviationLoader;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.preferences.CliPreferences;
import org.jabref.logic.preferences.JabRefCliPreferences;
import org.jabref.logic.remote.server.RemoteMessageHandler;

import org.eclipse.lsp4j.jsonrpc.Launcher;
import org.eclipse.lsp4j.launch.LSPLauncher;
import org.eclipse.lsp4j.services.LanguageClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -25,21 +28,29 @@ public class LspLauncher extends Thread {
private final CliPreferences cliPreferences;
private final JournalAbbreviationRepository abbreviationRepository;
private final ExecutorService threadPool;
private final RemoteMessageHandler messageHandler;

private final int port;
private boolean standalone = false;
private volatile boolean running;
private ServerSocket serverSocket;

public LspLauncher(CliPreferences cliPreferences, JournalAbbreviationRepository abbreviationRepository, int port) {
public LspLauncher(RemoteMessageHandler messageHandler, CliPreferences cliPreferences, JournalAbbreviationRepository abbreviationRepository, int port) {
this.cliPreferences = cliPreferences;
this.abbreviationRepository = abbreviationRepository;
this.threadPool = Executors.newCachedThreadPool();
this.port = port;
this.setName("JabLs - JabRef Language Server on: " + port);
this.messageHandler = messageHandler;
}

public LspLauncher(CliPreferences cliPreferences, int port) {
this(cliPreferences, JournalAbbreviationLoader.loadRepository(cliPreferences.getJournalAbbreviationPreferences()), port);
public LspLauncher(RemoteMessageHandler messageHandler, CliPreferences cliPreferences, int port) {
this(messageHandler, cliPreferences, JournalAbbreviationLoader.loadRepository(cliPreferences.getJournalAbbreviationPreferences()), port);
}

public LspLauncher(JabRefCliPreferences instance, Integer port) {
this(_ -> LOGGER.warn("LSP cannot handle UICommands in standalone mode."), instance, port);
this.standalone = true;
}

@Override
Expand Down Expand Up @@ -69,12 +80,13 @@ public void run() {
}

private void handleClient(Socket socket) {
LspClientHandler clientHandler = new LspClientHandler(cliPreferences, abbreviationRepository);
LspClientHandler clientHandler = new LspClientHandler(messageHandler, cliPreferences, abbreviationRepository);
clientHandler.setStandalone(standalone);
LOGGER.debug("LSP clientHandler started.");
try (socket; // socket should be closed on error
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream()) {
Launcher<LanguageClient> launcher = org.eclipse.lsp4j.launch.LSPLauncher.createServerLauncher(clientHandler, in, out, Executors.newCachedThreadPool(), Function.identity());
Launcher<LanguageClient> launcher = LSPLauncher.createServerLauncher(clientHandler, in, out, Executors.newCachedThreadPool(), Function.identity());
LOGGER.debug("LSP clientHandler launched.");
clientHandler.connect(launcher.getRemoteProxy());
LOGGER.debug("LSP clientHandler connected.");
Expand Down Expand Up @@ -105,4 +117,8 @@ public void interrupt() {
public boolean isRunning() {
return running;
}

public boolean isStandalone() {
return standalone;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.jabref.languageserver.LspLauncher;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.preferences.CliPreferences;
import org.jabref.logic.remote.server.RemoteMessageHandler;

import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
Expand All @@ -24,13 +25,13 @@ public LanguageServerController(CliPreferences cliPreferences, JournalAbbreviati
LOGGER.debug("LanguageServerController initialized.");
}

public synchronized void start(int port) {
public synchronized void start(RemoteMessageHandler messageHandler, int port) {
if (lspLauncher != null) {
LOGGER.warn("Language server controller already started, cannot start again.");
return;
}

lspLauncher = new LspLauncher(cliPreferences, abbreviationRepository, port);
lspLauncher = new LspLauncher(messageHandler, cliPreferences, abbreviationRepository, port);
// This enqueues the thread to run in the background
// The JVM will take care of running it at some point in time in the future
// Thus, we cannot check directly if it really runs
Expand Down
Loading
Loading