You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by en...@apache.org on 2021/07/14 22:15:56 UTC
[netbeans] branch master updated: Visually differentiate lines with
DWARF information during native image debugging.
This is an automated email from the ASF dual-hosted git repository.
entl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new 9cd0dee Visually differentiate lines with DWARF information during native image debugging.
9cd0dee is described below
commit 9cd0dee3499cd77c86db6ec6c864d8e7eec0a107
Author: Martin Entlicher <ma...@oracle.com>
AuthorDate: Wed Jun 30 09:49:01 2021 +0200
Visually differentiate lines with DWARF information during native image debugging.
---
cpplite/cpplite.debugger/nbproject/project.xml | 2 +-
.../modules/cpplite/debugger/CPPLiteDebugger.java | 139 +++++++
.../debugger/ni/NIDebuggerProviderImpl.java | 20 +
ide/nativeimage.api/manifest.mf | 2 +-
.../netbeans/modules/nativeimage/api/Location.java | 140 +++++++
.../modules/nativeimage/api/SourceInfo.java | 138 +++++++
.../netbeans/modules/nativeimage/api/Symbol.java | 131 +++++++
.../modules/nativeimage/api/debug/NIDebugger.java | 48 +++
.../nativeimage/spi/debug/NIDebuggerProvider.java | 26 +-
java/java.lsp.server/nbproject/project.xml | 2 +-
.../modules/java/lsp/server/LspServerState.java | 6 +
.../server/debugging/launch/NbLaunchDelegate.java | 9 +
.../server/debugging/ni/NILocationVisualizer.java | 411 +++++++++++++++++++++
.../java/lsp/server/files/OpenedDocuments.java | 98 +++++
.../server/protocol/DecorationRenderOptions.java | 313 ++++++++++++++++
.../lsp/server/protocol/NbCodeClientWrapper.java | 15 +
.../lsp/server/protocol/NbCodeLanguageClient.java | 25 ++
.../java/lsp/server/protocol/NbLspServer.java | 5 +
.../lsp/server/protocol/OverviewRulerLane.java | 53 +++
.../modules/java/lsp/server/protocol/Server.java | 26 ++
.../protocol/SetTextEditorDecorationParams.java | 139 +++++++
.../server/protocol/TextDocumentServiceImpl.java | 30 +-
.../ThemableDecorationAttachmentRenderOptions.java | 229 ++++++++++++
.../protocol/ThemableDecorationRenderOptions.java | 383 +++++++++++++++++++
.../java/lsp/server/protocol/ThemeColor.java | 81 ++++
.../server/progress/TestProgressHandlerTest.java | 18 +
.../lsp/server/protocol/OverviewRulerLaneTest.java | 38 ++
.../java/lsp/server/protocol/ServerTest.java | 120 ++++++
java/java.lsp.server/vscode/src/extension.ts | 31 +-
java/java.lsp.server/vscode/src/protocol.ts | 25 +-
.../nbproject/project.xml | 2 +-
.../debugger/displayer/JavaFrameDisplayer.java | 3 +
32 files changed, 2683 insertions(+), 25 deletions(-)
diff --git a/cpplite/cpplite.debugger/nbproject/project.xml b/cpplite/cpplite.debugger/nbproject/project.xml
index 48ff741..380bbb0 100644
--- a/cpplite/cpplite.debugger/nbproject/project.xml
+++ b/cpplite/cpplite.debugger/nbproject/project.xml
@@ -66,7 +66,7 @@
<compile-dependency/>
<run-dependency>
<release-version>0</release-version>
- <specification-version>0.1</specification-version>
+ <specification-version>0.2</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java
index 0c41c83..07c78f1 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/CPPLiteDebugger.java
@@ -29,7 +29,9 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.EventListener;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -59,6 +61,9 @@ import org.netbeans.modules.cpplite.debugger.breakpoints.CPPLiteBreakpoint;
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory;
import org.netbeans.modules.nativeexecution.api.pty.Pty;
import org.netbeans.modules.nativeexecution.api.pty.PtySupport;
+import org.netbeans.modules.nativeimage.api.Location;
+import org.netbeans.modules.nativeimage.api.SourceInfo;
+import org.netbeans.modules.nativeimage.api.Symbol;
import org.netbeans.spi.debugger.ContextProvider;
import org.netbeans.spi.debugger.DebuggerEngineProvider;
import org.netbeans.spi.debugger.SessionProvider;
@@ -421,6 +426,140 @@ public final class CPPLiteDebugger {
return versionRecord.command().getConsoleStream();
}
+ public List<Location> listLocations(String filePath) {
+ MIRecord lines;
+ try {
+ lines = sendAndGet("-symbol-list-lines " + filePath);
+ } catch (InterruptedException ex) {
+ return null;
+ }
+ MIValue linesValue = lines.results().valueOf("lines");
+ if (linesValue instanceof MITList) {
+ MITList lineList = (MITList) linesValue;
+ int size = lineList.size();
+ List<Location> locations = new ArrayList<>(size);
+ Location.Builder locationBuilder = Location.newBuilder();
+ for (MITListItem item : lineList) {
+ if (item instanceof MITList) {
+ MITList il = (MITList) item;
+ String pcs = il.getConstValue("pc", null);
+ if (pcs != null) {
+ long pc;
+ if (pcs.startsWith("0x")) {
+ pcs = pcs.substring(2);
+ pc = Long.parseUnsignedLong(pcs, 16);
+ } else {
+ pc = Long.parseUnsignedLong(pcs);
+ }
+ locationBuilder.pc(pc);
+ } else {
+ locationBuilder.pc(0);
+ }
+ String lineStr = il.getConstValue("line", null);
+ if (lineStr != null) {
+ locationBuilder.line(Integer.parseInt(lineStr));
+ } else {
+ locationBuilder.line(0);
+ }
+ locations.add(locationBuilder.build());
+ }
+ }
+ return locations;
+ } else {
+ return null;
+ }
+ }
+
+ public Map<SourceInfo, List<Symbol>> listFunctions(String name, boolean includeNondebug, int maxResults) {
+ StringBuilder command = new StringBuilder("-symbol-info-functions");
+ if (name != null) {
+ command.append(" --name ");
+ command.append(name);
+ }
+ if (includeNondebug) {
+ command.append(" --include-nondebug");
+ }
+ if (maxResults > 0) {
+ command.append(" --max-results ");
+ command.append(maxResults);
+ }
+ return listSymbols(command.toString());
+ }
+
+ public Map<SourceInfo, List<Symbol>> listVariables(String name, boolean includeNondebug, int maxResults) {
+ StringBuilder command = new StringBuilder("-symbol-info-variables");
+ if (name != null) {
+ command.append(" --name ");
+ command.append(name);
+ }
+ if (includeNondebug) {
+ command.append(" --include-nondebug");
+ }
+ if (maxResults > 0) {
+ command.append(" --max-results ");
+ command.append(maxResults);
+ }
+ return listSymbols(command.toString());
+ }
+
+ private Map<SourceInfo, List<Symbol>> listSymbols(String command) {
+ MIRecord result;
+ try {
+ result = sendAndGet(command);
+ } catch (InterruptedException ex) {
+ return null;
+ }
+ MIValue allSymbolsValue = result.results().valueOf("symbols");
+ if (allSymbolsValue instanceof MITList) {
+ MITList allSymbolsList = (MITList) allSymbolsValue;
+ if (allSymbolsList.size() == 0) {
+ return Collections.emptyMap();
+ }
+ MIValue debugValue = allSymbolsList.valueOf("debug");
+ if (debugValue instanceof MITList) {
+ MITList debugList = (MITList) debugValue;
+ int size = debugList.size();
+ Map<SourceInfo, List<Symbol>> sourceSymbols = new LinkedHashMap<>(size);
+ for (MITListItem debugItem : debugList) {
+ if (debugItem instanceof MITList) {
+ MITList sourceWithSymbols = (MITList) debugItem;
+ SourceInfo.Builder sourceBuilder = SourceInfo.newBuilder();
+ String filename = sourceWithSymbols.getConstValue("filename", null);
+ String fullname = sourceWithSymbols.getConstValue("fullname", null);
+ sourceBuilder.fileName(filename);
+ sourceBuilder.fullName(fullname);
+ SourceInfo source = sourceBuilder.build();
+ MIValue symbolsValue = sourceWithSymbols.valueOf("symbols");
+ if (symbolsValue instanceof MITList) {
+ MITList symbolsList = (MITList) symbolsValue;
+ int symbolsSize = symbolsList.size();
+ List<Symbol> symbols = new ArrayList<>(symbolsSize);
+ for (MITListItem symbolItem : symbolsList) {
+ if (symbolItem instanceof MITList) {
+ MITList symbolList = (MITList) symbolItem;
+ String name = symbolList.getConstValue("name");
+ String type = symbolList.getConstValue("type", null);
+ String description = symbolList.getConstValue("description", null);
+ Symbol.Builder symbolBuilder = Symbol.newBuilder();
+ symbolBuilder.name(name);
+ symbolBuilder.type(type);
+ symbolBuilder.description(description);
+ symbols.add(symbolBuilder.build());
+ }
+ }
+ sourceSymbols.put(source, symbols);
+ }
+ }
+ }
+ return Collections.unmodifiableMap(sourceSymbols);
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
ContextProvider getContextProvider() {
return contextProvider;
}
diff --git a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerProviderImpl.java b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerProviderImpl.java
index b136c33..4c75cb8 100644
--- a/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerProviderImpl.java
+++ b/cpplite/cpplite.debugger/src/org/netbeans/modules/cpplite/debugger/ni/NIDebuggerProviderImpl.java
@@ -20,6 +20,7 @@ package org.netbeans.modules.cpplite.debugger.ni;
import java.io.File;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.function.Consumer;
@@ -32,6 +33,9 @@ import org.netbeans.modules.cpplite.debugger.CPPFrame;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebugger;
import org.netbeans.modules.cpplite.debugger.CPPLiteDebuggerConfig;
import org.netbeans.modules.cpplite.debugger.CPPThread;
+import org.netbeans.modules.nativeimage.api.Location;
+import org.netbeans.modules.nativeimage.api.SourceInfo;
+import org.netbeans.modules.nativeimage.api.Symbol;
import org.netbeans.modules.nativeimage.api.debug.EvaluateException;
import org.netbeans.modules.nativeimage.api.debug.NIFrame;
import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
@@ -180,4 +184,20 @@ public class NIDebuggerProviderImpl implements NIDebuggerProvider {
public String getVersion() {
return debugger.getVersion();
}
+
+ @Override
+ public List<Location> listLocations(String filePath) {
+ return debugger.listLocations(filePath);
+ }
+
+ @Override
+ public Map<SourceInfo, List<Symbol>> listFunctions(String name, boolean includeNondebug, int maxResults) {
+ return debugger.listFunctions(name, includeNondebug, maxResults);
+ }
+
+ @Override
+ public Map<SourceInfo, List<Symbol>> listVariables(String name, boolean includeNondebug, int maxResults) {
+ return debugger.listVariables(name, includeNondebug, maxResults);
+ }
+
}
diff --git a/ide/nativeimage.api/manifest.mf b/ide/nativeimage.api/manifest.mf
index fdfa01c..bad1b2a 100644
--- a/ide/nativeimage.api/manifest.mf
+++ b/ide/nativeimage.api/manifest.mf
@@ -2,5 +2,5 @@ Manifest-Version: 1.0
AutoUpdate-Show-In-Client: false
OpenIDE-Module: org.netbeans.modules.nativeimage.api/0
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/nativeimage/api/Bundle.properties
-OpenIDE-Module-Specification-Version: 0.1
+OpenIDE-Module-Specification-Version: 0.2
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/Location.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/Location.java
new file mode 100644
index 0000000..4771117
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/Location.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.api;
+
+/**
+ * A location in the debuggee program.
+ *
+ * @since 0.2
+ */
+public final class Location {
+
+ private final long pc;
+ private final int line;
+ private final int column;
+
+ private Location(long pc, int line, int column) {
+ this.pc = pc;
+ this.line = line;
+ this.column = column;
+ }
+
+ /**
+ * Get the program counter position.
+ *
+ * @since 0.2
+ */
+ public long getPC() {
+ return pc;
+ }
+
+ /**
+ * Get 1-based line number. Returns 0 when the line is not defined.
+ *
+ * @since 0.2
+ */
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * Get 1-based column number. Returns 0 when the column is not defined.
+ *
+ * @since 0.2
+ */
+ public int getColumn() {
+ return column;
+ }
+
+ /**
+ * Creates a builder to build a new {@link Location}.
+ *
+ * @since 0.2
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ @Override
+ public String toString() {
+ return "Location{" + "pc=" + pc + ", line=" + line + ", column=" + column + '}';
+ }
+
+ /**
+ * Location's builder.
+ *
+ * @since 0.2
+ */
+ public static final class Builder {
+
+ private long pc;
+ private int line;
+ private int column;
+
+ Builder() {}
+
+ /**
+ * Set a program counter location in the native binary.
+ *
+ * @since 0.2
+ */
+ public void pc(long pc) {
+ this.pc = pc;
+ }
+
+ /**
+ * Set an 1-based line. The line is treated as unknown when 0.
+ *
+ * @since 0.2
+ */
+ public void line(int line) {
+ if (line < 0) {
+ throw new IllegalArgumentException("Line must not be negative");
+ }
+ this.line = line;
+ }
+
+ /**
+ * Set an 1-based column. The column is treated as unknown when 0.
+ *
+ * @since 0.2
+ */
+ public void column(int column) {
+ if (column < 0) {
+ throw new IllegalArgumentException("Column must not be negative");
+ }
+ this.column = column;
+ }
+
+ /**
+ * Build the {@link Location} object.
+ *
+ * @since 0.2
+ */
+ public Location build() {
+ if (column > 0 && line == 0) {
+ throw new IllegalStateException("Column can not be defined without a line.");
+ }
+ if (line == 0 && pc == 0) {
+ throw new IllegalStateException("No location information is defined.");
+ }
+ return new Location(pc, line, column);
+ }
+ }
+}
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/SourceInfo.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/SourceInfo.java
new file mode 100644
index 0000000..5855e77
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/SourceInfo.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.api;
+
+import java.util.Objects;
+
+/**
+ * A source file information in the debuggee program.
+ *
+ * @since 0.2
+ */
+public final class SourceInfo {
+
+ private final String fileName;
+ private final String fullName;
+
+ private SourceInfo(String fileName, String fullName) {
+ this.fileName = fileName;
+ this.fullName = fullName;
+ }
+
+ /**
+ * Get the file name, or <code>null</code> when unknown. May return a relative path.
+ *
+ * @since 0.2
+ */
+ public String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Get the full file name, or <code>null</code> when unknown. Returns an absolute path, if any.
+ *
+ * @since 0.2
+ */
+ public String getFullName() {
+ return fullName;
+ }
+
+ /**
+ * Creates a builder to build a new {@link SourceInfo}.
+ *
+ * @since 0.2
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 17 * hash + Objects.hashCode(this.fileName);
+ hash = 17 * hash + Objects.hashCode(this.fullName);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final SourceInfo other = (SourceInfo) obj;
+ if (!Objects.equals(this.fileName, other.fileName)) {
+ return false;
+ }
+ if (!Objects.equals(this.fullName, other.fullName)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "SourceInfo{" + "fileName=" + fileName + ", fullName=" + fullName + '}';
+ }
+
+ /**
+ * Symbol's builder.
+ *
+ * @since 0.2
+ */
+ public static final class Builder {
+
+ private String fileName;
+ private String fullName;
+
+ Builder() {}
+
+ /**
+ * Set a file name. It may be a relative path.
+ *
+ * @since 0.2
+ */
+ public void fileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ /**
+ * Set a full file name. It needs to be an absolute path.
+ *
+ * @since 0.2
+ */
+ public void fullName(String fullName) {
+ this.fullName = fullName;
+ }
+
+ /**
+ * Build the {@link Symbol} object.
+ *
+ * @since 0.2
+ */
+ public SourceInfo build() {
+ return new SourceInfo(fileName, fullName);
+ }
+ }
+}
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/Symbol.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/Symbol.java
new file mode 100644
index 0000000..cf18960
--- /dev/null
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/Symbol.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.nativeimage.api;
+
+/**
+ * A symbol in the debuggee program.
+ *
+ * @since 0.2
+ */
+public final class Symbol {
+
+ private final String name;
+ private final String type;
+ private final String description;
+
+ private Symbol(String name, String type, String description) {
+ this.name = name;
+ this.type = type;
+ this.description = description;
+ }
+
+ /**
+ * Get the symbol name. Never <code>null<code>.
+ *
+ * @since 0.2
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the symbol type.
+ *
+ * @since 0.2
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Get the symbol description.
+ *
+ * @since 0.2
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Creates a builder to build a new {@link Symbol}.
+ *
+ * @since 0.2
+ */
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ @Override
+ public String toString() {
+ return "Symbol{" + "name=" + name + ", type=" + type + ", description=" + description + '}';
+ }
+
+ /**
+ * Symbol's builder.
+ *
+ * @since 0.2
+ */
+ public static final class Builder {
+
+ private String name;
+ private String type;
+ private String description;
+
+ Builder() {}
+
+ /**
+ * Set the symbol name. The name must be defined.
+ *
+ * @since 0.2
+ */
+ public void name(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Set the symbol type.
+ *
+ * @since 0.2
+ */
+ public void type(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Set the symbol description.
+ *
+ * @since 0.2
+ */
+ public void description(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Build the {@link Symbol} object.
+ *
+ * @since 0.2
+ */
+ public Symbol build() {
+ if (name == null) {
+ throw new IllegalArgumentException("Name must be defined.");
+ }
+ return new Symbol(name, type, description);
+ }
+ }
+}
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIDebugger.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIDebugger.java
index f980655..b5042c0 100644
--- a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIDebugger.java
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/api/debug/NIDebugger.java
@@ -20,13 +20,18 @@ package org.netbeans.modules.nativeimage.api.debug;
import java.io.File;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
+import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.debugger.Breakpoint;
import org.netbeans.api.debugger.DebuggerEngine;
import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.modules.nativeimage.api.Location;
+import org.netbeans.modules.nativeimage.api.SourceInfo;
+import org.netbeans.modules.nativeimage.api.Symbol;
import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerProvider;
import org.netbeans.modules.nativeimage.spi.debug.NIDebuggerServiceProvider;
import org.netbeans.modules.nativeimage.spi.debug.filters.FrameDisplayer;
@@ -166,6 +171,49 @@ public final class NIDebugger {
}
/**
+ * Get a list of locations for a given file path.
+ *
+ * @param filePath a file path
+ * @return list of locations, or <code>null</code> when there's no location
+ * information about such file.
+ * @since 0.2
+ */
+ @CheckForNull
+ public List<Location> listLocations(String filePath) {
+ return provider.listLocations(filePath);
+ }
+
+ /**
+ * Get functions of a given name.
+ *
+ * @param name a name pattern
+ * @param includeNondebug include also symbols from the symbol table
+ * @param maxResults maximum number of results
+ * @return map of source information and their symbols, or <code>null</code>
+ * when there are no matching symbols.
+ * @since 0.2
+ */
+ @CheckForNull
+ public Map<SourceInfo, List<Symbol>> listFunctions(String name, boolean includeNondebug, int maxResults) {
+ return provider.listFunctions(name, includeNondebug, maxResults);
+ }
+
+ /**
+ * Get variables of a given name.
+ *
+ * @param name a name pattern
+ * @param includeNondebug include also symbols from the symbol table
+ * @param maxResults maximum number of results
+ * @return map of source information and their symbols, or <code>null</code>
+ * when there are no matching symbols.
+ * @since 0.2
+ */
+ @CheckForNull
+ public Map<SourceInfo, List<Symbol>> listVariables(String name, boolean includeNondebug, int maxResults) {
+ return provider.listVariables(name, includeNondebug, maxResults);
+ }
+
+ /**
* A builder that creates a Native Image debugger with optional displayers.
*
* @since 1.0
diff --git a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerProvider.java b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerProvider.java
index c2ff425..8868123 100644
--- a/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerProvider.java
+++ b/ide/nativeimage.api/src/org/netbeans/modules/nativeimage/spi/debug/NIDebuggerProvider.java
@@ -20,12 +20,16 @@ package org.netbeans.modules.nativeimage.spi.debug;
import java.io.File;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
+
import org.netbeans.api.debugger.Breakpoint;
import org.netbeans.api.debugger.DebuggerEngine;
-
import org.netbeans.api.extexecution.ExecutionDescriptor;
+import org.netbeans.modules.nativeimage.api.Location;
+import org.netbeans.modules.nativeimage.api.SourceInfo;
+import org.netbeans.modules.nativeimage.api.Symbol;
import org.netbeans.modules.nativeimage.api.debug.NIFrame;
import org.netbeans.modules.nativeimage.api.debug.NILineBreakpointDescriptor;
import org.netbeans.modules.nativeimage.api.debug.NIVariable;
@@ -120,4 +124,24 @@ public interface NIDebuggerProvider {
* @since 1.0
*/
String getVersion();
+
+ /**
+ * Provide a list of locations for a given file path.
+ *
+ * @param filePath a file path
+ * @return list of locations, or <code>null</code> when there's no location
+ * information about such file.
+ * @since 0.2
+ */
+ default List<Location> listLocations(String filePath) {
+ return null;
+ }
+
+ default Map<SourceInfo, List<Symbol>> listFunctions(String name, boolean includeNondebug, int maxResults) {
+ return null;
+ }
+
+ default Map<SourceInfo, List<Symbol>> listVariables(String name, boolean includeNondebug, int maxResults) {
+ return null;
+ }
}
diff --git a/java/java.lsp.server/nbproject/project.xml b/java/java.lsp.server/nbproject/project.xml
index 4bb0e49..a34b540 100644
--- a/java/java.lsp.server/nbproject/project.xml
+++ b/java/java.lsp.server/nbproject/project.xml
@@ -344,7 +344,7 @@
<compile-dependency/>
<run-dependency>
<release-version>0</release-version>
- <specification-version>0.1</specification-version>
+ <specification-version>0.2</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/LspServerState.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/LspServerState.java
index bb66851..4ad2d08 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/LspServerState.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/LspServerState.java
@@ -23,6 +23,7 @@ import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.netbeans.api.project.Project;
+import org.netbeans.modules.java.lsp.server.files.OpenedDocuments;
import org.openide.filesystems.FileObject;
/**
@@ -73,4 +74,9 @@ public interface LspServerState {
* @return TextDocumentService
*/
public TextDocumentService getTextDocumentService();
+
+ /**
+ * Get documents opened by the LSP client.
+ */
+ public OpenedDocuments getOpenedDocuments();
}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchDelegate.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchDelegate.java
index c6304c0..9803105 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchDelegate.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/launch/NbLaunchDelegate.java
@@ -62,6 +62,7 @@ import org.netbeans.api.project.ProjectUtils;
import org.netbeans.modules.java.lsp.server.Utils;
import org.netbeans.modules.java.lsp.server.debugging.DebugAdapterContext;
import org.netbeans.modules.java.lsp.server.debugging.NbSourceProvider;
+import org.netbeans.modules.java.lsp.server.debugging.ni.NILocationVisualizer;
import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities;
import org.netbeans.modules.java.lsp.server.progress.OperationContext;
import org.netbeans.modules.java.lsp.server.progress.ProgressOperationEvent;
@@ -364,6 +365,7 @@ public abstract class NbLaunchDelegate {
private static void startNativeDebug(File nativeImageFile, List<String> args, String miDebugger, DebugAdapterContext context, ExecutionDescriptor executionDescriptor, CompletableFuture<Void> launchFuture, ActionProgress debugProgress) {
AtomicReference<NbDebugSession> debugSessionRef = new AtomicReference<>();
+ CompletableFuture<Void> finished = new CompletableFuture<>();
NIDebugger niDebugger;
try {
niDebugger = NIDebugRunner.start(nativeImageFile, args, miDebugger, null, null, executionDescriptor, engine -> {
@@ -373,6 +375,12 @@ public abstract class NbLaunchDelegate {
context.setDebugSession(debugSession);
launchFuture.complete(null);
context.getConfigurationSemaphore().waitForConfigurationDone();
+ session.addPropertyChangeListener(Session.PROP_CURRENT_LANGUAGE, evt -> {
+ if (evt.getNewValue() == null) {
+ // No current language => finished
+ finished.complete(null);
+ }
+ });
});
} catch (IllegalStateException ex) {
ErrorUtilities.completeExceptionally(launchFuture,
@@ -383,6 +391,7 @@ public abstract class NbLaunchDelegate {
}
NbDebugSession debugSession = debugSessionRef.get();
debugSession.setNIDebugger(niDebugger);
+ NILocationVisualizer.handle(nativeImageFile, niDebugger, finished, context.getLspSession().getLspServer().getOpenedDocuments());
}
@NonNull
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/ni/NILocationVisualizer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/ni/NILocationVisualizer.java
new file mode 100644
index 0000000..13cb437
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/ni/NILocationVisualizer.java
@@ -0,0 +1,411 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.debugging.ni;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.LineMap;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.SourcePositions;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+
+import org.eclipse.lsp4j.Position;
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.jsonrpc.messages.Either;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.api.java.source.TreeUtilities;
+import org.netbeans.modules.java.lsp.server.files.OpenedDocuments;
+import org.netbeans.modules.java.lsp.server.progress.OperationContext;
+import org.netbeans.modules.java.lsp.server.protocol.DecorationRenderOptions;
+import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient;
+import org.netbeans.modules.java.lsp.server.protocol.SetTextEditorDecorationParams;
+import org.netbeans.modules.nativeimage.api.Location;
+import org.netbeans.modules.nativeimage.api.SourceInfo;
+import org.netbeans.modules.nativeimage.api.Symbol;
+import org.netbeans.modules.nativeimage.api.debug.NIDebugger;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.URLMapper;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @author Martin Entlicher
+ */
+public final class NILocationVisualizer implements Consumer<String> {
+
+ private final File niFileSources;
+ private final NIDebugger niDebugger;
+ private final NbCodeLanguageClient client;
+ private final OpenedDocuments openedDocuments;
+ private Set<String> decorationKeys = new HashSet<>();
+
+ private NILocationVisualizer(File nativeImageFile, NIDebugger niDebugger, CompletableFuture<Void> finished, OpenedDocuments openedDocuments) {
+ this.niFileSources = getNativeSources(nativeImageFile);
+ this.niDebugger = niDebugger;
+ OperationContext ctx = OperationContext.find(Lookup.getDefault());
+ this.client = ctx.getClient();
+ this.openedDocuments = openedDocuments;
+ finished.thenRun(() -> {
+ openedDocuments.removeOpenedConsumer(this);
+ Set<String> keys;
+ synchronized (this) {
+ keys = decorationKeys;
+ decorationKeys = null;
+ }
+ for (String key : keys) {
+ client.disposeTextEditorDecoration(key);
+ }
+ });
+ }
+
+ private static File getNativeSources(File niFile) {
+ File sources = new File(niFile.getParentFile(), "sources");
+ if (sources.isDirectory()) {
+ return sources;
+ } else {
+ return null;
+ }
+ }
+
+ public static void handle(File nativeImageFile, NIDebugger niDebugger, CompletableFuture<Void> finished, OpenedDocuments openedDocuments) {
+ openedDocuments.addOpenedConsumer(new NILocationVisualizer(nativeImageFile, niDebugger, finished, openedDocuments));
+ }
+
+ @Override
+ public void accept(final String uri) {
+ List<Location> locations = getLocations(uri);
+ if (locations != null) {
+ DecorationRenderOptions decorationOptions = new DecorationRenderOptions();
+ decorationOptions.setColor(Either.forLeft("gray"));
+ CompletableFuture<String> decorationFuture = client.createTextEditorDecoration(decorationOptions);
+ decorationFuture.thenAccept(key -> {
+ Intervals intervals = getCodeIntervals(uri);
+ Range[] ranges = locationsToRanges(locations, intervals);
+ client.setTextEditorDecoration(new SetTextEditorDecorationParams(key, uri, ranges));
+ boolean disposed;
+ synchronized (this) {
+ disposed = decorationKeys == null; // Disposed in the mean time
+ if (!disposed) {
+ decorationKeys.add(key);
+ }
+ }
+ if (disposed) {
+ client.disposeTextEditorDecoration(key);
+ }
+ });
+ }
+ }
+
+ private final List<Location> getLocations(String uri) {
+ List<Location> locations = niDebugger.listLocations(uri);
+ if (locations == null && niFileSources != null) {
+ String relPath = getRelativePath(uri);
+ if (relPath != null) {
+ File sourcesFile = new File(niFileSources, relPath);
+ String filePath = sourcesFile.getAbsolutePath();
+ locations = niDebugger.listLocations(filePath);
+ }
+ }
+ return locations;
+ }
+
+ /**
+ * The ranges are sub-intervals of <code>intervals</code> that do not contain <code>locations</code>.
+ */
+ private Range[] locationsToRanges(List<Location> locations, Intervals intervals) {
+ locations.sort((l1, l2) -> l1.getLine() - l2.getLine());
+ List<Range> ranges = new ArrayList<>();
+ int lastLine = intervals.getFirst();
+ int maxLine = intervals.getLast();
+ for (Location l : locations) {
+ int line = l.getLine();
+ if (line == 0) { // Unknown line location
+ continue;
+ }
+ if (lastLine < line) {
+ int start = lastLine;
+ int end = line - 1;
+ do {
+ while (!intervals.contains(start) && start < maxLine) {
+ start++;
+ }
+ if (start > end) {
+ break;
+ }
+ int rangeEnd = start;
+ while (rangeEnd < end && intervals.contains(rangeEnd)) {
+ rangeEnd++;
+ }
+ int startCol = intervals.getFirstColumn(start);
+ int endCol = intervals.getLastColumn(rangeEnd);
+ int endLine = rangeEnd;
+ if (endCol == -1) { // end is the end of line
+ endLine++;
+ endCol = 1;
+ }
+ ranges.add(new Range(new Position(start-1, startCol-1), new Position(endLine-1, endCol-1))); // Position is 0-based
+ start = rangeEnd + 1;
+ } while (start <= end);
+ }
+ lastLine = line + 1;
+ }
+ if (lastLine < maxLine) {
+ ranges.add(new Range(new Position(lastLine, 0), new Position(maxLine, 0)));
+ }
+ for (String variable : intervals.variables.keySet()) {
+ Map<SourceInfo, List<Symbol>> listVariables = niDebugger.listVariables(variable, true, -1);
+ if (listVariables != null && listVariables.isEmpty()) {
+ Interval interval = intervals.variables.get(variable);
+ ranges.add(new Range(new Position(interval.l1-1, interval.c1-1), new Position(interval.l2-1, interval.c2-1))); // Position is 0-based
+ }
+ }
+ return ranges.toArray(new Range[ranges.size()]);
+ }
+
+ private static String r2s(List<Range> ranges) {
+ StringBuilder sb = new StringBuilder("[");
+ for (Range r : ranges) {
+ sb.append(r.getStart().getLine() + " - " + r.getEnd().getLine());
+ sb.append(", ");
+ }
+ if (sb.length() > 3) {
+ sb.delete(sb.length() - 2, sb.length());
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ private static String getRelativePath(String url) {
+ FileObject fo;
+ try {
+ fo = URLMapper.findFileObject(new URL(url));
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ if (fo == null) {
+ return null;
+ }
+ ClassPath cp = ClassPath.getClassPath (fo, ClassPath.SOURCE);
+ if (cp == null) {
+ cp = ClassPath.getClassPath (fo, ClassPath.COMPILE);
+ }
+ if (cp == null) {
+ return null;
+ }
+ return cp.getResourceName (fo, '/', true);
+ }
+
+ private static Intervals getCodeIntervals(String url) {
+ FileObject fo;
+ try {
+ fo = URLMapper.findFileObject(new URL(url));
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ JavaSource source = JavaSource.forFileObject(fo);
+ Intervals intervals = new Intervals();
+ try {
+ source.runWhenScanFinished(new Task<CompilationController>() {
+ @Override
+ public void run(CompilationController cc) throws Exception {
+ List<? extends TypeElement> topLevelElements = cc.getTopLevelElements();
+ TreeUtilities treeUtilities = cc.getTreeUtilities();
+ SourcePositions sourcePositions = cc.getTrees().getSourcePositions();
+ LineMap lineMap = cc.getCompilationUnit().getLineMap();
+ for (Element element : topLevelElements) {
+ Tree tree = cc.getTrees().getTree(element);
+ if (tree.getKind() == Tree.Kind.CLASS) {
+ List<? extends Tree> members = ((ClassTree) tree).getMembers();
+ for (Tree member : members) {
+ Tree t = null;
+ if (member.getKind() == Tree.Kind.METHOD) {
+ t = ((MethodTree) member).getBody();
+ } else if (member.getKind() == Tree.Kind.BLOCK) {
+ t = member;
+ }
+ if (t != null) {
+ Interval interval = createInterval(cc.getCompilationUnit(), sourcePositions, lineMap, t);
+ if (interval != null) {
+ intervals.add(interval);
+ }
+ } else if (member.getKind() == Tree.Kind.VARIABLE) {
+ VariableTree variable = (VariableTree) member;
+ boolean isStatic = variable.getModifiers().getFlags().contains(Modifier.STATIC);
+ if (isStatic) {
+ String name = variable.getName().toString();
+ name = cc.getElementUtilities().getElementName(element, true) + "::" + name;
+ Interval interval = createInterval(cc.getCompilationUnit(), sourcePositions, lineMap, member);
+ if (interval != null) {
+ intervals.addVariable(name, interval);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }, true);
+ } catch (IOException ex) {
+ }
+ return intervals;
+ }
+
+ private static Interval createInterval(CompilationUnitTree cut, SourcePositions sourcePositions, LineMap lineMap, Tree tree) {
+ long start = sourcePositions.getStartPosition(cut, tree);
+ long end = sourcePositions.getEndPosition(cut, tree);
+ if (start != Diagnostic.NOPOS && end != Diagnostic.NOPOS) {
+ int line1 = (int) lineMap.getLineNumber(start);
+ int col1 = (int) lineMap.getColumnNumber(start);
+ int line2 = (int) lineMap.getLineNumber(end);
+ int col2 = (int) lineMap.getColumnNumber(end);
+ return new Interval(line1, col1, line2, col2);
+ } else {
+ return null;
+ }
+ }
+
+ private static final class Intervals {
+
+ private final List<Interval> intervals = new ArrayList<>();
+ private final Map<String, Interval> variables = new HashMap<>();
+
+ void add(Interval i) {
+ int index = intervals.size();
+ for (int idx = 0; idx < intervals.size(); idx++) {
+ Interval ii = intervals.get(idx);
+ if (i.l1 < ii.l1) {
+ index = idx;
+ break;
+ }
+ }
+ intervals.add(index, i);
+ }
+
+ void addVariable(String name, Interval i) {
+ variables.put(name, i);
+ }
+
+ boolean contains(int n) {
+ for (Interval i : intervals) {
+ if (i.contains(n)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int getFirst() {
+ if (intervals.size() > 0) {
+ return intervals.get(0).l1;
+ } else {
+ return 0;
+ }
+ }
+
+ int getLast() {
+ int s = intervals.size();
+ if (s > 0) {
+ return intervals.get(s - 1).l2;
+ } else {
+ return -1;
+ }
+ }
+
+ private int getFirstColumn(int line) {
+ for (Interval i : intervals) {
+ if (i.contains(line)) {
+ return i.firstColumnOn(line);
+ }
+ }
+ return 1;
+ }
+
+ private int getLastColumn(int line) {
+ for (Interval i : intervals) {
+ if (i.contains(line)) {
+ return i.lastColumnOn(line);
+ }
+ }
+ return -1;
+ }
+ }
+
+ private static final class Interval {
+
+ private final int l1;
+ private final int c1;
+ private final int l2;
+ private final int c2;
+
+ Interval(int l1, int c1, int l2, int c2) {
+ assert l1 <= l2;
+ this.l1 = l1;
+ this.c1 = c1;
+ this.l2 = l2;
+ this.c2 = c2;
+ }
+
+ private boolean contains(int l) {
+ return l1 <= l && l <= l2;
+ }
+
+ private int firstColumnOn(int l) {
+ if (l == l1) {
+ return c1;
+ } else {
+ return 1;
+ }
+ }
+
+ private int lastColumnOn(int l) {
+ if (l == l2) {
+ return c2;
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Interval<" + l1 + ", " + l2 + '>';
+ }
+
+ }
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/files/OpenedDocuments.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/files/OpenedDocuments.java
new file mode 100644
index 0000000..b8b1826
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/files/OpenedDocuments.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.files;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+import javax.swing.text.Document;
+
+/**
+ * Gathers documents opened by the LSP client.
+ *
+ * @author Martin Entlicher
+ */
+public final class OpenedDocuments {
+
+ private final Map<String, Document> openedDocuments = new ConcurrentHashMap<>();
+ private final List<Consumer<String>> openedConsumers = new ArrayList<>();
+
+ /**
+ * Get URIs of opened documents.
+ * @return a collection of URIs of opened documents.
+ */
+ public Collection<String> getUris() {
+ return Collections.unmodifiableSet(openedDocuments.keySet());
+ }
+
+ /**
+ * Get an opened document from an URI.
+ * @param uri an URI
+ * @return an opened document from the provided URI, or <code>null</code>
+ * when no document was opened from the URI.
+ */
+ public Document getDocument(String uri) {
+ return openedDocuments.get(uri);
+ }
+
+ /**
+ * Notify that a document was opened from an URI.
+ */
+ public void notifyOpened(String uri, Document doc) {
+ openedDocuments.put(uri, doc);
+ synchronized (openedConsumers) {
+ for (Consumer<String> c : openedConsumers) {
+ c.accept(uri);
+ }
+ }
+ }
+
+ /**
+ * Notify that a document was closed.
+ */
+ public void notifyClosed(String uri) {
+ openedDocuments.remove(uri);
+ }
+
+ /**
+ * Add a consumer to be notified with URIs of opened documents.
+ * The added consumer is notified with the already opened documents immediately.
+ */
+ public void addOpenedConsumer(Consumer<String> openedConsumer) {
+ synchronized (openedConsumers) {
+ openedConsumers.add(openedConsumer);
+ }
+ for (String uri : getUris()) {
+ openedConsumer.accept(uri);
+ }
+ }
+
+ /**
+ * Remove a consumer that was previously added.
+ */
+ public void removeOpenedConsumer(Consumer<String> openedConsumer) {
+ synchronized (openedConsumers) {
+ openedConsumers.remove(openedConsumer);
+ }
+ }
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DecorationRenderOptions.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DecorationRenderOptions.java
new file mode 100644
index 0000000..6105ac0
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DecorationRenderOptions.java
@@ -0,0 +1,313 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.protocol;
+
+import java.net.URI;
+
+import org.eclipse.lsp4j.jsonrpc.messages.Either;
+import org.eclipse.xtext.xbase.lib.Pure;
+import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
+
+/**
+ *
+ * @author Martin Entlicher
+ */
+public final class DecorationRenderOptions {
+
+ private ThemableDecorationAttachmentRenderOptions after;
+ private Either<String, ThemeColor> backgroundColor;
+ private ThemableDecorationAttachmentRenderOptions before;
+ private String border;
+ private Either<String, ThemeColor> borderColor;
+ private String borderRadius;
+ private String borderSpacing;
+ private String borderStyle;
+ private String borderWidth;
+ private Either<String, ThemeColor> color;
+ private String cursor;
+ private ThemableDecorationRenderOptions dark;
+ private String fontStyle;
+ private String fontWeight;
+ private Either<String, URI> gutterIconPath;
+ private String gutterIconSize;
+ private boolean isWholeLine;
+ private String letterSpacing;
+ private ThemableDecorationRenderOptions light;
+ private String opacity;
+ private String outline;
+ private Either<String, ThemeColor> outlineColor;
+ private String outlineStyle;
+ private String outlineWidth;
+ private Either<String, ThemeColor> overviewRulerColor;
+ private OverviewRulerLane overviewRulerLane;
+ //private DecorationRangeBehavior rangeBehavior;
+ private String textDecoration;
+
+ @Pure
+ @Override
+ public String toString() {
+ ToStringBuilder b = new ToStringBuilder(this);
+ b.add("after", after);
+ b.add("backgroundColor", backgroundColor);
+ b.add("before", before);
+ b.add("border", border);
+ b.add("borderColor", borderColor);
+ b.add("borderRadius", borderRadius);
+ b.add("borderSpacing", borderSpacing);
+ b.add("borderStyle", borderStyle);
+ b.add("borderWidth", borderWidth);
+ b.add("color", color);
+ b.add("cursor", cursor);
+ b.add("dark", dark);
+ b.add("fontStyle", fontStyle);
+ b.add("fontWeight", fontWeight);
+ b.add("gutterIconPath", gutterIconPath);
+ b.add("gutterIconSize", gutterIconSize);
+ b.add("isWholeLine", isWholeLine);
+ b.add("letterSpacing", letterSpacing);
+ b.add("light", light);
+ b.add("opacity", opacity);
+ b.add("outline", outline);
+ b.add("outlineColor", outlineColor);
+ b.add("outlineStyle", outlineStyle);
+ b.add("outlineWidth", outlineWidth);
+ b.add("overviewRulerColor", overviewRulerColor);
+ b.add("overviewRulerLane", overviewRulerLane);
+ b.add("textDecoration", textDecoration);
+ return b.toString();
+ }
+
+ public ThemableDecorationAttachmentRenderOptions getAfter() {
+ return after;
+ }
+
+ public void setAfter(ThemableDecorationAttachmentRenderOptions after) {
+ this.after = after;
+ }
+
+ public Either<String, ThemeColor> getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public void setBackgroundColor(Either<String, ThemeColor> backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ }
+
+ public ThemableDecorationAttachmentRenderOptions getBefore() {
+ return before;
+ }
+
+ public void setBefore(ThemableDecorationAttachmentRenderOptions before) {
+ this.before = before;
+ }
+
+ public String getBorder() {
+ return border;
+ }
+
+ public void setBorder(String border) {
+ this.border = border;
+ }
+
+ public Either<String, ThemeColor> getBorderColor() {
+ return borderColor;
+ }
+
+ public void setBorderColor(Either<String, ThemeColor> borderColor) {
+ this.borderColor = borderColor;
+ }
+
+ public String getBorderRadius() {
+ return borderRadius;
+ }
+
+ public void setBorderRadius(String borderRadius) {
+ this.borderRadius = borderRadius;
+ }
+
+ public String getBorderSpacing() {
+ return borderSpacing;
+ }
+
+ public void setBorderSpacing(String borderSpacing) {
+ this.borderSpacing = borderSpacing;
+ }
+
+ public String getBorderStyle() {
+ return borderStyle;
+ }
+
+ public void setBorderStyle(String borderStyle) {
+ this.borderStyle = borderStyle;
+ }
+
+ public String getBorderWidth() {
+ return borderWidth;
+ }
+
+ public void setBorderWidth(String borderWidth) {
+ this.borderWidth = borderWidth;
+ }
+
+ public Either<String, ThemeColor> getColor() {
+ return color;
+ }
+
+ public void setColor(Either<String, ThemeColor> color) {
+ this.color = color;
+ }
+
+ public String getCursor() {
+ return cursor;
+ }
+
+ public void setCursor(String cursor) {
+ this.cursor = cursor;
+ }
+
+ public ThemableDecorationRenderOptions getDark() {
+ return dark;
+ }
+
+ public void setDark(ThemableDecorationRenderOptions dark) {
+ this.dark = dark;
+ }
+
+ public String getFontStyle() {
+ return fontStyle;
+ }
+
+ public void setFontStyle(String fontStyle) {
+ this.fontStyle = fontStyle;
+ }
+
+ public String getFontWeight() {
+ return fontWeight;
+ }
+
+ public void setFontWeight(String fontWeight) {
+ this.fontWeight = fontWeight;
+ }
+
+ public Either<String, URI> getGutterIconPath() {
+ return gutterIconPath;
+ }
+
+ public void setGutterIconPath(Either<String, URI> gutterIconPath) {
+ this.gutterIconPath = gutterIconPath;
+ }
+
+ public String getGutterIconSize() {
+ return gutterIconSize;
+ }
+
+ public void setGutterIconSize(String gutterIconSize) {
+ this.gutterIconSize = gutterIconSize;
+ }
+
+ public boolean isIsWholeLine() {
+ return isWholeLine;
+ }
+
+ public void setIsWholeLine(boolean isWholeLine) {
+ this.isWholeLine = isWholeLine;
+ }
+
+ public String getLetterSpacing() {
+ return letterSpacing;
+ }
+
+ public void setLetterSpacing(String letterSpacing) {
+ this.letterSpacing = letterSpacing;
+ }
+
+ public ThemableDecorationRenderOptions getLight() {
+ return light;
+ }
+
+ public void setLight(ThemableDecorationRenderOptions light) {
+ this.light = light;
+ }
+
+ public String getOpacity() {
+ return opacity;
+ }
+
+ public void setOpacity(String opacity) {
+ this.opacity = opacity;
+ }
+
+ public String getOutline() {
+ return outline;
+ }
+
+ public void setOutline(String outline) {
+ this.outline = outline;
+ }
+
+ public Either<String, ThemeColor> getOutlineColor() {
+ return outlineColor;
+ }
+
+ public void setOutlineColor(Either<String, ThemeColor> outlineColor) {
+ this.outlineColor = outlineColor;
+ }
+
+ public String getOutlineStyle() {
+ return outlineStyle;
+ }
+
+ public void setOutlineStyle(String outlineStyle) {
+ this.outlineStyle = outlineStyle;
+ }
+
+ public String getOutlineWidth() {
+ return outlineWidth;
+ }
+
+ public void setOutlineWidth(String outlineWidth) {
+ this.outlineWidth = outlineWidth;
+ }
+
+ public Either<String, ThemeColor> getOverviewRulerColor() {
+ return overviewRulerColor;
+ }
+
+ public void setOverviewRulerColor(Either<String, ThemeColor> overviewRulerColor) {
+ this.overviewRulerColor = overviewRulerColor;
+ }
+
+ public OverviewRulerLane getOverviewRulerLane() {
+ return overviewRulerLane;
+ }
+
+ public void setOverviewRulerLane(OverviewRulerLane overviewRulerLane) {
+ this.overviewRulerLane = overviewRulerLane;
+ }
+
+ public String getTextDecoration() {
+ return textDecoration;
+ }
+
+ public void setTextDecoration(String textDecoration) {
+ this.textDecoration = textDecoration;
+ }
+
+
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java
index 0d4f513..05520e0 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientWrapper.java
@@ -144,4 +144,19 @@ class NbCodeClientWrapper implements NbCodeLanguageClient {
public void notifyProgress(ProgressParams params) {
remote.notifyProgress(params);
}
+
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ return remote.createTextEditorDecoration(params);
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ remote.setTextEditorDecoration(params);
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ remote.disposeTextEditorDecoration(params);
+ }
}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java
index 6954b40..c1b3923 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeLanguageClient.java
@@ -72,6 +72,31 @@ public interface NbCodeLanguageClient extends LanguageClient {
public void notifyTestProgress(@NonNull TestProgressParams params);
/**
+ * Create a text editor decoration.
+ *
+ * @param params the decoration render options
+ * @return a key of the created decoration
+ */
+ @JsonRequest("window/createTextEditorDecoration")
+ public CompletableFuture<String> createTextEditorDecoration(@NonNull DecorationRenderOptions params);
+
+ /**
+ * Set text editor decoration to an array of code ranges.
+ *
+ * @param params
+ */
+ @JsonNotification("window/setTextEditorDecoration")
+ public void setTextEditorDecoration(@NonNull SetTextEditorDecorationParams params);
+
+ /**
+ * Notifies client about disposal of the text editor decoration.
+ *
+ * @param params the decoration key
+ */
+ @JsonNotification("window/disposeTextEditorDecoration")
+ public void disposeTextEditorDecoration(@NonNull String params);
+
+ /**
* Returns extended code capabilities.
* @return code capabilities.
*/
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbLspServer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbLspServer.java
index 0453434..f50d437 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbLspServer.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbLspServer.java
@@ -23,6 +23,7 @@ import java.util.concurrent.Future;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.eclipse.lsp4j.services.WorkspaceService;
import org.netbeans.modules.java.lsp.server.LspSession;
+import org.netbeans.modules.java.lsp.server.files.OpenedDocuments;
import org.openide.util.Lookup;
/**
@@ -57,4 +58,8 @@ public final class NbLspServer implements LspSession.ScheduledServer {
public Future<Void> getRunningFuture() {
return runningFuture;
}
+
+ public OpenedDocuments getOpenedDocuments() {
+ return impl.getOpenedDocuments();
+ }
}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OverviewRulerLane.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OverviewRulerLane.java
new file mode 100644
index 0000000..e8eb9a5
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OverviewRulerLane.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.protocol;
+
+/**
+ *
+ * @author Martin Entlicher
+ */
+public enum OverviewRulerLane {
+
+ Center(2),
+ Full(7),
+ Left(1),
+ Right(4);
+
+ private final int intValue;
+
+ OverviewRulerLane(int intValue) {
+ this.intValue = intValue;
+ }
+
+ public int getIntValue() {
+ return intValue;
+ }
+
+ public static OverviewRulerLane get(int intValue) {
+ switch (intValue) {
+ case 2: return Center;
+ case 7: return Full;
+ case 1: return Left;
+ case 4: return Right;
+ default:
+ return null;
+ }
+ }
+
+}
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 4774ecc..9944083 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
@@ -88,6 +88,7 @@ import org.netbeans.api.project.ui.OpenProjects;
import org.netbeans.modules.java.lsp.server.LspServerState;
import org.netbeans.modules.java.lsp.server.LspSession;
import org.netbeans.modules.java.lsp.server.Utils;
+import org.netbeans.modules.java.lsp.server.files.OpenedDocuments;
import org.netbeans.modules.java.lsp.server.progress.OperationContext;
import org.netbeans.modules.progress.spi.InternalHandle;
import org.netbeans.spi.project.ActionProgress;
@@ -316,6 +317,8 @@ public final class Server {
* the set of opened projects change, collections are never modified.
*/
private volatile Collection<Project> openedProjects = Collections.emptyList();
+
+ private final OpenedDocuments openedDocuments = new OpenedDocuments();
Lookup getSessionLookup() {
return sessionLookup;
@@ -574,6 +577,11 @@ public final class Server {
return workspaceProjects;
}
+ @Override
+ public OpenedDocuments getOpenedDocuments() {
+ return openedDocuments;
+ }
+
private JavaSource showIndexingCompleted(Project[] opened) {
try {
final JavaSource source = checkJavaSupport();
@@ -827,6 +835,24 @@ public final class Server {
}
@Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ logWarning(params);
+ CompletableFuture<String> x = new CompletableFuture<>();
+ x.complete(null);
+ return x;
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ logWarning(params);
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ logWarning(params);
+ }
+
+ @Override
public void logMessage(MessageParams message) {
logWarning(message);
}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SetTextEditorDecorationParams.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SetTextEditorDecorationParams.java
new file mode 100644
index 0000000..e6b8c70
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SetTextEditorDecorationParams.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.protocol;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
+import org.eclipse.xtext.xbase.lib.Pure;
+import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
+
+/**
+ * VSCode's DecorationRenderOptions.
+ *
+ * @author martin
+ */
+public final class SetTextEditorDecorationParams {
+
+ /**
+ * The text editor decoration key.
+ */
+ @NonNull
+ private String key;
+
+ /**
+ * The text editor uri.
+ */
+ @NonNull
+ private String uri;
+
+ /**
+ * The decoration ranges.
+ */
+ @NonNull
+ private Range[] ranges;
+
+ public SetTextEditorDecorationParams() {
+ this("", "", new Range[]{});
+ }
+
+ public SetTextEditorDecorationParams(@NonNull String key, @NonNull String uri, @NonNull Range[] ranges) {
+ this.key = key;
+ this.uri = uri;
+ this.ranges = ranges;
+ }
+
+ @Pure
+ @NonNull
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(@NonNull String key) {
+ this.key = key;
+ }
+
+ @Pure
+ @NonNull
+ public String getUri() {
+ return uri;
+ }
+
+ public void setUri(@NonNull String uri) {
+ this.uri = uri;
+ }
+
+ @Pure
+ @NonNull
+ public Range[] getRanges() {
+ return ranges;
+ }
+
+ public void setRanges(@NonNull Range[] ranges) {
+ this.ranges = ranges;
+ }
+
+ @Pure
+ @Override
+ public String toString() {
+ ToStringBuilder b = new ToStringBuilder(this);
+ b.add("key", key);
+ b.add("uri", uri);
+ b.add("ranges", Arrays.toString(ranges));
+ return b.toString();
+ }
+
+ @Pure
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 23 * hash + Objects.hashCode(this.key);
+ hash = 23 * hash + Objects.hashCode(this.uri);
+ hash = 23 * hash + Arrays.deepHashCode(this.ranges);
+ return hash;
+ }
+
+ @Pure
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final SetTextEditorDecorationParams other = (SetTextEditorDecorationParams) obj;
+ if (!Objects.equals(this.key, other.key)) {
+ return false;
+ }
+ if (!Objects.equals(this.uri, other.uri)) {
+ return false;
+ }
+ if (!Arrays.deepEquals(this.ranges, other.ranges)) {
+ return false;
+ }
+ return 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 0685f07..a1af889 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
@@ -175,6 +175,7 @@ import org.netbeans.modules.java.lsp.server.Utils;
import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities;
import org.netbeans.modules.parsing.api.ParserManager;
import org.netbeans.modules.parsing.api.ResultIterator;
+import org.netbeans.modules.java.lsp.server.files.OpenedDocuments;
import org.netbeans.modules.parsing.api.Source;
import org.netbeans.modules.parsing.api.UserTask;
import org.netbeans.modules.parsing.impl.indexing.implspi.ActiveDocumentProvider.IndexingAware;
@@ -235,7 +236,6 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
/**
* Documents actually opened by the client.
*/
- private final Map<String, Document> openedDocuments = new ConcurrentHashMap<>();
private final Map<String, RequestProcessor.Task> diagnosticTasks = new HashMap<>();
private final LspServerState server;
private NbCodeLanguageClient client;
@@ -246,9 +246,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
}
private void reRunDiagnostics() {
- Set<String> documents = new HashSet<>(openedDocuments.keySet());
-
- for (String doc : documents) {
+ for (String doc : server.getOpenedDocuments().getUris()) {
runDiagnosticTasks(doc);
}
}
@@ -447,7 +445,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
}
String uri = params.getTextDocument().getUri();
FileObject file = fromURI(uri);
- Document doc = openedDocuments.get(uri);
+ Document doc = server.getOpenedDocuments().getDocument(uri);
if (file == null || doc == null) {
return CompletableFuture.completedFuture(null);
}
@@ -471,7 +469,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition(DefinitionParams params) {
try {
String uri = params.getTextDocument().getUri();
- Document doc = openedDocuments.get(uri);
+ Document doc = server.getOpenedDocuments().getDocument(uri);
if (doc != null) {
FileObject file = Utils.fromUri(uri);
if (file != null) {
@@ -494,7 +492,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> typeDefinition(TypeDefinitionParams params) {
try {
String uri = params.getTextDocument().getUri();
- Document doc = openedDocuments.get(uri);
+ Document doc = server.getOpenedDocuments().getDocument(uri);
if (doc != null) {
FileObject file = Utils.fromUri(uri);
if (file != null) {
@@ -770,7 +768,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
if (server.openedProjects().getNow(null) == null) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
- Document doc = openedDocuments.get(params.getTextDocument().getUri());
+ Document doc = server.getOpenedDocuments().getDocument(params.getTextDocument().getUri());
if (doc == null) {
return CompletableFuture.completedFuture(Collections.emptyList());
}
@@ -1316,7 +1314,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
//TODO: include stack trace:
client.logMessage(new MessageParams(MessageType.Error, ex.getMessage()));
}
- openedDocuments.put(params.getTextDocument().getUri(), doc);
+ server.getOpenedDocuments().notifyOpened(params.getTextDocument().getUri(), doc);
// attempt to open the directly owning project, delay diagnostics after project open:
server.asyncOpenFileOwner(file).thenRun(() ->
@@ -1333,7 +1331,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
public void didChange(DidChangeTextDocumentParams params) {
String uri = params.getTextDocument().getUri();
upToDateTests.put(uri, Boolean.FALSE);
- Document doc = openedDocuments.get(uri);
+ Document doc = server.getOpenedDocuments().getDocument(uri);
if (doc != null) {
NbDocument.runAtomic((StyledDocument) doc, () -> {
for (TextDocumentContentChangeEvent change : params.getContentChanges()) {
@@ -1359,7 +1357,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
upToDateTests.remove(uri);
// the order here is important ! As the file may cease to exist, it's
// important that the doucment is already gone form the client.
- openedDocuments.remove(uri);
+ server.getOpenedDocuments().notifyClosed(uri);
FileObject file = fromURI(uri, true);
if (file == null) {
return;
@@ -1481,14 +1479,14 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
}
diagnosticTasks.computeIfAbsent(uri, u -> {
return BACKGROUND_TASKS.create(() -> {
- Document originalDoc = openedDocuments.get(uri);
+ Document originalDoc = server.getOpenedDocuments().getDocument(uri);
long originalVersion = documentVersion(originalDoc);
List<Diagnostic> errorDiags = computeDiags(u, -1, ErrorProvider.Kind.ERRORS, originalVersion);
if (documentVersion(originalDoc) == originalVersion) {
publishDiagnostics(uri, errorDiags);
BACKGROUND_TASKS.create(() -> {
List<Diagnostic> hintDiags = computeDiags(u, -1, ErrorProvider.Kind.HINTS, originalVersion);
- Document doc = openedDocuments.get(uri);
+ Document doc = server.getOpenedDocuments().getDocument(uri);
if (documentVersion(doc) == originalVersion) {
publishDiagnostics(uri, hintDiags);
}
@@ -1646,7 +1644,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
* @param uri file URI
*/
private void missingFileDiscovered(String uri) {
- if (openedDocuments.get(uri) != null) {
+ if (server.getOpenedDocuments().getDocument(uri) != null) {
// do not report anything, the document is still opened in the editor
return;
}
@@ -1677,7 +1675,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
@CheckForNull
public JavaSource getJavaSource(String fileUri) {
- Document doc = openedDocuments.get(fileUri);
+ Document doc = server.getOpenedDocuments().getDocument(fileUri);
if (doc == null) {
FileObject file = fromURI(fileUri);
if (file == null) {
@@ -1691,7 +1689,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
@CheckForNull
public Source getSource(String fileUri) {
- Document doc = openedDocuments.get(fileUri);
+ Document doc = server.getOpenedDocuments().getDocument(fileUri);
if (doc == null) {
FileObject file = fromURI(fileUri);
if (file == null) {
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ThemableDecorationAttachmentRenderOptions.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ThemableDecorationAttachmentRenderOptions.java
new file mode 100644
index 0000000..6e78867
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ThemableDecorationAttachmentRenderOptions.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.protocol;
+
+import java.net.URI;
+import java.util.Objects;
+import org.eclipse.lsp4j.jsonrpc.messages.Either;
+import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
+
+/**
+ *
+ * @author Martin Entlicher
+ */
+public final class ThemableDecorationAttachmentRenderOptions {
+
+ private Either<String, ThemeColor> backgroundColor;
+ private String border;
+ private Either<String, ThemeColor> borderColor;
+ private Either<String, ThemeColor> color;
+ private Either<String, URI> contentIconPath;
+ private String contentText;
+ private String fontStyle;
+ private String fontWeight;
+ private String height;
+ private String margin;
+ private String textDecoration;
+ private String width;
+
+ public Either<String, ThemeColor> getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public void setBackgroundColor(Either<String, ThemeColor> backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ }
+
+ public String getBorder() {
+ return border;
+ }
+
+ public void setBorder(String border) {
+ this.border = border;
+ }
+
+ public Either<String, ThemeColor> getBorderColor() {
+ return borderColor;
+ }
+
+ public void setBorderColor(Either<String, ThemeColor> borderColor) {
+ this.borderColor = borderColor;
+ }
+
+ public Either<String, ThemeColor> getColor() {
+ return color;
+ }
+
+ public void setColor(Either<String, ThemeColor> color) {
+ this.color = color;
+ }
+
+ public Either<String, URI> getContentIconPath() {
+ return contentIconPath;
+ }
+
+ public void setContentIconPath(Either<String, URI> contentIconPath) {
+ this.contentIconPath = contentIconPath;
+ }
+
+ public String getContentText() {
+ return contentText;
+ }
+
+ public void setContentText(String contentText) {
+ this.contentText = contentText;
+ }
+
+ public String getFontStyle() {
+ return fontStyle;
+ }
+
+ public void setFontStyle(String fontStyle) {
+ this.fontStyle = fontStyle;
+ }
+
+ public String getFontWeight() {
+ return fontWeight;
+ }
+
+ public void setFontWeight(String fontWeight) {
+ this.fontWeight = fontWeight;
+ }
+
+ public String getHeight() {
+ return height;
+ }
+
+ public void setHeight(String height) {
+ this.height = height;
+ }
+
+ public String getMargin() {
+ return margin;
+ }
+
+ public void setMargin(String margin) {
+ this.margin = margin;
+ }
+
+ public String getTextDecoration() {
+ return textDecoration;
+ }
+
+ public void setTextDecoration(String textDecoration) {
+ this.textDecoration = textDecoration;
+ }
+
+ public String getWidth() {
+ return width;
+ }
+
+ public void setWidth(String width) {
+ this.width = width;
+ }
+
+ @Override
+ public String toString() {
+ ToStringBuilder b = new ToStringBuilder(this);
+ b.add("backgroundColor", backgroundColor);
+ b.add("border", border);
+ b.add("borderColor", borderColor);
+ b.add("color", color);
+ b.add("contentIconPath", contentIconPath);
+ b.add("contentText", contentText);
+ b.add("fontStyle", fontStyle);
+ b.add("fontWeight", fontWeight);
+ b.add("height", height);
+ b.add("margin", margin);
+ b.add("textDecoration", textDecoration);
+ b.add("width", width);
+ return b.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 79 * hash + Objects.hashCode(this.backgroundColor);
+ hash = 79 * hash + Objects.hashCode(this.border);
+ hash = 79 * hash + Objects.hashCode(this.borderColor);
+ hash = 79 * hash + Objects.hashCode(this.color);
+ hash = 79 * hash + Objects.hashCode(this.contentIconPath);
+ hash = 79 * hash + Objects.hashCode(this.contentText);
+ hash = 79 * hash + Objects.hashCode(this.fontStyle);
+ hash = 79 * hash + Objects.hashCode(this.fontWeight);
+ hash = 79 * hash + Objects.hashCode(this.height);
+ hash = 79 * hash + Objects.hashCode(this.margin);
+ hash = 79 * hash + Objects.hashCode(this.textDecoration);
+ hash = 79 * hash + Objects.hashCode(this.width);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ThemableDecorationAttachmentRenderOptions other = (ThemableDecorationAttachmentRenderOptions) obj;
+ if (!Objects.equals(this.border, other.border)) {
+ return false;
+ }
+ if (!Objects.equals(this.contentText, other.contentText)) {
+ return false;
+ }
+ if (!Objects.equals(this.fontStyle, other.fontStyle)) {
+ return false;
+ }
+ if (!Objects.equals(this.fontWeight, other.fontWeight)) {
+ return false;
+ }
+ if (!Objects.equals(this.height, other.height)) {
+ return false;
+ }
+ if (!Objects.equals(this.margin, other.margin)) {
+ return false;
+ }
+ if (!Objects.equals(this.textDecoration, other.textDecoration)) {
+ return false;
+ }
+ if (!Objects.equals(this.width, other.width)) {
+ return false;
+ }
+ if (!Objects.equals(this.backgroundColor, other.backgroundColor)) {
+ return false;
+ }
+ if (!Objects.equals(this.borderColor, other.borderColor)) {
+ return false;
+ }
+ if (!Objects.equals(this.color, other.color)) {
+ return false;
+ }
+ if (!Objects.equals(this.contentIconPath, other.contentIconPath)) {
+ return false;
+ }
+ return true;
+ }
+
+
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ThemableDecorationRenderOptions.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ThemableDecorationRenderOptions.java
new file mode 100644
index 0000000..5ef78a3
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ThemableDecorationRenderOptions.java
@@ -0,0 +1,383 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.protocol;
+
+import java.net.URI;
+import java.util.Objects;
+import org.eclipse.lsp4j.jsonrpc.messages.Either;
+import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
+
+/**
+ *
+ * @author Martin Entlicher
+ */
+public final class ThemableDecorationRenderOptions {
+
+ private ThemableDecorationAttachmentRenderOptions after;
+ private Either<String, ThemeColor> backgroundColor;
+ private ThemableDecorationAttachmentRenderOptions before;
+ private String border;
+ private Either<String, ThemeColor> borderColor;
+ private String borderRadius;
+ private String borderSpacing;
+ private String borderStyle;
+ private String borderWidth;
+ private Either<String, ThemeColor> color;
+ private String cursor;
+ private String fontStyle;
+ private String fontWeight;
+ private Either<String, URI> gutterIconPath;
+ private String gutterIconSize;
+ private String letterSpacing;
+ private String opacity;
+ private String outline;
+ private Either<String, ThemeColor> outlineColor;
+ private String outlineStyle;
+ private String outlineWidth;
+ private Either<String, ThemeColor> overviewRulerColor;
+ private String textDecoration;
+
+ public ThemableDecorationAttachmentRenderOptions getAfter() {
+ return after;
+ }
+
+ public void setAfter(ThemableDecorationAttachmentRenderOptions after) {
+ this.after = after;
+ }
+
+ public Either<String, ThemeColor> getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public void setBackgroundColor(Either<String, ThemeColor> backgroundColor) {
+ this.backgroundColor = backgroundColor;
+ }
+
+ public ThemableDecorationAttachmentRenderOptions getBefore() {
+ return before;
+ }
+
+ public void setBefore(ThemableDecorationAttachmentRenderOptions before) {
+ this.before = before;
+ }
+
+ public String getBorder() {
+ return border;
+ }
+
+ public void setBorder(String border) {
+ this.border = border;
+ }
+
+ public Either<String, ThemeColor> getBorderColor() {
+ return borderColor;
+ }
+
+ public void setBorderColor(Either<String, ThemeColor> borderColor) {
+ this.borderColor = borderColor;
+ }
+
+ public String getBorderRadius() {
+ return borderRadius;
+ }
+
+ public void setBorderRadius(String borderRadius) {
+ this.borderRadius = borderRadius;
+ }
+
+ public String getBorderSpacing() {
+ return borderSpacing;
+ }
+
+ public void setBorderSpacing(String borderSpacing) {
+ this.borderSpacing = borderSpacing;
+ }
+
+ public String getBorderStyle() {
+ return borderStyle;
+ }
+
+ public void setBorderStyle(String borderStyle) {
+ this.borderStyle = borderStyle;
+ }
+
+ public String getBorderWidth() {
+ return borderWidth;
+ }
+
+ public void setBorderWidth(String borderWidth) {
+ this.borderWidth = borderWidth;
+ }
+
+ public Either<String, ThemeColor> getColor() {
+ return color;
+ }
+
+ public void setColor(Either<String, ThemeColor> color) {
+ this.color = color;
+ }
+
+ public String getCursor() {
+ return cursor;
+ }
+
+ public void setCursor(String cursor) {
+ this.cursor = cursor;
+ }
+
+ public String getFontStyle() {
+ return fontStyle;
+ }
+
+ public void setFontStyle(String fontStyle) {
+ this.fontStyle = fontStyle;
+ }
+
+ public String getFontWeight() {
+ return fontWeight;
+ }
+
+ public void setFontWeight(String fontWeight) {
+ this.fontWeight = fontWeight;
+ }
+
+ public Either<String, URI> getGutterIconPath() {
+ return gutterIconPath;
+ }
+
+ public void setGutterIconPath(Either<String, URI> gutterIconPath) {
+ this.gutterIconPath = gutterIconPath;
+ }
+
+ public String getGutterIconSize() {
+ return gutterIconSize;
+ }
+
+ public void setGutterIconSize(String gutterIconSize) {
+ this.gutterIconSize = gutterIconSize;
+ }
+
+ public String getLetterSpacing() {
+ return letterSpacing;
+ }
+
+ public void setLetterSpacing(String letterSpacing) {
+ this.letterSpacing = letterSpacing;
+ }
+
+ public String getOpacity() {
+ return opacity;
+ }
+
+ public void setOpacity(String opacity) {
+ this.opacity = opacity;
+ }
+
+ public String getOutline() {
+ return outline;
+ }
+
+ public void setOutline(String outline) {
+ this.outline = outline;
+ }
+
+ public Either<String, ThemeColor> getOutlineColor() {
+ return outlineColor;
+ }
+
+ public void setOutlineColor(Either<String, ThemeColor> outlineColor) {
+ this.outlineColor = outlineColor;
+ }
+
+ public String getOutlineStyle() {
+ return outlineStyle;
+ }
+
+ public void setOutlineStyle(String outlineStyle) {
+ this.outlineStyle = outlineStyle;
+ }
+
+ public String getOutlineWidth() {
+ return outlineWidth;
+ }
+
+ public void setOutlineWidth(String outlineWidth) {
+ this.outlineWidth = outlineWidth;
+ }
+
+ public Either<String, ThemeColor> getOverviewRulerColor() {
+ return overviewRulerColor;
+ }
+
+ public void setOverviewRulerColor(Either<String, ThemeColor> overviewRulerColor) {
+ this.overviewRulerColor = overviewRulerColor;
+ }
+
+ public String getTextDecoration() {
+ return textDecoration;
+ }
+
+ public void setTextDecoration(String textDecoration) {
+ this.textDecoration = textDecoration;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 37 * hash + Objects.hashCode(this.after);
+ hash = 37 * hash + Objects.hashCode(this.backgroundColor);
+ hash = 37 * hash + Objects.hashCode(this.before);
+ hash = 37 * hash + Objects.hashCode(this.border);
+ hash = 37 * hash + Objects.hashCode(this.borderColor);
+ hash = 37 * hash + Objects.hashCode(this.borderRadius);
+ hash = 37 * hash + Objects.hashCode(this.borderSpacing);
+ hash = 37 * hash + Objects.hashCode(this.borderStyle);
+ hash = 37 * hash + Objects.hashCode(this.borderWidth);
+ hash = 37 * hash + Objects.hashCode(this.color);
+ hash = 37 * hash + Objects.hashCode(this.cursor);
+ hash = 37 * hash + Objects.hashCode(this.fontStyle);
+ hash = 37 * hash + Objects.hashCode(this.fontWeight);
+ hash = 37 * hash + Objects.hashCode(this.gutterIconPath);
+ hash = 37 * hash + Objects.hashCode(this.gutterIconSize);
+ hash = 37 * hash + Objects.hashCode(this.letterSpacing);
+ hash = 37 * hash + Objects.hashCode(this.opacity);
+ hash = 37 * hash + Objects.hashCode(this.outline);
+ hash = 37 * hash + Objects.hashCode(this.outlineColor);
+ hash = 37 * hash + Objects.hashCode(this.outlineStyle);
+ hash = 37 * hash + Objects.hashCode(this.outlineWidth);
+ hash = 37 * hash + Objects.hashCode(this.overviewRulerColor);
+ hash = 37 * hash + Objects.hashCode(this.textDecoration);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ThemableDecorationRenderOptions other = (ThemableDecorationRenderOptions) obj;
+ if (!Objects.equals(this.border, other.border)) {
+ return false;
+ }
+ if (!Objects.equals(this.borderRadius, other.borderRadius)) {
+ return false;
+ }
+ if (!Objects.equals(this.borderSpacing, other.borderSpacing)) {
+ return false;
+ }
+ if (!Objects.equals(this.borderStyle, other.borderStyle)) {
+ return false;
+ }
+ if (!Objects.equals(this.borderWidth, other.borderWidth)) {
+ return false;
+ }
+ if (!Objects.equals(this.cursor, other.cursor)) {
+ return false;
+ }
+ if (!Objects.equals(this.fontStyle, other.fontStyle)) {
+ return false;
+ }
+ if (!Objects.equals(this.fontWeight, other.fontWeight)) {
+ return false;
+ }
+ if (!Objects.equals(this.gutterIconSize, other.gutterIconSize)) {
+ return false;
+ }
+ if (!Objects.equals(this.letterSpacing, other.letterSpacing)) {
+ return false;
+ }
+ if (!Objects.equals(this.opacity, other.opacity)) {
+ return false;
+ }
+ if (!Objects.equals(this.outline, other.outline)) {
+ return false;
+ }
+ if (!Objects.equals(this.outlineStyle, other.outlineStyle)) {
+ return false;
+ }
+ if (!Objects.equals(this.outlineWidth, other.outlineWidth)) {
+ return false;
+ }
+ if (!Objects.equals(this.textDecoration, other.textDecoration)) {
+ return false;
+ }
+ if (!Objects.equals(this.after, other.after)) {
+ return false;
+ }
+ if (!Objects.equals(this.backgroundColor, other.backgroundColor)) {
+ return false;
+ }
+ if (!Objects.equals(this.before, other.before)) {
+ return false;
+ }
+ if (!Objects.equals(this.borderColor, other.borderColor)) {
+ return false;
+ }
+ if (!Objects.equals(this.color, other.color)) {
+ return false;
+ }
+ if (!Objects.equals(this.gutterIconPath, other.gutterIconPath)) {
+ return false;
+ }
+ if (!Objects.equals(this.outlineColor, other.outlineColor)) {
+ return false;
+ }
+ if (!Objects.equals(this.overviewRulerColor, other.overviewRulerColor)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ ToStringBuilder b = new ToStringBuilder(this);
+ b.add("after", after);
+ b.add("backgroundColor", backgroundColor);
+ b.add("before", before);
+ b.add("border", border);
+ b.add("borderColor", borderColor);
+ b.add("borderRadius", borderRadius);
+ b.add("borderSpacing", borderSpacing);
+ b.add("borderStyle", borderStyle);
+ b.add("borderWidth", borderWidth);
+ b.add("color", color);
+ b.add("cursor", cursor);
+ b.add("fontStyle", fontStyle);
+ b.add("fontWeight", fontWeight);
+ b.add("gutterIconPath", gutterIconPath);
+ b.add("gutterIconSize", gutterIconSize);
+ b.add("letterSpacing", letterSpacing);
+ b.add("opacity", opacity);
+ b.add("outline", outline);
+ b.add("outlineColor", outlineColor);
+ b.add("outlineStyle", outlineStyle);
+ b.add("outlineWidth", outlineWidth);
+ b.add("overviewRulerColor", overviewRulerColor);
+ b.add("textDecoration", textDecoration);
+ return b.toString();
+ }
+
+
+}
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ThemeColor.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ThemeColor.java
new file mode 100644
index 0000000..405942e
--- /dev/null
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ThemeColor.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.protocol;
+
+import java.util.Objects;
+
+import org.eclipse.xtext.xbase.lib.Pure;
+import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
+import org.netbeans.api.annotations.common.NonNull;
+
+/**
+ *
+ * @author Martin Entlicher
+ */
+public final class ThemeColor {
+
+ @NonNull
+ private final String id;
+
+ public ThemeColor(@NonNull String id) {
+ this.id = id;
+ }
+
+ @Pure
+ @NonNull
+ public String getId() {
+ return id;
+ }
+
+ @Pure
+ @Override
+ public String toString() {
+ ToStringBuilder b = new ToStringBuilder(this);
+ b.add("id", id);
+ return b.toString();
+ }
+
+ @Pure
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 29 * hash + Objects.hashCode(this.id);
+ return hash;
+ }
+
+ @Pure
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ThemeColor other = (ThemeColor) obj;
+ if (!Objects.equals(this.id, other.id)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
index 5a54f0b..1265b97 100644
--- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
+++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/progress/TestProgressHandlerTest.java
@@ -38,9 +38,11 @@ import org.netbeans.modules.gsf.testrunner.api.Status;
import org.netbeans.modules.gsf.testrunner.api.TestSession;
import org.netbeans.modules.gsf.testrunner.api.Testcase;
import org.netbeans.modules.gsf.testrunner.api.Trouble;
+import org.netbeans.modules.java.lsp.server.protocol.DecorationRenderOptions;
import org.netbeans.modules.java.lsp.server.protocol.NbCodeClientCapabilities;
import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient;
import org.netbeans.modules.java.lsp.server.protocol.QuickPickItem;
+import org.netbeans.modules.java.lsp.server.protocol.SetTextEditorDecorationParams;
import org.netbeans.modules.java.lsp.server.protocol.ShowInputBoxParams;
import org.netbeans.modules.java.lsp.server.protocol.ShowQuickPickParams;
import org.netbeans.modules.java.lsp.server.protocol.ShowStatusMessageParams;
@@ -198,5 +200,21 @@ public class TestProgressHandlerTest extends NbTestCase {
fail();
return null;
}
+
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ fail();
+ return null;
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ fail();
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ fail();
+ }
}
}
diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/OverviewRulerLaneTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/OverviewRulerLaneTest.java
new file mode 100644
index 0000000..d45133f
--- /dev/null
+++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/OverviewRulerLaneTest.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.lsp.server.protocol;
+
+import org.netbeans.junit.NbTestCase;
+
+/**
+ *
+ * @author martin
+ */
+public class OverviewRulerLaneTest extends NbTestCase {
+
+ public OverviewRulerLaneTest(String name) {
+ super(name);
+ }
+
+ public void testAllIntValuesCovered() {
+ for (OverviewRulerLane value : OverviewRulerLane.values()) {
+ assertSame(value, OverviewRulerLane.get(value.getIntValue()));
+ }
+ }
+}
diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
index 15f0ffc..9f4fb43 100644
--- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
+++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
@@ -1604,6 +1604,21 @@ public class ServerTest extends NbTestCase {
public void logMessage(MessageParams arg0) {
throw new UnsupportedOperationException("Not supported yet.");
}
+
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
}, client.getInputStream(), client.getOutputStream());
serverLauncher.startListening();
LanguageServer server = serverLauncher.getRemoteProxy();
@@ -2942,6 +2957,21 @@ public class ServerTest extends NbTestCase {
throw new UnsupportedOperationException("Not supported yet.");
}
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
}, client.getInputStream(), client.getOutputStream());
serverLauncher.startListening();
LanguageServer server = serverLauncher.getRemoteProxy();
@@ -3141,6 +3171,21 @@ public class ServerTest extends NbTestCase {
throw new UnsupportedOperationException("Not supported yet.");
}
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
}, client.getInputStream(), client.getOutputStream());
serverLauncher.startListening();
LanguageServer server = serverLauncher.getRemoteProxy();
@@ -3257,6 +3302,21 @@ public class ServerTest extends NbTestCase {
throw new UnsupportedOperationException("Not supported yet.");
}
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
}, client.getInputStream(), client.getOutputStream());
serverLauncher.startListening();
LanguageServer server = serverLauncher.getRemoteProxy();
@@ -3374,6 +3434,21 @@ public class ServerTest extends NbTestCase {
throw new UnsupportedOperationException("Not supported yet.");
}
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
}, client.getInputStream(), client.getOutputStream());
serverLauncher.startListening();
LanguageServer server = serverLauncher.getRemoteProxy();
@@ -3478,6 +3553,21 @@ public class ServerTest extends NbTestCase {
throw new UnsupportedOperationException("Not supported yet.");
}
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
}, client.getInputStream(), client.getOutputStream());
serverLauncher.startListening();
LanguageServer server = serverLauncher.getRemoteProxy();
@@ -3587,6 +3677,21 @@ public class ServerTest extends NbTestCase {
throw new UnsupportedOperationException("Not supported yet.");
}
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
}, client.getInputStream(), client.getOutputStream());
serverLauncher.startListening();
LanguageServer server = serverLauncher.getRemoteProxy();
@@ -3693,6 +3798,21 @@ public class ServerTest extends NbTestCase {
throw new UnsupportedOperationException("Not supported yet.");
}
+ @Override
+ public CompletableFuture<String> createTextEditorDecoration(DecorationRenderOptions params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void setTextEditorDecoration(SetTextEditorDecorationParams params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void disposeTextEditorDecoration(String params) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
}, client.getInputStream(), client.getOutputStream());
serverLauncher.startListening();
LanguageServer server = serverLauncher.getRemoteProxy();
diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts
index 22f7e5d..9eefdb8 100644
--- a/java/java.lsp.server/vscode/src/extension.ts
+++ b/java/java.lsp.server/vscode/src/extension.ts
@@ -18,7 +18,7 @@
*/
'use strict';
-import { commands, window, workspace, ExtensionContext, ProgressLocation } from 'vscode';
+import { commands, window, workspace, ExtensionContext, ProgressLocation, TextEditorDecorationType } from 'vscode';
import {
LanguageClient,
@@ -43,7 +43,9 @@ import { testExplorerExtensionId, TestHub } from 'vscode-test-adapter-api';
import { TestAdapterRegistrar } from 'vscode-test-adapter-util';
import * as launcher from './nbcode';
import {NbTestAdapter} from './testAdapter';
-import { StatusMessageRequest, ShowStatusMessageParams, QuickPickRequest, InputBoxRequest, TestProgressNotification, DebugConnector } from './protocol';
+import { StatusMessageRequest, ShowStatusMessageParams, QuickPickRequest, InputBoxRequest, TestProgressNotification, DebugConnector,
+ TextEditorDecorationCreateRequest, TextEditorDecorationSetNotification, TextEditorDecorationDisposeNotification,
+} from './protocol';
import * as launchConfigurations from './launchConfigurations';
const API_VERSION : string = "1.0";
@@ -596,7 +598,30 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex
}
}
}
- })
+ });
+ let decorations = new Map<string, TextEditorDecorationType>();
+ c.onRequest(TextEditorDecorationCreateRequest.type, param => {
+ let decorationType = vscode.window.createTextEditorDecorationType(param);
+ decorations.set(decorationType.key, decorationType);
+ return decorationType.key;
+ });
+ c.onNotification(TextEditorDecorationSetNotification.type, param => {
+ let decorationType = decorations.get(param.key);
+ if (decorationType) {
+ let editorsWithUri = vscode.window.visibleTextEditors.filter(
+ editor => editor.document.uri.toString() == param.uri
+ );
+ if (editorsWithUri.length > 0) {
+ editorsWithUri[0].setDecorations(decorationType, param.ranges);
+ }
+ }
+ });
+ c.onNotification(TextEditorDecorationDisposeNotification.type, param => {
+ let decorationType = decorations.get(param);
+ if (decorationType) {
+ decorationType.dispose();
+ }
+ });
handleLog(log, 'Language Client: Ready');
setClient[0](c);
commands.executeCommand('setContext', 'nbJavaLSReady', true);
diff --git a/java/java.lsp.server/vscode/src/protocol.ts b/java/java.lsp.server/vscode/src/protocol.ts
index 75c1d2e..3c3a254 100644
--- a/java/java.lsp.server/vscode/src/protocol.ts
+++ b/java/java.lsp.server/vscode/src/protocol.ts
@@ -18,7 +18,12 @@
*/
'use strict';
-import {QuickPickItem} from 'vscode';
+import {
+ DecorationRenderOptions,
+ QuickPickItem,
+ Range,
+ TextEditorDecorationType,
+} from 'vscode';
import {
NotificationType,
RequestType,
@@ -105,3 +110,21 @@ export interface DebugConnector {
defaultValues: string[];
descriptions: string[];
}
+
+export interface SetTextEditorDecorationParams {
+ key: string;
+ uri: string;
+ ranges: Range[];
+};
+
+export namespace TextEditorDecorationCreateRequest {
+ export const type = new RequestType<DecorationRenderOptions, string, void, void>('window/createTextEditorDecoration');
+};
+
+export namespace TextEditorDecorationSetNotification {
+ export const type = new NotificationType<SetTextEditorDecorationParams, void>('window/setTextEditorDecoration');
+};
+
+export namespace TextEditorDecorationDisposeNotification {
+ export const type = new NotificationType<string, void>('window/disposeTextEditorDecoration');
+};
diff --git a/java/java.nativeimage.debugger/nbproject/project.xml b/java/java.nativeimage.debugger/nbproject/project.xml
index 21f442c..5251556 100644
--- a/java/java.nativeimage.debugger/nbproject/project.xml
+++ b/java/java.nativeimage.debugger/nbproject/project.xml
@@ -85,7 +85,7 @@
<compile-dependency/>
<run-dependency>
<release-version>0</release-version>
- <specification-version>0.1</specification-version>
+ <specification-version>0.2</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaFrameDisplayer.java b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaFrameDisplayer.java
index 2123c98..6c40c8b 100644
--- a/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaFrameDisplayer.java
+++ b/java/java.nativeimage.debugger/src/org/netbeans/modules/java/nativeimage/debugger/displayer/JavaFrameDisplayer.java
@@ -115,6 +115,9 @@ public final class JavaFrameDisplayer implements FrameDisplayer {
private URI getSourceURI(NIFrame frame) {
String functionName = frame.getFunctionName();
int methodEnd = functionName.indexOf('(');
+ if (methodEnd < 0) {
+ methodEnd = functionName.length();
+ }
if (methodEnd > 0) {
int methodStart = functionName.lastIndexOf('.', methodEnd);
if (methodStart > 0) {
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists