Skip to content

Commit 17bf758

Browse files
LSP client stops working on file after renaming it
The LSP protocol requires that when a file is renamed the client signals this to the server by sending a didClose for the old location and after that a didOpen with the new location. The change assumes, that the IDE always goes through the DataObject to issue the rename/move. Changes through the raw FileObject are not tracked. Closes: #7806
1 parent a013912 commit 17bf758

File tree

9 files changed

+243
-48
lines changed

9 files changed

+243
-48
lines changed

ide/lsp.client/src/org/netbeans/modules/lsp/client/LSPBindings.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.Set;
4646
import java.util.WeakHashMap;
4747
import java.util.concurrent.CompletableFuture;
48+
import java.util.concurrent.ConcurrentHashMap;
4849
import java.util.concurrent.ExecutionException;
4950
import java.util.concurrent.TimeUnit;
5051
import java.util.concurrent.TimeoutException;
@@ -143,7 +144,7 @@ public class LSPBindings {
143144
}
144145

145146
private static final Map<FileObject, Map<BackgroundTask, RequestProcessor.Task>> backgroundTasks = new WeakHashMap<>();
146-
private final Set<FileObject> openedFiles = new HashSet<>();
147+
private final Map<FileObject, Boolean> openedFiles = new ConcurrentHashMap<>();
147148

148149
public static synchronized LSPBindings getBindings(FileObject file) {
149150
for (Entry<FileObject, Map<String, LSPBindings>> e : workspace2Extension2Server.entrySet()) {
@@ -542,7 +543,7 @@ private static Map<BackgroundTask, Task> backgroundTasksMapFor(FileObject file)
542543
return backgroundTasks.computeIfAbsent(file, f -> new IdentityHashMap<>());
543544
}
544545

545-
public Set<FileObject> getOpenedFiles() {
546+
public Map<FileObject, Boolean> getOpenedFiles() {
546547
return openedFiles;
547548
}
548549

ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java

+39-2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import org.openide.filesystems.URLMapper;
5858
import org.openide.loaders.DataFolder;
5959
import org.openide.loaders.DataObject;
60+
import org.openide.loaders.DataObjectNotFoundException;
6061
import org.openide.text.Line;
6162
import org.openide.text.NbDocument;
6263
import org.openide.util.Exceptions;
@@ -71,6 +72,23 @@ public static String toURI(FileObject file) {
7172
return file.toURI().toString().replace("file:/", "file:///");
7273
}
7374

75+
public static String uriReplaceFilename(String inputUriString, String filename) {
76+
try {
77+
URI inputUri = URI.create(inputUriString);
78+
URI newUri = inputUri.resolve(new URI(null, null, filename, null));
79+
if ("file".equals(newUri.getScheme())) {
80+
// By default the java URI routines drop empty hostnames from
81+
// file URIs. Normalize this to the empty hostname. See also
82+
// #toURI
83+
return new URI("file", "", newUri.getPath(), null).toString();
84+
} else {
85+
return newUri.toString();
86+
}
87+
} catch (URISyntaxException ex) {
88+
throw new IllegalArgumentException(ex);
89+
}
90+
}
91+
7492
public static Position createPosition(Document doc, int offset) throws BadLocationException {
7593
return new Position(LineDocumentUtils.getLineIndex((LineDocument) doc, offset),
7694
offset - LineDocumentUtils.getLineStart((LineDocument) doc, offset));
@@ -137,7 +155,7 @@ public static void applyWorkspaceEdit(WorkspaceEdit edit) {
137155
private static void applyEdits(String uri, List<TextEdit> edits) {
138156
try {
139157
FileObject file = URLMapper.findFileObject(new URI(uri).toURL());
140-
EditorCookie ec = file.getLookup().lookup(EditorCookie.class);
158+
EditorCookie ec = lookupForFile(file, EditorCookie.class);
141159
Document doc = ec != null ? ec.openDocument() : null;
142160
if (doc == null) {
143161
return ;
@@ -274,7 +292,7 @@ public static void open(String targetUri, Range targetRange) {
274292
FileObject targetFile = fromURI(targetUri);
275293

276294
if (targetFile != null) {
277-
LineCookie lc = targetFile.getLookup().lookup(LineCookie.class);
295+
LineCookie lc = lookupForFile(targetFile, LineCookie.class);
278296

279297
//TODO: expecting lc != null!
280298

@@ -288,6 +306,25 @@ public static void open(String targetUri, Range targetRange) {
288306
}
289307
}
290308

309+
public static <T> T lookupForFile(FileObject targetFile, Class<T> clazz) {
310+
if(targetFile == null) {
311+
return null;
312+
}
313+
T lc = null;
314+
try {
315+
if (lc == null) {
316+
DataObject dataObject = DataObject.find(targetFile);
317+
lc = dataObject.getLookup().lookup(clazz);
318+
}
319+
} catch (DataObjectNotFoundException ex) {
320+
// Ignore
321+
}
322+
if (lc == null) {
323+
lc = targetFile.getLookup().lookup(clazz);
324+
}
325+
return lc;
326+
}
327+
291328
private static final Comparator<TextEdit> rangeReverseSort = (s1, s2) -> {
292329
int l1 = s1.getRange().getEnd().getLine();
293330
int l2 = s2.getRange().getEnd().getLine();

ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/FoldManagerImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public void release() {
110110

111111
@Override
112112
public void run(LSPBindings bindings, FileObject file) {
113-
EditorCookie ec = file.getLookup().lookup(EditorCookie.class);
113+
EditorCookie ec = Utils.lookupForFile(file, EditorCookie.class);
114114
Document doc = ec != null ? ec.getDocument() : null;
115115
if (doc == null) {
116116
return;

ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/LanguageClientImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public void notifyProgress(ProgressParams params) {
159159
public void publishDiagnostics(PublishDiagnosticsParams pdp) {
160160
try {
161161
FileObject file = URLMapper.findFileObject(new URI(pdp.getUri()).toURL());
162-
EditorCookie ec = file != null ? file.getLookup().lookup(EditorCookie.class) : null;
162+
EditorCookie ec = Utils.lookupForFile(file, EditorCookie.class);
163163
Document doc = ec != null ? ec.getDocument() : null;
164164
if (doc == null) {
165165
return ; //ignore...

ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/LspStructureNavigatorPanel.java

+4-12
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,24 @@
1818
*/
1919
package org.netbeans.modules.lsp.client.bindings;
2020

21-
import java.awt.BorderLayout;
22-
import java.awt.EventQueue;
2321
import java.util.Collection;
2422
import java.util.logging.Level;
25-
import java.util.logging.Logger;
2623
import javax.swing.Action;
27-
import javax.swing.JComponent;
28-
import javax.swing.JPanel;
2924
import javax.swing.text.StyledDocument;
3025
import org.netbeans.api.actions.Openable;
3126
import org.netbeans.api.editor.mimelookup.MimeLookup;
3227
import org.netbeans.api.lsp.StructureElement;
28+
import org.netbeans.modules.lsp.client.Utils;
3329
import org.netbeans.spi.lsp.StructureProvider;
34-
import org.netbeans.spi.navigator.NavigatorPanel;
3530
import org.openide.awt.Actions;
3631
import org.openide.cookies.EditorCookie;
3732
import org.openide.cookies.LineCookie;
38-
import org.openide.explorer.ExplorerManager;
39-
import org.openide.explorer.view.BeanTreeView;
4033
import org.openide.filesystems.FileObject;
4134
import org.openide.nodes.AbstractNode;
4235
import org.openide.nodes.Children;
4336
import org.openide.nodes.Node;
4437
import org.openide.text.Line;
4538
import org.openide.text.NbDocument;
46-
import org.openide.util.Lookup;
4739
import org.openide.util.NbBundle;
4840
import org.openide.util.RequestProcessor;
4941
import org.openide.util.lookup.AbstractLookup;
@@ -75,7 +67,7 @@ void removeBackgroundTask(FileObject fo) {
7567

7668
void refreshStructure(FileObject fo) {
7769
LOG.log(Level.INFO, "panelActivated: {0}", fo);
78-
EditorCookie ec = fo.getLookup().lookup(EditorCookie.class);
70+
EditorCookie ec = Utils.lookupForFile(fo, EditorCookie.class);
7971
if (ec != null) {
8072
StyledDocument doc = ec.getDocument();
8173
if (doc != null) {
@@ -130,12 +122,12 @@ private StructureElementNode(StructureElement e, FileObject fo, InstanceContent
130122
setShortDescription(e.getDetail());
131123
setIconBaseWithExtension(Icons.getSymbolIconBase(e.getKind()));
132124
Openable open = () -> {
133-
EditorCookie ec = fo.getLookup().lookup(EditorCookie.class);
125+
EditorCookie ec = Utils.lookupForFile(fo, EditorCookie.class);
134126
if (ec != null) {
135127
StyledDocument doc = ec.getDocument();
136128
if (doc != null) {
137129
int lineNumber = NbDocument.findLineNumber(doc, e.getSelectionStartOffset());
138-
LineCookie lines = fo.getLookup().lookup(LineCookie.class);
130+
LineCookie lines = Utils.lookupForFile(fo, LineCookie.class);
139131
if (lines != null) {
140132
Line at = lines.getLineSet().getOriginal(lineNumber);
141133
if (at != null) {

0 commit comments

Comments
 (0)