diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java index f9b7ba00f..bbe8c4399 100644 --- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java @@ -92,6 +92,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer { documents.onDidChangeContent(params -> { TextDocument doc = params.getDocument(); validateWith(doc.getId(), reconcileEngine); + highlighWith(doc, new WordHighlighter(this, "foo")); }); ICompletionEngine bootCompletionEngine = createCompletionEngine(javaProjectFinder, indexProvider); diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/WordHighlighter.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/WordHighlighter.java new file mode 100644 index 000000000..c089d78ff --- /dev/null +++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/WordHighlighter.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2017 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.ide.vscode.boot.java; + +import java.util.List; +import java.util.function.Function; + +import org.eclipse.lsp4j.Range; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.languageserver.util.TextDocumentContentChange; +import org.springframework.ide.vscode.commons.util.BadLocationException; +import org.springframework.ide.vscode.commons.util.Log; +import org.springframework.ide.vscode.commons.util.text.TextDocument; + +import com.google.common.collect.ImmutableList; + +/** + * Sample implementation of a 'highlighter' that can be used with {@link SimpleLanguageServer}.highlightWith. + *

+ * Finds every occurence of a given word and highlights it. + * + * @author Kris De Volder + */ +public class WordHighlighter implements Function> { + + private final SimpleLanguageServer server; + private final String word; + + public WordHighlighter(SimpleLanguageServer server, String word) { + super(); + this.server = server; + this.word = word; + } + + @Override + public List apply(TextDocument doc) { + String text = doc.get(); + int wordStart = text.indexOf(word); + ImmutableList.Builder highlights = ImmutableList.builder(); + while (wordStart>=0) { + try { + highlights.add(doc.toRange(wordStart, word.length())); + } catch (BadLocationException e) { + Log.log(e); + } + wordStart = text.indexOf(word, wordStart+word.length()); + } + return highlights.build(); + } +} diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/HighlightParams.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/HighlightParams.java new file mode 100644 index 000000000..bf812f99a --- /dev/null +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/HighlightParams.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2017 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.ide.vscode.commons.languageserver; + +import java.util.List; + +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.TextDocumentIdentifier; + +public class HighlightParams { + + private TextDocumentIdentifier doc; + private List ranges; + + public HighlightParams() { + } + + public HighlightParams(TextDocumentIdentifier doc, List ranges) { + super(); + this.doc = doc; + this.ranges = ranges; + } + public TextDocumentIdentifier getDoc() { + return doc; + } + public void setDoc(TextDocumentIdentifier doc) { + this.doc = doc; + } + public List getRanges() { + return ranges; + } + public void setRanges(List ranges) { + this.ranges = ranges; + } + +} diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/STS4LanguageClient.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/STS4LanguageClient.java index 4830dff83..2d7892023 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/STS4LanguageClient.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/STS4LanguageClient.java @@ -25,6 +25,9 @@ import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixEd */ public interface STS4LanguageClient extends LanguageClient { + @JsonNotification("sts/highlight") + void highlight(HighlightParams highlights); + @JsonNotification("sts/progress") void progress(ProgressParams progressEvent); diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java index 3b7f3bfa9..4c7fd0cd3 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleLanguageServer.java @@ -17,6 +17,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import org.eclipse.lsp4j.ApplyWorkspaceEditParams; import org.eclipse.lsp4j.ApplyWorkspaceEditResponse; @@ -37,6 +38,7 @@ import org.eclipse.lsp4j.TextDocumentSyncKind; 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.HighlightParams; import org.springframework.ide.vscode.commons.languageserver.ProgressParams; import org.springframework.ide.vscode.commons.languageserver.ProgressService; import org.springframework.ide.vscode.commons.languageserver.STS4LanguageClient; @@ -447,7 +449,7 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl } } - public LanguageClient getClient() { + public STS4LanguageClient getClient() { return client; } @@ -460,5 +462,13 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl testListener = languageServerTestListener; } + protected void highlighWith(TextDocument doc, Function> wordHighlighter) { + List highlights = wordHighlighter.apply(doc); + if (highlights==null) { + highlights = ImmutableList.of(); + } + client.highlight(new HighlightParams(doc.getId(), highlights)); + } + } diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java index 07830f3b0..7ba98f330 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/LanguageServerHarness.java @@ -75,6 +75,7 @@ import org.eclipse.lsp4j.WorkspaceClientCapabilities; import org.eclipse.lsp4j.WorkspaceEdit; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.LanguageClientAware; +import org.springframework.ide.vscode.commons.languageserver.HighlightParams; import org.springframework.ide.vscode.commons.languageserver.ProgressParams; import org.springframework.ide.vscode.commons.languageserver.STS4LanguageClient; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; @@ -232,7 +233,6 @@ public class LanguageServerHarness { @Override public void progress(ProgressParams progressEvent) { // TODO Auto-generated method stub - } @Override @@ -245,6 +245,11 @@ public class LanguageServerHarness { } return CompletableFuture.completedFuture(new ApplyWorkspaceEditResponse(false)); } + + @Override + public void highlight(HighlightParams highlights) { + // TODO Auto-generated method stub + } }); } diff --git a/vscode-extensions/commons-vscode/icons/boot-icon.png b/vscode-extensions/commons-vscode/icons/boot-icon.png new file mode 100644 index 000000000..de88ef0d5 Binary files /dev/null and b/vscode-extensions/commons-vscode/icons/boot-icon.png differ diff --git a/vscode-extensions/commons-vscode/package.json b/vscode-extensions/commons-vscode/package.json index dbab4b1f0..ce13187be 100644 --- a/vscode-extensions/commons-vscode/package.json +++ b/vscode-extensions/commons-vscode/package.json @@ -14,7 +14,7 @@ "" ], "files": [ - "lib" + "lib", "icons" ], "main": "lib/index.js", "typings": "lib/index.d.ts", diff --git a/vscode-extensions/commons-vscode/src/highlight-service.ts b/vscode-extensions/commons-vscode/src/highlight-service.ts new file mode 100644 index 000000000..f31c5888d --- /dev/null +++ b/vscode-extensions/commons-vscode/src/highlight-service.ts @@ -0,0 +1,55 @@ +import {TextDocumentIdentifier, Position, Range} from 'vscode-languageclient' +import * as VSCode from 'vscode'; +import * as path from "path"; + +function toDecoration(rng : Range) : VSCode.Range { + return new VSCode.Range(toPosition(rng.start), toPosition(rng.end)); +} + +function toPosition(p : Position) : VSCode.Position { + return new VSCode.Position(p.line, p.character); +} + +export interface HighlightParams { + doc: TextDocumentIdentifier + ranges: Range[] +} + +export class HighlightService { + + DECORATION : VSCode.TextEditorDecorationType; + + highlights : Map; + + dispose() { + this.DECORATION.dispose(); + } + + constructor() { + this.DECORATION = VSCode.window.createTextEditorDecorationType({ + // textDecoration: "underline", + gutterIconPath: path.resolve(__dirname, "../icons/boot-icon.png"), + gutterIconSize: "contain", + outline: "#32BA56 dotted thin" + }); + this.highlights = new Map(); + } + + handle(params : HighlightParams) : void { + this.highlights.set(params.doc.uri, params.ranges); + this.refresh(params.doc.uri); + } + + refresh(uri : String) { + let editor = VSCode.window.activeTextEditor; + let activeUri = editor.document.uri.toString(); + console.log("Refreshing uri :" + uri); + console.log(" active editor uri :" + editor.document.uri); + if (uri===activeUri) { + //We only update highlights in the active editor for now + let highlights : Range[] = this.highlights.get(uri) || []; + let decorations = highlights.map(hl => toDecoration(hl)); + editor.setDecorations(this.DECORATION, decorations); + } + } +} \ No newline at end of file diff --git a/vscode-extensions/commons-vscode/src/launch-util.ts b/vscode-extensions/commons-vscode/src/launch-util.ts index a465ad859..315500148 100644 --- a/vscode-extensions/commons-vscode/src/launch-util.ts +++ b/vscode-extensions/commons-vscode/src/launch-util.ts @@ -10,11 +10,12 @@ import * as FS from 'fs'; import PortFinder = require('portfinder'); import * as Net from 'net'; import * as ChildProcess from 'child_process'; -import { RequestType, LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, StreamInfo } from 'vscode-languageclient'; +import { TextDocumentIdentifier, RequestType, LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, StreamInfo, Range } from 'vscode-languageclient'; import { TextDocument, OutputChannel, Disposable, window } from 'vscode'; import { Trace, NotificationType } from 'vscode-jsonrpc'; import * as P2C from 'vscode-languageclient/lib/protocolConverter'; import {WorkspaceEdit, Position} from 'vscode-languageserver-types'; +import {HighlightService, HighlightParams} from './highlight-service'; let p2c = P2C.createConverter(); @@ -145,17 +146,23 @@ function setupLanguageClient(context: VSCode.ExtensionContext, createServer: Ser } let progressNotification = new NotificationType("sts/progress"); + let highlightNotification = new NotificationType("sts/highlight"); let moveCursorRequest = new RequestType("sts/moveCursor"); let disposable = client.start(); let progressService = new ProgressService(); + let highlightService = new HighlightService(); context.subscriptions.push(disposable); context.subscriptions.push(progressService); + context.subscriptions.push(highlightService); return client.onReady().then(() => { client.onNotification(progressNotification, (params: ProgressParams) => { progressService.handle(params); }); + client.onNotification(highlightNotification, (params: HighlightParams) => { + highlightService.handle(params); + }); client.onRequest(moveCursorRequest, (params: MoveCursorParams) => { let editors = VSCode.window.visibleTextEditors; for (let editor of editors) {