Trying to make jumpies work in lsp4e
This works 'in theory'. Alas, lsp4e doesn't seem to execute commands from a completion items. So cursor doesn't move. Also filtering in lsp4e is still bonkers too.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.ls.eclipse.commons;
|
||||
|
||||
import org.eclipse.lsp4j.Position;
|
||||
|
||||
public class CursorMovement {
|
||||
private String uri;
|
||||
private Position position;
|
||||
|
||||
public CursorMovement() {
|
||||
}
|
||||
|
||||
public CursorMovement(String uri, Position position) {
|
||||
this.uri = uri;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,8 +30,8 @@ public interface STS4LanguageClient extends LanguageClient {
|
||||
@JsonNotification("sts/progress")
|
||||
void progress(ProgressParams progressEvent);
|
||||
|
||||
// TODO: @JsonRequest("sts/moveCursor")
|
||||
// CompletableFuture<Object> moveCursor(CursorMovement cursorMovement);
|
||||
@JsonRequest("sts/moveCursor")
|
||||
CompletableFuture<Object> moveCursor(CursorMovement cursorMovement);
|
||||
|
||||
@JsonRequest("sts/addClasspathListener")
|
||||
CompletableFuture<Object> addClasspathListener(ClasspathListenerParams params);
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
@@ -25,10 +26,12 @@ import org.eclipse.jface.action.IStatusLineManager;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.TextSelection;
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelExtension;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
import org.eclipse.jface.viewers.ISelectionProvider;
|
||||
import org.eclipse.lsp4e.LSPEclipseUtils;
|
||||
import org.eclipse.lsp4e.LanguageClientImpl;
|
||||
import org.eclipse.lsp4e.LanguageServiceAccessor;
|
||||
@@ -224,4 +227,32 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La
|
||||
return CompletableFuture.completedFuture(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Object> moveCursor(CursorMovement cursorMovement) {
|
||||
//WARNING: this code never ran. It is meant to be called by server 'moveCursor' command
|
||||
// when appplying jumpy completions. But lsp4e doesn't execute commands from completions
|
||||
// because they haven't implemented support for that part of the protocol yet.
|
||||
Throwable problem = null;
|
||||
for (Pair<IDocument, AbstractTextEditor> editorAndDoc : StsLspEclipseUtil.getTextEditorsForUri(cursorMovement.getUri())) {
|
||||
try {
|
||||
AbstractTextEditor editor = editorAndDoc.getRight();
|
||||
IDocument doc = editorAndDoc.getLeft();
|
||||
int cursor = LSPEclipseUtils.toOffset(cursorMovement.getPosition(), doc);
|
||||
moveCursor(editor, cursor);
|
||||
} catch (Exception e) {
|
||||
if (problem==null) {
|
||||
problem = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return problem == null
|
||||
? CompletableFuture.completedFuture("ok")
|
||||
: Futures.fail(problem);
|
||||
}
|
||||
|
||||
private void moveCursor(AbstractTextEditor editor, int cursor) {
|
||||
ISelectionProvider sp = editor.getSelectionProvider();
|
||||
sp.setSelection(new TextSelection(cursor, 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.ls.eclipse.commons;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.lsp4e.LSPEclipseUtils;
|
||||
import org.eclipse.lsp4e.LanguageServiceAccessor;
|
||||
import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
|
||||
import org.eclipse.ui.IEditorInput;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IEditorReference;
|
||||
import org.eclipse.ui.IWorkbenchPage;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PartInitException;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.texteditor.AbstractTextEditor;
|
||||
|
||||
public class StsLspEclipseUtil {
|
||||
|
||||
public static List<Pair<IDocument, AbstractTextEditor>> getTextEditorsForUri(String uri) {
|
||||
List<Pair<IDocument, AbstractTextEditor>> editors = new ArrayList<>(1); //Typical expectation is just one editor.
|
||||
for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
|
||||
for (IWorkbenchPage page : window.getPages()) {
|
||||
for (IEditorReference editor : page.getEditorReferences()) {
|
||||
try {
|
||||
IEditorInput input = editor.getEditorInput();
|
||||
if (input!=null) {
|
||||
IDocument doc = LSPEclipseUtils.getDocument(input);
|
||||
Collection<LSPDocumentInfo> infos = LanguageServiceAccessor.getLSPDocumentInfosFor(doc, (x) -> true);
|
||||
for (LSPDocumentInfo lspDoc : infos) {
|
||||
if (uri.equals(lspDoc.getFileUri().toString())) {
|
||||
boolean restore = false;
|
||||
IEditorPart editorPart = editor.getEditor(restore );
|
||||
if (editorPart instanceof AbstractTextEditor) {
|
||||
editors.add(Pair.of(doc, (AbstractTextEditor) editorPart));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (PartInitException e) {
|
||||
LanguageServerCommonsActivator.logError(e, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return editors;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import org.eclipse.lsp4j.services.LanguageClient;
|
||||
import org.eclipse.lsp4j.services.LanguageClientAware;
|
||||
import org.eclipse.lsp4j.services.LanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LoggingFormat;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
|
||||
@@ -60,6 +61,7 @@ public abstract class LaunguageServerApp {
|
||||
private static final int SERVER_STANDALONE_PORT = 5007;
|
||||
|
||||
public static void start(String name, Provider<SimpleLanguageServer> languageServerFactory) throws IOException, InterruptedException {
|
||||
Log.info("ClientType = "+LspClient.currentClient());
|
||||
System.setProperty(STS4_LANGUAGESERVER_NAME, name); //makes it easy to recognize language server processes.
|
||||
LaunguageServerApp app = new LaunguageServerApp() {
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits.Direction;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits.OffsetTransformer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient.Client;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
@@ -135,7 +137,7 @@ public class LspCompletionInterpreter implements IDocumentState {
|
||||
if (afterEdit!=null) additionalEdits.add(afterEdit);
|
||||
item.setAdditionalTextEdits(additionalEdits.build());
|
||||
|
||||
if (mainEdit!=null && mainEdit.getNewText().equals("")) {
|
||||
if (LspClient.currentClient()==Client.VSCODE && mainEdit!=null && mainEdit.getNewText().equals("")) {
|
||||
//Vscode handles this poorly and adds 'junk' instead.
|
||||
mainEdit.setNewText(" "); // Adding a space. It is still junk but it is at least not immediately visible.
|
||||
}
|
||||
|
||||
@@ -155,6 +155,16 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
|
||||
}
|
||||
}
|
||||
list.setItems(items);
|
||||
System.err.println(">>> completions [isInconplete = "+list.isIncomplete()+"]");
|
||||
for (CompletionItem item : items) {
|
||||
System.err.println(
|
||||
"lbl = '"+item.getLabel()+"' " +
|
||||
"sort = '"+item.getSortText()+"' " +
|
||||
"filt = '"+item.getFilterText()+"' " +
|
||||
"newText = '"+item.getTextEdit().getNewText()+"'"
|
||||
);
|
||||
}
|
||||
System.err.println("<<< completions");
|
||||
return list;
|
||||
})
|
||||
.subscribeOn(Schedulers.elastic()); //!!! without this the mono will just be computed on the same thread that calls it.
|
||||
|
||||
@@ -1450,59 +1450,64 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest {
|
||||
}
|
||||
|
||||
@Test public void testJumpyInsertion() throws Exception {
|
||||
String[] names = {"foo", "nested", "bar"};
|
||||
int levels = 4;
|
||||
generateNestedProperties(levels, names, "");
|
||||
//We care more about eclipse for this test case because it fails for vscode
|
||||
// because we have to add some extra in vscode as a workaround for this bug:
|
||||
// https://github.com/Microsoft/vscode-languageserver-node/issues/361
|
||||
withSystemProperty("sts.lsp.client", "eclipse", () -> {
|
||||
String[] names = {"foo", "nested", "bar"};
|
||||
int levels = 4;
|
||||
generateNestedProperties(levels, names, "");
|
||||
|
||||
assertCompletion(
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
"other:\n" +
|
||||
"foo.nested.bar.b<*>"
|
||||
,
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
" bar: <*>\n" +
|
||||
"other:"
|
||||
);
|
||||
assertCompletion(
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
"other:\n" +
|
||||
"foo.nested.bar.b<*>"
|
||||
,
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
" bar: <*>\n" +
|
||||
"other:"
|
||||
);
|
||||
|
||||
assertCompletion(
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
"other:\n" +
|
||||
"foo.nested.nested.b<*>"
|
||||
,
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar: <*>\n"+
|
||||
"other:"
|
||||
);
|
||||
assertCompletion(
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
"other:\n" +
|
||||
"foo.nested.nested.b<*>"
|
||||
,
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar: <*>\n"+
|
||||
"other:"
|
||||
);
|
||||
|
||||
assertCompletion(
|
||||
"foo.nested.nested.b<*>\n" +
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
"other:"
|
||||
,
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar: <*>\n"+
|
||||
"other:"
|
||||
);
|
||||
assertCompletion(
|
||||
"foo.nested.nested.b<*>\n" +
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
"other:"
|
||||
,
|
||||
"foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar:\n" +
|
||||
" foo:\n" +
|
||||
" nested:\n" +
|
||||
" bar: <*>\n"+
|
||||
"other:"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Test public void testBooleanValueCompletion() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user