From 5a4d719b970de887746db046ffb24c0c7795f687 Mon Sep 17 00:00:00 2001 From: Svata Dedic Date: Wed, 4 Sep 2024 08:37:30 +0200 Subject: [PATCH] Forces refresh of a FileObject after the LSP client reports the file has been saved. --- .../java/lsp/server/protocol/Server.java | 4 +++ .../protocol/TextDocumentServiceImpl.java | 34 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java index 203cb9e7bc75..be8e46a06d11 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java @@ -71,6 +71,7 @@ import org.eclipse.lsp4j.MessageType; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.RenameOptions; +import org.eclipse.lsp4j.SaveOptions; import org.eclipse.lsp4j.SemanticTokensCapabilities; import org.eclipse.lsp4j.SemanticTokensParams; import org.eclipse.lsp4j.ServerCapabilities; @@ -847,6 +848,9 @@ private InitializeResult constructInitResponse(InitializeParams init, JavaSource textDocumentSyncOptions.setChange(TextDocumentSyncKind.Incremental); textDocumentSyncOptions.setOpenClose(true); textDocumentSyncOptions.setWillSaveWaitUntil(true); + // TODO: we now do not request to send saved contents, but in case of client side applied text edits, it could be cool to + // receive the current document contents at a savepoint. + textDocumentSyncOptions.setSave(new SaveOptions(false)); capabilities.setTextDocumentSync(textDocumentSyncOptions); CompletionOptions completionOptions = new CompletionOptions(); completionOptions.setResolveProvider(true); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java index d51967268a8b..b4ff3bd29963 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java @@ -40,6 +40,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.nio.file.Path; @@ -79,6 +80,7 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.swing.JEditorPane; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; @@ -256,6 +258,7 @@ import org.openide.filesystems.FileUtil; import org.openide.filesystems.URLMapper; import org.openide.loaders.DataObject; +import org.openide.text.CloneableEditorSupport; import org.openide.text.NbDocument; import org.openide.text.PositionBounds; import org.openide.util.BaseUtilities; @@ -1773,9 +1776,34 @@ public CompletableFuture> willSaveWaitUntil(WillSaveTextDocumentP } @Override - public void didSave(DidSaveTextDocumentParams arg0) { - //TODO: nothing for now? - LOG.log(Level.FINER, "didSave: {0}", arg0); + public void didSave(DidSaveTextDocumentParams savedParams) { + LOG.log(Level.FINER, "didSave: {0}", savedParams); + FileObject file = fromURI(savedParams.getTextDocument().getUri()); + if (file == null) { + return; + } + // refresh the file systems, potentially fire events + file.refresh(); + EditorCookie cake = file.getLookup().lookup(EditorCookie.class); + if (cake == null) { + return; + } + StyledDocument alreadyLoaded = cake.getDocument(); + if (alreadyLoaded == null) { + return; + } + try { + // if the FileObject.refresh() only now discovered a change, it have fired an event and initiated a reload, which might + // be still pending. Grab the reload task and wait for it: + Method reload = CloneableEditorSupport.class.getDeclaredMethod("reloadDocument"); + reload.setAccessible(true); + org.openide.util.Task t = (org.openide.util.Task)reload.invoke(cake); + // wait for a limited time, this could be enough for the reload to complete, blocking LSP queue. We do not want to block LSP queue indefinitely: + // in case of an error, the server could become unresponsive. + t.waitFinished(300); + } catch (ReflectiveOperationException | InterruptedException | SecurityException ex) { + // nop + } } CompletableFuture> superImplementations(String uri, Position position) {