This is an automated email from the ASF dual-hosted git repository.

dbalek 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 8aa2c91  LSP: Groovy diagnostic handling. (#3009)
8aa2c91 is described below

commit 8aa2c913074415b49cc1df4407e818a27c8a2ade
Author: Dusan Balek <dusan.ba...@oracle.com>
AuthorDate: Tue Jun 22 19:57:02 2021 +0200

    LSP: Groovy diagnostic handling. (#3009)
    
    * LSP: Hint suggestions for offset computed via new generic ErrorProvider 
API.
    * ErrorProvider implementation for GSF languages.
    * Fixing Groovy hints to work with LSP.
---
 .../editor/hints/AddImportStatementHint.java       |  16 +-
 .../hints/ImplementAllAbstractMethodsHint.java     |  73 +++---
 .../groovy/editor/hints/MakeClassAbstractHint.java |  32 ++-
 .../editor/hints/RemoveUnusedImportHint.java       |  33 ++-
 .../groovy/editor/imports/ImportHelper.java        | 127 +++++------
 ide/api.lsp/apichanges.xml                         |  13 ++
 ide/api.lsp/manifest.mf                            |   2 +-
 .../src/org/netbeans/spi/lsp/ErrorProvider.java    |  26 +++
 ide/csl.api/nbproject/project.properties           |   2 +-
 ide/csl.api/nbproject/project.xml                  |   9 +
 .../src/org/netbeans/modules/csl/api/EditList.java |  14 +-
 .../org/netbeans/modules/csl/core/ApiAccessor.java |  52 +++++
 .../csl/core/LanguageRegistrationProcessor.java    |  10 +-
 .../modules/csl/hints/GsfErrorProvider.java        | 186 +++++++++++++++
 java/java.hints/nbproject/project.xml              |   2 +-
 .../hints/infrastructure/JavaErrorProvider.java    |   4 +-
 ...eans.modules.java.hints.StaticImport.properties |  13 +-
 java/java.lsp.server/nbproject/project.xml         |   2 +-
 .../server/protocol/TextDocumentServiceImpl.java   | 253 ++++++++++-----------
 java/java.lsp.server/vscode/package-lock.json      |  12 +-
 java/java.lsp.server/vscode/package.json           |   5 +-
 21 files changed, 598 insertions(+), 288 deletions(-)

diff --git 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/AddImportStatementHint.java
 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/AddImportStatementHint.java
index 144cadc..ec029fb 100644
--- 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/AddImportStatementHint.java
+++ 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/AddImportStatementHint.java
@@ -89,7 +89,7 @@ public class AddImportStatementHint extends GroovyErrorRule {
                 HintFix fixToApply = new AddImportFix(fo, fqn);
                 fixList.add(fixToApply);
 
-                Hint descriptor = new Hint(this, fixToApply.getDescription(), 
fo, range,
+                Hint descriptor = new Hint(this, desc, fo, range,
                         fixList, DEFAULT_PRIORITY);
 
                 result.add(descriptor);
@@ -126,7 +126,7 @@ public class AddImportStatementHint extends GroovyErrorRule 
{
         return HintSeverity.ERROR;
     }
 
-    private static class AddImportFix implements HintFix {
+    private static class AddImportFix implements PreviewableFix {
 
         private final FileObject fo;
         private final String fqn;
@@ -147,7 +147,12 @@ public class AddImportStatementHint extends 
GroovyErrorRule {
 
         @Override
         public void implement() throws Exception {
-            ImportHelper.addImportStatement(fo, fqn);
+            getEditList().apply();
+        }
+
+        @Override
+        public EditList getEditList() throws Exception {
+            return ImportHelper.addImportStatementEdits(fo, fqn);
         }
 
         @Override
@@ -159,5 +164,10 @@ public class AddImportStatementHint extends 
GroovyErrorRule {
         public boolean isInteractive() {
             return false;
         }
+
+        @Override
+        public boolean canPreview() {
+            return true;
+        }
     }
 }
diff --git 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/ImplementAllAbstractMethodsHint.java
 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/ImplementAllAbstractMethodsHint.java
index efa5bb2..ba30377 100644
--- 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/ImplementAllAbstractMethodsHint.java
+++ 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/ImplementAllAbstractMethodsHint.java
@@ -35,6 +35,7 @@ import org.netbeans.modules.csl.api.Hint;
 import org.netbeans.modules.csl.api.HintFix;
 import org.netbeans.modules.csl.api.HintSeverity;
 import org.netbeans.modules.csl.api.OffsetRange;
+import org.netbeans.modules.csl.api.PreviewableFix;
 import org.netbeans.modules.csl.api.RuleContext;
 import org.netbeans.modules.editor.indent.api.IndentUtils;
 import org.netbeans.modules.groovy.editor.api.lexer.GroovyTokenId;
@@ -70,7 +71,7 @@ public final class ImplementAllAbstractMethodsHint extends 
GroovyErrorRule {
 
             OffsetRange range = HintUtils.getLineOffset(context, error);
             if (range != null) {
-                result.add(new Hint(this, fix.getDescription(), fo, range, 
Collections.<HintFix>singletonList(fix), 100));
+                result.add(new Hint(this, error.getDescription(), fo, range, 
Collections.<HintFix>singletonList(fix), 100));
             }
         }
         
@@ -134,7 +135,7 @@ public final class ImplementAllAbstractMethodsHint extends 
GroovyErrorRule {
      * Fix representing possibility to add empty method stubs directly to the 
source
      * code.
      */
-    private static class AddMethodStubsFix implements HintFix {
+    private static class AddMethodStubsFix implements PreviewableFix {
 
         private final GroovyError error;
         private final List<String> missingMethods;
@@ -151,41 +152,44 @@ public final class ImplementAllAbstractMethodsHint 
extends GroovyErrorRule {
 
         @Override
         public void implement() throws Exception {
-            BaseDocument baseDoc = LexUtilities.getDocument(error.getFile(), 
true);
-            if (baseDoc == null) {
-                return;
-            }
+            getEditList().apply();
+        }
 
+        @Override
+        public EditList getEditList() throws Exception {
+            BaseDocument baseDoc = LexUtilities.getDocument(error.getFile(), 
true);
             EditList edits = new EditList(baseDoc);
-            for (int i = 0; i < missingMethods.size(); i++) {
-                StringBuilder sb = new StringBuilder();
-                
-                // Add one additional new line before the first method stub
-                if (i == 0) {
-                    sb.append("\n"); // NOI18N
-                }
-                sb.append("public " ); // NOI18N
-                sb.append(missingMethods.get(i));
-                sb.append(" {\n"); // NOI18N
-                
-                for (int space = 0; space < 
IndentUtils.indentLevelSize(baseDoc); space++) {
-                    sb.append(" "); // NOI18N
-                }
-                sb.append("throw new UnsupportedOperationException(\"Not 
supported yet.\");\n"); // NOI18N
-                sb.append("}"); // NOI18N
-                
-                // In the last inserted stub, add only one additional new line
-                if (i == missingMethods.size() - 1) {
-                    sb.append("\n"); // NOI18N
-                } else {
-                    sb.append("\n\n"); // NOI18N
+            if (baseDoc != null) {
+                for (int i = 0; i < missingMethods.size(); i++) {
+                    StringBuilder sb = new StringBuilder();
+
+                    // Add one additional new line before the first method stub
+                    if (i == 0) {
+                        sb.append("\n"); // NOI18N
+                    }
+                    sb.append("public " ); // NOI18N
+                    sb.append(missingMethods.get(i));
+                    sb.append(" {\n"); // NOI18N
+
+                    for (int space = 0; space < 
IndentUtils.indentLevelSize(baseDoc); space++) {
+                        sb.append(" "); // NOI18N
+                    }
+                    sb.append("throw new UnsupportedOperationException(\"Not 
supported yet.\");\n"); // NOI18N
+                    sb.append("}"); // NOI18N
+
+                    // In the last inserted stub, add only one additional new 
line
+                    if (i == missingMethods.size() - 1) {
+                        sb.append("\n"); // NOI18N
+                    } else {
+                        sb.append("\n\n"); // NOI18N
+                    }
+
+                    edits.replace(getInsertPosition(baseDoc), 0, 
sb.toString(), true, 0);
                 }
-                
-                edits.replace(getInsertPosition(baseDoc), 0, sb.toString(), 
true, 0);
             }
-            edits.apply();
+            return edits;
         }
-        
+
         private int getInsertPosition(BaseDocument doc) {
             TokenSequence<GroovyTokenId> ts = 
LexUtilities.getGroovyTokenSequence(doc, 1);
 
@@ -270,5 +274,10 @@ public final class ImplementAllAbstractMethodsHint extends 
GroovyErrorRule {
         public boolean isInteractive() {
             return false;
         }
+
+        @Override
+        public boolean canPreview() {
+            return true;
+        }
     }
 }
diff --git 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/MakeClassAbstractHint.java
 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/MakeClassAbstractHint.java
index 87aa9da..7671de9 100644
--- 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/MakeClassAbstractHint.java
+++ 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/MakeClassAbstractHint.java
@@ -34,6 +34,7 @@ import org.netbeans.modules.csl.api.Hint;
 import org.netbeans.modules.csl.api.HintFix;
 import org.netbeans.modules.csl.api.HintSeverity;
 import org.netbeans.modules.csl.api.OffsetRange;
+import org.netbeans.modules.csl.api.PreviewableFix;
 import org.netbeans.modules.csl.api.RuleContext;
 import org.netbeans.modules.groovy.editor.api.lexer.GroovyTokenId;
 import org.netbeans.modules.groovy.editor.api.lexer.LexUtilities;
@@ -69,7 +70,7 @@ public final class MakeClassAbstractHint extends 
GroovyErrorRule {
         if (range != null) {
             HintFix fix = new MakeClassAbstractFix(error);
             
-            result.add(new Hint(this, fix.getDescription(), error.getFile(), 
range, Collections.singletonList(fix), 200));
+            result.add(new Hint(this, error.getDescription(), error.getFile(), 
range, Collections.singletonList(fix), 200));
         }
     }
     
@@ -94,7 +95,7 @@ public final class MakeClassAbstractHint extends 
GroovyErrorRule {
         return HintSeverity.ERROR;
     }
     
-    private static class MakeClassAbstractFix implements HintFix {
+    private static class MakeClassAbstractFix implements PreviewableFix {
 
         private final GroovyError error;
 
@@ -105,20 +106,22 @@ public final class MakeClassAbstractHint extends 
GroovyErrorRule {
 
         @Override
         public void implement() throws Exception {
+            getEditList().apply();
+        }
+
+        @Override
+        public EditList getEditList() throws Exception {
             BaseDocument baseDoc = LexUtilities.getDocument(error.getFile(), 
true);
-            if (baseDoc == null) {
-                return;
-            }
             EditList edits = new EditList(baseDoc);
-            
-            int classPosition = getInsertPosition(baseDoc);
-            if (classPosition != 0) {
-                edits.replace(classPosition, 0, "abstract ", false, 0);
+            if (baseDoc != null) {
+                int classPosition = getInsertPosition(baseDoc);
+                if (classPosition != 0) {
+                    edits.replace(classPosition, 0, "abstract ", false, 0);
+                }
             }
-            
-            edits.apply();
+            return edits;
         }
-        
+
         private int getInsertPosition(BaseDocument doc) {
             TokenSequence<GroovyTokenId> ts = 
LexUtilities.getGroovyTokenSequence(doc, 1);
 
@@ -184,5 +187,10 @@ public final class MakeClassAbstractHint extends 
GroovyErrorRule {
         public boolean isInteractive() {
             return false;
         }
+
+        @Override
+        public boolean canPreview() {
+            return true;
+        }
     }
 }
diff --git 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/RemoveUnusedImportHint.java
 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/RemoveUnusedImportHint.java
index 1d16876..03e41ed 100644
--- 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/RemoveUnusedImportHint.java
+++ 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/hints/RemoveUnusedImportHint.java
@@ -35,6 +35,7 @@ import org.netbeans.modules.csl.api.EditList;
 import org.netbeans.modules.csl.api.Hint;
 import org.netbeans.modules.csl.api.HintFix;
 import org.netbeans.modules.csl.api.HintSeverity;
+import org.netbeans.modules.csl.api.PreviewableFix;
 import org.netbeans.modules.csl.api.RuleContext;
 import org.netbeans.modules.editor.NbEditorUtilities;
 import org.netbeans.modules.groovy.editor.api.ASTUtils;
@@ -43,6 +44,7 @@ import 
org.netbeans.modules.groovy.editor.api.lexer.LexUtilities;
 import org.netbeans.modules.groovy.editor.hints.infrastructure.GroovyAstRule;
 import 
org.netbeans.modules.groovy.editor.hints.infrastructure.GroovyHintsProvider;
 import org.openide.util.Exceptions;
+import org.openide.util.NbBundle;
 
 /**
  *
@@ -51,6 +53,7 @@ import org.openide.util.Exceptions;
 public class RemoveUnusedImportHint extends GroovyAstRule {
 
     @Override
+    @NbBundle.Messages("UnusedImport=Unused import")
     public void computeHints(GroovyHintsProvider.GroovyRuleContext context, 
List<Hint> result) {
         final ModuleNode moduleNode = 
context.getGroovyParserResult().getRootElement().getModuleNode();
         if (null == moduleNode) {
@@ -68,10 +71,10 @@ public class RemoveUnusedImportHint extends GroovyAstRule {
                 while(-1 != (find = context.doc.find(stringFwdFinder, find+1, 
-1)) && skipUsage(find, context.doc));
                 
                 if (-1 == find) {
-                    result.add(new Hint(this, "Unused Import", 
+                    result.add(new Hint(this, Bundle.UnusedImport(), 
                             NbEditorUtilities.getFileObject(context.doc), 
                             ASTUtils.getRangeFull(importNode, context.doc), 
-                            Collections.<HintFix>singletonList(new 
RemoveUnusedImportFix("Remove unused import", context.doc, importNode)), 1));
+                            Collections.<HintFix>singletonList(new 
RemoveUnusedImportFix(Bundle.RemoveUnusedImportHintDescription(), context.doc, 
importNode)), 1));
                 }             
             } catch (BadLocationException ex) {
                 Exceptions.printStackTrace(ex);
@@ -104,8 +107,9 @@ public class RemoveUnusedImportHint extends GroovyAstRule {
     }
 
     @Override
+    @NbBundle.Messages("RemoveUnusedImportHintDescription=Remove unused 
import")
     public String getDescription() {
-        return "Remove unused Import";
+        return Bundle.RemoveUnusedImportHintDescription();
     }
 
     @Override
@@ -125,7 +129,7 @@ public class RemoveUnusedImportHint extends GroovyAstRule {
 
     @Override
     public String getDisplayName() {
-        return "Remove unused import";
+        return Bundle.RemoveUnusedImportHintDescription();
     }
 
     @Override
@@ -137,14 +141,14 @@ public class RemoveUnusedImportHint extends GroovyAstRule 
{
     public HintSeverity getDefaultSeverity() {
         return HintSeverity.INFO;
     }
-    
-    private static class RemoveUnusedImportFix implements HintFix {
+
+    private static class RemoveUnusedImportFix implements PreviewableFix {
 
         final BaseDocument baseDoc;
         final String desc;
         final ImportNode importNode;
 
-        public RemoveUnusedImportFix(String desc, BaseDocument baseDoc, 
ImportNode importNode) {
+        private RemoveUnusedImportFix(String desc, BaseDocument baseDoc, 
ImportNode importNode) {
             this.desc = desc;
             this.baseDoc = baseDoc;
             this.importNode = importNode;
@@ -157,11 +161,16 @@ public class RemoveUnusedImportHint extends GroovyAstRule 
{
 
         @Override
         public void implement() throws Exception {
+            getEditList().apply();
+        }
+
+        @Override
+        public EditList getEditList() throws Exception {
             EditList edits = new EditList(baseDoc);
             int offset =  
ASTUtils.getOffset(baseDoc,importNode.getLineNumber(), 1);
             int removeLen =  
ASTUtils.getOffset(baseDoc,importNode.getLineNumber()+1, 1)-offset;
             edits.replace(offset, removeLen, "", true, 0);
-            edits.apply();
+            return edits;
         }
 
         @Override
@@ -173,6 +182,10 @@ public class RemoveUnusedImportHint extends GroovyAstRule {
         public boolean isInteractive() {
             return false;
         }
-    }    
-    
+
+        @Override
+        public boolean canPreview() {
+            return true;
+        }
+    }
 }
diff --git 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/imports/ImportHelper.java
 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/imports/ImportHelper.java
index dd4901c..38865e1 100644
--- 
a/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/imports/ImportHelper.java
+++ 
b/groovy/groovy.editor/src/org/netbeans/modules/groovy/editor/imports/ImportHelper.java
@@ -129,7 +129,7 @@ public final class ImportHelper {
 
                 @Override
                 public void run() {
-                    addImportStatements(fo, singleCandidates);
+                    addImportStatements(fo, singleCandidates).apply();
                 }
             }, "Adding imports", cancel, false);
         }
@@ -192,7 +192,7 @@ public final class ImportHelper {
 
     private static Set<ImportCandidate> findJavaImportCandidates(FileObject 
fo, String packageName, String missingClass) {
         final Set<ImportCandidate> candidates = new HashSet<>();
-        final ClasspathInfo pathInfo = createClasspathInfo(fo);
+        final ClasspathInfo pathInfo = ClasspathInfo.create(fo);
 
         Set<ElementHandle<TypeElement>> typeNames = 
pathInfo.getClassIndex().getDeclaredTypes(
                 missingClass, NameKind.SIMPLE_NAME, 
EnumSet.allOf(ClassIndex.SearchScope.class));
@@ -218,24 +218,6 @@ public final class ImportHelper {
         return candidates;
     }
 
-    @NonNull
-    private static ClasspathInfo createClasspathInfo(FileObject fo) {
-        ClassPath bootPath = ClassPath.getClassPath(fo, ClassPath.BOOT);
-        ClassPath compilePath = ClassPath.getClassPath(fo, ClassPath.COMPILE);
-        ClassPath srcPath = ClassPath.getClassPath(fo, ClassPath.SOURCE);
-
-        if (bootPath == null) {
-            bootPath = ClassPath.EMPTY;
-        }
-        if (compilePath == null) {
-            compilePath = ClassPath.EMPTY;
-        }
-        if (srcPath == null) {
-            srcPath = ClassPath.EMPTY;
-        }
-        return ClasspathInfo.create(bootPath, compilePath, srcPath);
-    }
-
     private static ImportCandidate createImportCandidate(String missingClass, 
String fqnName, ElementKind kind) {
         int level = getImportanceLevel(fqnName);
         Icon icon = ElementIcons.getElementIcon(kind, null);
@@ -266,19 +248,17 @@ public final class ImportHelper {
      */
     public static String getMissingClassName(String errorMessage) {
         String errorPrefix = "unable to resolve class "; // NOI18N
-        String missingClass = null;
-
-        if (errorMessage.startsWith(errorPrefix)) {
-
-            missingClass = errorMessage.substring(errorPrefix.length());
-            int idx = missingClass.indexOf(" ");
+        if (!errorMessage.startsWith(errorPrefix)) {
+            return null;
+        }
 
-            if (idx != -1) {
-                return missingClass.substring(0, idx);
-            }
+        String missingClass = errorMessage.substring(errorPrefix.length());
+        int idx = missingClass.indexOf(" ");
+        if (idx != -1) {
+            missingClass = missingClass.substring(0, idx);
         }
 
-        return missingClass;
+        return missingClass.trim();
     }
 
     private static List<String> showFixImportChooser(Map<String, 
Set<ImportCandidate>> multipleCandidates) {
@@ -309,48 +289,60 @@ public final class ImportHelper {
      * @param fqName fully qualified name of the import
      */
     public static void addImportStatement(FileObject fo, String fqName) {
-        addImportStatements(fo, Collections.singletonList(fqName));
+        addImportStatements(fo, Collections.singletonList(fqName)).apply();
     }
 
-    private static void addImportStatements(FileObject fo, List<String> 
fqNames) {
-        BaseDocument doc = LexUtilities.getDocument(fo, true);
-        if (doc == null) {
-            return;
-        }
+    /**
+     * Returns edits for adding import to the source code (does not run any 
checks if the import
+     * has more candidates from different packages etc.). Typically used by 
"Add import
+     * hint" where we already know what to add.
+     *
+     * @param fo file where we want to put import statement
+     * @param fqName fully qualified name of the import
+     * @return list of edits to be made
+     */
+    public static EditList addImportStatementEdits(FileObject fo, String 
fqName) {
+        return addImportStatements(fo, Collections.singletonList(fqName));
+    }
 
-        for (String fqName : fqNames) {
-            EditList edits = new EditList(doc);
-            try {
-                int packageLine = getPackageLineIndex(doc);
-                int afterPackageLine = packageLine + 1;
-                int afterPackageOffset = 
Utilities.getRowStartFromLineOffset(doc, afterPackageLine);
-                int importLine = getAppropriateLine(doc, fqName);
-                
-                // If the line after the package statement isn't empty, put 
one empty line there
-                if (!Utilities.isRowWhite(doc, afterPackageOffset)) {
-                    edits.replace(afterPackageOffset, 0, "\n", false, 0);
-                } else {
-                    if (collectImports(doc).isEmpty()) {
-                        importLine++;
+    private static EditList addImportStatements(FileObject fo, List<String> 
fqNames) {
+        BaseDocument doc = LexUtilities.getDocument(fo, true);
+        EditList edits = new EditList(doc);
+        if (doc != null) {
+            for (String fqName : fqNames) {
+                try {
+                    int packageLine = getPackageLineIndex(doc);
+                    int afterPackageLine = packageLine + 1;
+                    int afterPackageOffset = 
Utilities.getRowStartFromLineOffset(doc, afterPackageLine);
+                    int importLine = getAppropriateLine(doc, fqName);
+                    if (importLine >= 0) {
+                        // If the line after the package statement isn't 
empty, put one empty line there
+                        if (!Utilities.isRowWhite(doc, afterPackageOffset)) {
+                            edits.replace(afterPackageOffset, 0, "\n", false, 
0);
+                        } else {
+                            if (collectImports(doc).isEmpty()) {
+                                importLine++;
+                            }
+                        }
+
+                        // Find appropriate place to import and put it there
+                        int importOffset = 
Utilities.getRowStartFromLineOffset(doc, importLine);
+                        edits.replace(importOffset, 0, "import " + fqName + 
"\n", false, 0);
+
+                        // If it's the last import and if the line after the 
last import
+                        // statement isn't empty, put one empty line there
+                        int afterImportsOffset = 
Utilities.getRowStartFromLineOffset(doc, importLine);
+
+                        if (!Utilities.isRowWhite(doc, afterImportsOffset) && 
isLastImport(doc, fqName)) {
+                            edits.replace(afterImportsOffset, 0, "\n", false, 
0);
+                        }
                     }
+                } catch (BadLocationException ex) {
+                    Exceptions.printStackTrace(ex);
                 }
-
-                // Find appropriate place to import and put it there
-                int importOffset = Utilities.getRowStartFromLineOffset(doc, 
importLine);
-                edits.replace(importOffset, 0, "import " + fqName + "\n", 
false, 0);
-
-                // If it's the last import and if the line after the last 
import
-                // statement isn't empty, put one empty line there
-                int afterImportsOffset = 
Utilities.getRowStartFromLineOffset(doc, importLine);
-                
-                if (!Utilities.isRowWhite(doc, afterImportsOffset) && 
isLastImport(doc, fqName)) {
-                    edits.replace(afterImportsOffset, 0, "\n", false, 0);
-                }
-            } catch (BadLocationException ex) {
-                Exceptions.printStackTrace(ex);
             }
-            edits.apply();
         }
+        return edits;
     }
 
     private static int getAppropriateLine(BaseDocument doc, String fqName) 
throws BadLocationException {
@@ -360,6 +352,11 @@ public final class ImportHelper {
             return getPackageLineIndex(doc) + 1;
         }
 
+        if (imports.containsKey(fqName)) {
+            // Already imported
+            return -1;
+        }
+
         imports.put(fqName, -1);
 
         String lastImportName = null;
diff --git a/ide/api.lsp/apichanges.xml b/ide/api.lsp/apichanges.xml
index ba858ab..bfbd330 100644
--- a/ide/api.lsp/apichanges.xml
+++ b/ide/api.lsp/apichanges.xml
@@ -51,6 +51,19 @@
 <!-- ACTUAL CHANGES BEGIN HERE: -->
 
 <changes>
+    <change id="ErrorProvider.Context.getOffset">
+        <api name="LSP_API"/>
+        <summary>Adding ErrorProvider.Context.getOffset() method</summary>
+        <version major="1" minor="4"/>
+        <date day="21" month="6" year="2021"/>
+        <author login="balek"/>
+        <compatibility binary="compatible" source="compatible" addition="yes" 
deletion="no"/>
+        <description>
+            An <code>ErrorProvider.Context.getOffset()</code> method 
introduced that allows to
+            compute hint for a given file offset.
+        </description>
+        <class package="org.netbeans.api.lsp" name="ErrorProvider"/>
+    </change>
     <change id="ErrorProvider">
         <api name="LSP_API"/>
         <summary>Adding ErrorProvider</summary>
diff --git a/ide/api.lsp/manifest.mf b/ide/api.lsp/manifest.mf
index 3681b69..8a3d75f 100644
--- a/ide/api.lsp/manifest.mf
+++ b/ide/api.lsp/manifest.mf
@@ -1,6 +1,6 @@
 Manifest-Version: 1.0
 OpenIDE-Module: org.netbeans.api.lsp/1
 OpenIDE-Module-Localizing-Bundle: org/netbeans/api/lsp/Bundle.properties
-OpenIDE-Module-Specification-Version: 1.3
+OpenIDE-Module-Specification-Version: 1.4
 AutoUpdate-Show-In-Client: false
 
diff --git a/ide/api.lsp/src/org/netbeans/spi/lsp/ErrorProvider.java 
b/ide/api.lsp/src/org/netbeans/spi/lsp/ErrorProvider.java
index 8b18ea7..773df25 100644
--- a/ide/api.lsp/src/org/netbeans/spi/lsp/ErrorProvider.java
+++ b/ide/api.lsp/src/org/netbeans/spi/lsp/ErrorProvider.java
@@ -46,6 +46,7 @@ public interface ErrorProvider {
      */
     public static final class Context {
         private final FileObject file;
+        private final int offset;
         private final Kind errorKind;
         private final AtomicBoolean cancel = new AtomicBoolean();
         private final List<Runnable> cancelCallbacks = new ArrayList<>();
@@ -57,7 +58,21 @@ public interface ErrorProvider {
          * @param errorKind the type of errors/warnings that should be computed
          */
         public Context(FileObject file, Kind errorKind) {
+            this(file, -1, errorKind);
+        }
+
+        /**
+         * Construct a new {@code Context}.
+         *
+         * @param file file for which the errors/warnings should be computed
+         * @param offset offset for which the errors/warnings should be 
computed
+         * @param errorKind the type of errors/warnings that should be computed
+         *
+         * @since 1.4
+         */
+        public Context(FileObject file, int offset, Kind errorKind) {
             this.file = file;
+            this.offset = offset;
             this.errorKind = errorKind;
         }
 
@@ -71,6 +86,17 @@ public interface ErrorProvider {
         }
 
         /**
+         * The offset for which the errors/warnings should be computed.
+         *
+         * @return the offset for which the errors/warnings should be computed
+         *
+         * @since 1.4
+         */
+        public int getOffset() {
+            return offset;
+        }
+
+        /**
          * The type of errors/warnings should be computed.
          *
          * @return the type of errors/warnings should be computed
diff --git a/ide/csl.api/nbproject/project.properties 
b/ide/csl.api/nbproject/project.properties
index 3ba590e..b3967dc 100644
--- a/ide/csl.api/nbproject/project.properties
+++ b/ide/csl.api/nbproject/project.properties
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-spec.version.base=2.67.0
+spec.version.base=2.68.0
 is.autoload=true
 javac.source=1.8
 
diff --git a/ide/csl.api/nbproject/project.xml 
b/ide/csl.api/nbproject/project.xml
index 772b861..910c99b 100644
--- a/ide/csl.api/nbproject/project.xml
+++ b/ide/csl.api/nbproject/project.xml
@@ -44,6 +44,15 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.api.lsp</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.4</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.netbeans.api.progress</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
diff --git a/ide/csl.api/src/org/netbeans/modules/csl/api/EditList.java 
b/ide/csl.api/src/org/netbeans/modules/csl/api/EditList.java
index c83db1d..b0ebec7 100644
--- a/ide/csl.api/src/org/netbeans/modules/csl/api/EditList.java
+++ b/ide/csl.api/src/org/netbeans/modules/csl/api/EditList.java
@@ -28,10 +28,12 @@ import javax.swing.text.BadLocationException;
 import javax.swing.text.Document;
 import javax.swing.text.Position;
 import javax.swing.text.StyledDocument;
+import org.netbeans.api.annotations.common.NonNull;
 import org.netbeans.api.editor.document.AtomicLockDocument;
 import org.netbeans.api.editor.document.LineDocument;
 import org.netbeans.api.editor.document.LineDocumentUtils;
 import org.netbeans.editor.BaseDocument;
+import org.netbeans.modules.csl.core.ApiAccessor;
 import org.netbeans.modules.editor.indent.api.Reformat;
 import org.openide.text.NbDocument;
 import org.openide.util.Exceptions;
@@ -49,6 +51,14 @@ import org.openide.util.Exceptions;
  */
 public class EditList {
     private static final Logger LOG = 
Logger.getLogger(EditList.class.getName());
+
+    static {
+        ApiAccessor.setInstance(new ApiAccessor() {
+            public List<EditList.Edit> getEdits(@NonNull EditList editList) {
+                return Collections.unmodifiableList(editList.edits);
+            }
+        });
+    }
     
     private Document doc;
     private List<Edit> edits;
@@ -267,7 +277,7 @@ public class EditList {
             return 0;
         }
     }
-    
+
     /**
      * A class which records a set of edits to a document, and then can apply 
these edits.
      * The edit regions are sorted in reverse order and applied from back to 
front such that
@@ -275,7 +285,7 @@ public class EditList {
      * 
      * @author Tor Norbye
      */
-    private static class Edit implements Comparable<Edit> {
+    public static final class Edit implements Comparable<Edit> {
 
         int offset;
         int removeLen;
diff --git a/ide/csl.api/src/org/netbeans/modules/csl/core/ApiAccessor.java 
b/ide/csl.api/src/org/netbeans/modules/csl/core/ApiAccessor.java
new file mode 100644
index 0000000..38107a1
--- /dev/null
+++ b/ide/csl.api/src/org/netbeans/modules/csl/core/ApiAccessor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.csl.core;
+
+import java.util.List;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.modules.csl.api.EditList;
+import org.openide.util.Parameters;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public abstract class ApiAccessor {
+    private static volatile ApiAccessor instance;
+
+    @NonNull
+    public static synchronized ApiAccessor getInstance() {
+        if (instance == null) {
+            try {
+                Class.forName(EditList.class.getName(), true, 
ApiAccessor.class.getClassLoader());
+                assert instance != null;
+            } catch (ClassNotFoundException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return instance;
+    }
+
+    public static void setInstance(@NonNull final ApiAccessor inst) {
+        Parameters.notNull("inst", inst);   //NOI18N
+        instance = inst;
+    }
+
+    public abstract List<EditList.Edit> getEdits(@NonNull EditList editList);
+}
diff --git 
a/ide/csl.api/src/org/netbeans/modules/csl/core/LanguageRegistrationProcessor.java
 
b/ide/csl.api/src/org/netbeans/modules/csl/core/LanguageRegistrationProcessor.java
index 1ef86b3..fad7989 100644
--- 
a/ide/csl.api/src/org/netbeans/modules/csl/core/LanguageRegistrationProcessor.java
+++ 
b/ide/csl.api/src/org/netbeans/modules/csl/core/LanguageRegistrationProcessor.java
@@ -44,6 +44,7 @@ import 
org.netbeans.modules.csl.editor.fold.GsfFoldManagerFactory;
 import org.netbeans.modules.csl.editor.hyperlink.GsfHyperlinkProvider;
 import org.netbeans.modules.csl.editor.semantic.HighlightsLayerFactoryImpl;
 import org.netbeans.modules.csl.editor.semantic.OccurrencesMarkProviderCreator;
+import org.netbeans.modules.csl.hints.GsfErrorProvider;
 import org.netbeans.modules.csl.hints.GsfUpToDateStateProviderFactory;
 import org.netbeans.modules.csl.navigation.ClassMemberPanel;
 import org.netbeans.modules.csl.spi.LanguageRegistration;
@@ -124,7 +125,7 @@ public class LanguageRegistrationProcessor extends 
LayerGeneratingProcessor {
                     if (methods.containsKey("getParser")) { //NOI18N
                         registerParser(lb, mimeType);
                     }
-                        if (methods.containsKey("getIndexerFactory")) { 
//NOI18N
+                    if (methods.containsKey("getIndexerFactory")) { //NOI18N
                         registerIndexer(lb, mimeType);
                         if (!isAnnotatedByPathRecognizerRegistration) {
                             registerPathRecognizer(lb, mimeType);
@@ -136,6 +137,9 @@ public class LanguageRegistrationProcessor extends 
LayerGeneratingProcessor {
                     if (methods.containsKey("getDeclarationFinder")) { //NOI18N
                         registerHyperlinks(lb, mimeType);
                     }
+                    if (methods.containsKey("getHintsProvider")) { //NOI18N
+                        registerErrorProvider(lb, mimeType);
+                    }
                     registerSemanticHighlighting(lb, mimeType);
                     registerUpToDateStatus(lb, mimeType);
                     registerContextMenu(lb, mimeType, methods);
@@ -308,6 +312,10 @@ public class LanguageRegistrationProcessor extends 
LayerGeneratingProcessor {
 //        item = createFile(doc, mimeFolder, 
"org-netbeans-modules-csl-editor-semantic-HighlightsLayerFactoryImpl.instance");
 // NOI18N
     }
 
+    private static void registerErrorProvider(LayerBuilder b, String mimeType) 
{
+        instanceFile(b, "Editors/" + mimeType, null, GsfErrorProvider.class, 
null).write(); //NOI18N
+    }
+
     private void registerStructureScanner(LayerBuilder b, String mimeType) {
         instanceFile(b, "Navigator/Panels/" + mimeType, null, 
ClassMemberPanel.class, null).intvalue("position", 1000).write(); //NOI18N
         File sideBar = instanceFile(b, "Editors/" + mimeType + "/SideBar", 
null, "org.netbeans.modules.editor.breadcrumbs.spi.BreadcrumbsController", 
"createSideBarFactory");
diff --git 
a/ide/csl.api/src/org/netbeans/modules/csl/hints/GsfErrorProvider.java 
b/ide/csl.api/src/org/netbeans/modules/csl/hints/GsfErrorProvider.java
new file mode 100644
index 0000000..ca0eab0
--- /dev/null
+++ b/ide/csl.api/src/org/netbeans/modules/csl/hints/GsfErrorProvider.java
@@ -0,0 +1,186 @@
+/*
+ * 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.csl.hints;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.StyledDocument;
+import org.netbeans.api.editor.document.LineDocument;
+import org.netbeans.api.editor.document.LineDocumentUtils;
+import org.netbeans.api.lsp.CodeAction;
+import org.netbeans.api.lsp.Diagnostic;
+import org.netbeans.api.lsp.TextDocumentEdit;
+import org.netbeans.api.lsp.TextEdit;
+import org.netbeans.api.lsp.WorkspaceEdit;
+import org.netbeans.modules.csl.api.DataLoadersBridge;
+import org.netbeans.modules.csl.api.EditList;
+import org.netbeans.modules.csl.api.Error;
+import org.netbeans.modules.csl.api.Hint;
+import org.netbeans.modules.csl.api.HintFix;
+import org.netbeans.modules.csl.api.HintsProvider;
+import org.netbeans.modules.csl.api.OffsetRange;
+import org.netbeans.modules.csl.api.PreviewableFix;
+import org.netbeans.modules.csl.api.RuleContext;
+import org.netbeans.modules.csl.core.ApiAccessor;
+import org.netbeans.modules.csl.core.Language;
+import org.netbeans.modules.csl.core.LanguageRegistry;
+import org.netbeans.modules.csl.hints.infrastructure.GsfHintsManager;
+import org.netbeans.modules.csl.spi.ParserResult;
+import org.netbeans.modules.parsing.api.ParserManager;
+import org.netbeans.modules.parsing.api.ResultIterator;
+import org.netbeans.modules.parsing.api.Source;
+import org.netbeans.modules.parsing.api.UserTask;
+import org.netbeans.modules.parsing.spi.ParseException;
+import org.netbeans.modules.parsing.spi.Parser;
+import org.netbeans.spi.lsp.ErrorProvider;
+import org.openide.util.Exceptions;
+import org.openide.util.Union2;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class GsfErrorProvider implements ErrorProvider {
+
+    @Override
+    public List<? extends Diagnostic> computeErrors(Context context) {
+        final List<Hint> hints = new ArrayList<>();
+        final List<Error> errors = new ArrayList<>();
+        try {
+            
ParserManager.parse(Collections.singletonList(Source.create(context.file())), 
new UserTask() {
+                @Override
+                public void run(ResultIterator resultIterator) throws 
Exception {
+                    Parser.Result result = 
resultIterator.getParserResult(context.getOffset());
+                    if(result instanceof ParserResult) {
+                        ParserResult parserResult = (ParserResult) result;
+                        Language language = 
LanguageRegistry.getInstance().getLanguageByMimeType(resultIterator.getSnapshot().getMimeType());
+                        if (language != null) {
+                            HintsProvider hintsProvider = 
language.getHintsProvider();
+                            if (hintsProvider != null) {
+                                GsfHintsManager hintsManager = 
language.getHintsManager();
+                                RuleContext ruleContext = 
hintsManager.createRuleContext(parserResult, language, context.getOffset(), -1, 
-1);
+                                if (ruleContext != null) {
+                                    switch (context.errorKind()) {
+                                        case ERRORS:
+                                            
hintsProvider.computeErrors(hintsManager, ruleContext, hints, errors);
+                                            break;
+                                        case HINTS:
+                                            
hintsProvider.computeHints(hintsManager, ruleContext, hints);
+                                            
hintsProvider.computeSuggestions(hintsManager, ruleContext, hints, 
context.getOffset());
+                                            break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            });
+        } catch (ParseException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+        StyledDocument doc = 
DataLoadersBridge.getDefault().getDocument(context.file());
+        LineDocument lineDocument = doc != null ? LineDocumentUtils.as(doc, 
LineDocument.class) : null;
+        List<Diagnostic> diagnostics = new ArrayList<>(hints.size() + 
errors.size());
+        int idx = 0;
+        for (Hint hint : hints) {
+            diagnostics.add(hint2Diagnostic(hint, ++idx));
+        }
+        for (Error error : errors) {
+            diagnostics.add(error2Diagnostic(error, lineDocument, ++idx));
+        }
+        return diagnostics;
+    }
+
+    private Diagnostic error2Diagnostic(Error error, LineDocument 
lineDocument, int idx) {
+        Diagnostic.Builder diagBuilder = Diagnostic.Builder.create(() -> {
+            if (lineDocument != null) {
+                try {
+                    return 
LineDocumentUtils.getLineFirstNonWhitespace(lineDocument, 
error.getStartPosition());
+                } catch (BadLocationException ex) {}
+            }
+            return error.getStartPosition();
+        }, () -> {
+            if (lineDocument != null) {
+                try {
+                    return 
LineDocumentUtils.getLineLastNonWhitespace(lineDocument, 
error.getEndPosition());
+                } catch (BadLocationException ex) {}
+            }
+            return error.getEndPosition();
+        }, error.getDescription());
+        switch (error.getSeverity()) {
+            case FATAL:
+            case ERROR:
+                diagBuilder.setSeverity(Diagnostic.Severity.Error);
+                break;
+            case WARNING:
+                diagBuilder.setSeverity(Diagnostic.Severity.Warning);
+                break;
+            case INFO:
+                diagBuilder.setSeverity(Diagnostic.Severity.Information);
+                break;
+        }
+        String id = "errors:" + idx + "-" + error.getKey();
+        diagBuilder.setCode(id);
+        return diagBuilder.build();
+    }
+
+    private Diagnostic hint2Diagnostic(Hint hint, int idx) {
+        final OffsetRange range = hint.getRange();
+        Diagnostic.Builder diagBuilder = Diagnostic.Builder.create(() -> 
range.getStart(), () -> range.getEnd(), hint.getDescription());
+        switch (hint.getRule().getDefaultSeverity()) {
+            case ERROR:
+                diagBuilder.setSeverity(Diagnostic.Severity.Error);
+                break;
+            case CURRENT_LINE_WARNING:
+            case WARNING:
+                diagBuilder.setSeverity(Diagnostic.Severity.Warning);
+                break;
+            case INFO:
+                diagBuilder.setSeverity(Diagnostic.Severity.Information);
+                break;
+        }
+        String id = "hints:" + idx + "-" + hint.getRule().getDisplayName();
+        diagBuilder.setCode(id);
+        diagBuilder.addActions(errorReporter -> convertFixes(hint, 
errorReporter));
+        return diagBuilder.build();
+    }
+
+    private static List<CodeAction> convertFixes(Hint hint, 
Consumer<Exception> errorReporter) {
+        List<CodeAction> result = new ArrayList<>();
+        for (HintFix fix : hint.getFixes()) {
+            if (fix instanceof PreviewableFix) {
+                try {
+                    List<TextEdit> edits = new ArrayList<>();
+                    for (EditList.Edit edit : 
ApiAccessor.getInstance().getEdits(((PreviewableFix) fix).getEditList())) {
+                        String newText = edit.getInsertText();
+                        edits.add(new TextEdit(edit.getOffset(), 
edit.getOffset() + edit.getRemoveLen(), newText != null ? newText : ""));
+                    }
+                    TextDocumentEdit te = new 
TextDocumentEdit(hint.getFile().toURI().toString(), edits);
+                    result.add(new CodeAction(fix.getDescription(), new 
WorkspaceEdit(Collections.singletonList(Union2.createFirst(te)))));
+                } catch (Exception ex) {
+                    errorReporter.accept(ex);
+                }
+            }
+        }
+        return result;
+    }
+}
diff --git a/java/java.hints/nbproject/project.xml 
b/java/java.hints/nbproject/project.xml
index 9bc2f12..71477ae 100644
--- a/java/java.hints/nbproject/project.xml
+++ b/java/java.hints/nbproject/project.xml
@@ -58,7 +58,7 @@
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.0</specification-version>
+                        <specification-version>1.4</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
diff --git 
a/java/java.hints/src/org/netbeans/modules/java/hints/infrastructure/JavaErrorProvider.java
 
b/java/java.hints/src/org/netbeans/modules/java/hints/infrastructure/JavaErrorProvider.java
index e438009..2b6c246 100644
--- 
a/java/java.hints/src/org/netbeans/modules/java/hints/infrastructure/JavaErrorProvider.java
+++ 
b/java/java.hints/src/org/netbeans/modules/java/hints/infrastructure/JavaErrorProvider.java
@@ -111,7 +111,7 @@ public class JavaErrorProvider implements ErrorProvider {
                                 if (disabled.size() != 
Severity.values().length) {
                                     AtomicBoolean cancel = new AtomicBoolean();
                                     context.registerCancelCallback(() -> 
cancel.set(true));
-                                    
result.addAll(convert2Diagnostic(context.errorKind(), new 
HintsInvoker(HintsSettings.getGlobalSettings(), cancel).computeHints(cc), ed -> 
!disabled.contains(ed.getSeverity())));
+                                    
result.addAll(convert2Diagnostic(context.errorKind(), new 
HintsInvoker(HintsSettings.getGlobalSettings(), context.getOffset(), 
cancel).computeHints(cc), ed -> !disabled.contains(ed.getSeverity())));
                                 }
                                 break;
                         }
@@ -241,7 +241,7 @@ public class JavaErrorProvider implements ErrorProvider {
                     }
                     String newFilePath = null;
                     for (File newFile : newFiles) {
-                        newFilePath = newFile.getPath();
+                        newFilePath = newFile.toURI().toString();
                         documentChanges.add(Union2.createSecond(new 
CreateFile(newFilePath)));
                     }
                     outer: for (FileObject fileObject : 
changes.getModifiedFileObjects()) {
diff --git a/ide/csl.api/nbproject/project.properties 
b/java/java.lsp.server/nbcode/integration/release/config/Preferences/org/netbeans/modules/java/hints/default/org.netbeans.modules.java.hints.StaticImport.properties
similarity index 70%
copy from ide/csl.api/nbproject/project.properties
copy to 
java/java.lsp.server/nbcode/integration/release/config/Preferences/org/netbeans/modules/java/hints/default/org.netbeans.modules.java.hints.StaticImport.properties
index 3ba590e..d11f28c 100644
--- a/ide/csl.api/nbproject/project.properties
+++ 
b/java/java.lsp.server/nbcode/integration/release/config/Preferences/org/netbeans/modules/java/hints/default/org.netbeans.modules.java.hints.StaticImport.properties
@@ -15,15 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 
-spec.version.base=2.67.0
-is.autoload=true
-javac.source=1.8
-
-javadoc.overview=${basedir}/doc/overview.html
-javadoc.arch=${basedir}/arch.xml
-javadoc.apichanges=${basedir}/apichanges.xml
-javadoc.docfiles=${basedir}/doc
-
-test.config.stableBTD.includes=**/*Test.class
-test.config.stableBTD.excludes=\
-    **/LanguageRegistryTest.class
+enabled=true
diff --git a/java/java.lsp.server/nbproject/project.xml 
b/java/java.lsp.server/nbproject/project.xml
index 6c2e143..2f5e894 100644
--- a/java/java.lsp.server/nbproject/project.xml
+++ b/java/java.lsp.server/nbproject/project.xml
@@ -92,7 +92,7 @@
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.1</specification-version>
+                        <specification-version>1.4</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
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 da75ed4..1a9d211 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
@@ -166,11 +166,6 @@ import 
org.netbeans.modules.java.editor.overridden.ElementDescription;
 import org.netbeans.modules.java.hints.introduce.IntroduceFixBase;
 import org.netbeans.modules.java.hints.introduce.IntroduceHint;
 import org.netbeans.modules.java.hints.introduce.IntroduceKind;
-import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl;
-import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
-import org.netbeans.modules.java.hints.spiimpl.RulesManager;
-import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
-import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
 import org.netbeans.modules.java.lsp.server.LspServerState;
 import org.netbeans.modules.java.lsp.server.Utils;
 import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities;
@@ -193,7 +188,6 @@ import 
org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
 import org.netbeans.modules.refactoring.spi.Transaction;
 import org.netbeans.spi.editor.hints.ErrorDescription;
 import org.netbeans.spi.editor.hints.Fix;
-import org.netbeans.spi.java.hints.JavaFix;
 import org.netbeans.spi.lsp.ErrorProvider;
 import org.openide.cookies.EditorCookie;
 import org.openide.filesystems.FileObject;
@@ -764,139 +758,122 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
         if (doc == null) {
             return CompletableFuture.completedFuture(Collections.emptyList());
         }
-        JavaSource js = JavaSource.forDocument(doc);
-        if (js == null) {
-            return CompletableFuture.completedFuture(Collections.emptyList());
-        }
+
+        Range range = params.getRange();
+        int startOffset = Utils.getOffset(doc, range.getStart());
+        int endOffset = Utils.getOffset(doc, range.getEnd());
+
+        ArrayList<Diagnostic> diagnostics = new 
ArrayList<>(params.getContext().getDiagnostics());
+        diagnostics.addAll(computeDiags(params.getTextDocument().getUri(), 
startOffset, ErrorProvider.Kind.HINTS, documentVersion(doc)));
+
         Map<String, org.netbeans.api.lsp.Diagnostic> id2Errors = (Map<String, 
org.netbeans.api.lsp.Diagnostic>) doc.getProperty("lsp-errors");
         List<Either<Command, CodeAction>> result = new ArrayList<>();
         if (id2Errors != null) {
-        for (Diagnostic diag : params.getContext().getDiagnostics()) {
-            org.netbeans.api.lsp.Diagnostic err = 
id2Errors.get(diag.getCode().getLeft());
+            for (Diagnostic diag : diagnostics) {
+                org.netbeans.api.lsp.Diagnostic err = 
id2Errors.get(diag.getCode().getLeft());
 
-            if (err == null) {
-                client.logMessage(new MessageParams(MessageType.Log, "Cannot 
resolve error, code: " + diag.getCode().getLeft()));
-                continue;
-            }
-
-            for (org.netbeans.api.lsp.CodeAction inputAction : 
err.getActions().computeCodeActions(ex -> client.logMessage(new 
MessageParams(MessageType.Error, ex.getMessage())))) {
-                CodeAction action = new CodeAction(inputAction.getTitle());
-                action.setDiagnostics(Collections.singletonList(diag));
-                action.setKind(CodeActionKind.QuickFix);
-                if (inputAction.getCommand() != null) {
-                    action.setCommand(new 
Command(inputAction.getCommand().getTitle(), 
inputAction.getCommand().getCommand()));
+                if (err == null) {
+                    client.logMessage(new MessageParams(MessageType.Log, 
"Cannot resolve error, code: " + diag.getCode().getLeft()));
+                    continue;
                 }
-                if (inputAction.getEdit() != null) {
-                    org.netbeans.api.lsp.WorkspaceEdit edit = 
inputAction.getEdit();
-                    List<Either<TextDocumentEdit, ResourceOperation>> 
documentChanges = new ArrayList<>();
-                    FileObject file = js.getFileObjects().iterator().next();
-
-                    for (Union2<org.netbeans.api.lsp.TextDocumentEdit, 
org.netbeans.api.lsp.ResourceOperation> parts : edit.getDocumentChanges()) {
-                        if (parts.hasFirst()) {
-                            List<TextEdit> edits = 
parts.first().getEdits().stream().map(te -> new TextEdit(new 
Range(Utils.createPosition(file, te.getStartOffset()), 
Utils.createPosition(file, te.getEndOffset())), 
te.getNewText())).collect(Collectors.toList());
-                            TextDocumentEdit tde = new TextDocumentEdit(new 
VersionedTextDocumentIdentifier(parts.first().getDocument(), -1), edits);
-                            documentChanges.add(Either.forLeft(tde));
-                        } else {
-                            if (parts.second() instanceof 
org.netbeans.api.lsp.ResourceOperation.CreateFile) {
-                                documentChanges.add(Either.forRight(new 
CreateFile(((org.netbeans.api.lsp.ResourceOperation.CreateFile) 
parts.second()).getNewFile())));
-                            } else {
-                                throw new 
IllegalStateException(String.valueOf(parts.second()));
+                org.netbeans.api.lsp.Diagnostic.LazyCodeActions actions = 
err.getActions();
+                if (actions != null) {
+                    for (org.netbeans.api.lsp.CodeAction inputAction : 
actions.computeCodeActions(ex -> client.logMessage(new 
MessageParams(MessageType.Error, ex.getMessage())))) {
+                        CodeAction action = new 
CodeAction(inputAction.getTitle());
+                        action.setDiagnostics(Collections.singletonList(diag));
+                        action.setKind(kind(err.getSeverity()));
+                        if (inputAction.getCommand() != null) {
+                            action.setCommand(new 
Command(inputAction.getCommand().getTitle(), 
inputAction.getCommand().getCommand()));
+                        }
+                        if (inputAction.getEdit() != null) {
+                            org.netbeans.api.lsp.WorkspaceEdit edit = 
inputAction.getEdit();
+                            List<Either<TextDocumentEdit, ResourceOperation>> 
documentChanges = new ArrayList<>();
+                            for (Union2<org.netbeans.api.lsp.TextDocumentEdit, 
org.netbeans.api.lsp.ResourceOperation> parts : edit.getDocumentChanges()) {
+                                if (parts.hasFirst()) {
+                                    String docUri = 
parts.first().getDocument();
+                                    try {
+                                        FileObject file = 
Utils.fromUri(docUri);
+                                        if (file == null) {
+                                            file = 
Utils.fromUri(params.getTextDocument().getUri());
+                                        }
+                                        FileObject fo = file;
+                                        if (fo != null) {
+                                            List<TextEdit> edits = 
parts.first().getEdits().stream().map(te -> new TextEdit(new 
Range(Utils.createPosition(fo, te.getStartOffset()), Utils.createPosition(fo, 
te.getEndOffset())), te.getNewText())).collect(Collectors.toList());
+                                            TextDocumentEdit tde = new 
TextDocumentEdit(new VersionedTextDocumentIdentifier(docUri, -1), edits);
+                                            
documentChanges.add(Either.forLeft(tde));
+                                        }
+                                    } catch (Exception ex) {
+                                        client.logMessage(new 
MessageParams(MessageType.Error, ex.getMessage()));
+                                    }
+                                } else {
+                                    if (parts.second() instanceof 
org.netbeans.api.lsp.ResourceOperation.CreateFile) {
+                                        
documentChanges.add(Either.forRight(new 
CreateFile(((org.netbeans.api.lsp.ResourceOperation.CreateFile) 
parts.second()).getNewFile())));
+                                    } else {
+                                        throw new 
IllegalStateException(String.valueOf(parts.second()));
+                                    }
+                                }
                             }
+
+                            action.setEdit(new WorkspaceEdit(documentChanges));
                         }
+                        result.add(Either.forRight(action));
                     }
-
-                    action.setEdit(new WorkspaceEdit(documentChanges));
                 }
-                result.add(Either.forRight(action));
             }
         }
-        }
 
         try {
-            js.runUserActionTask(cc -> {
-                cc.toPhase(JavaSource.Phase.RESOLVED);
-                //code generators:
-                for (CodeGenerator codeGenerator : 
Lookup.getDefault().lookupAll(CodeGenerator.class)) {
-                    for (CodeAction codeAction : 
codeGenerator.getCodeActions(cc, params)) {
-                        result.add(Either.forRight(codeAction));
+            JavaSource js = JavaSource.forDocument(doc);
+            if (js != null) {
+                js.runUserActionTask(cc -> {
+                    cc.toPhase(JavaSource.Phase.RESOLVED);
+                    //code generators:
+                    for (CodeGenerator codeGenerator : 
Lookup.getDefault().lookupAll(CodeGenerator.class)) {
+                        for (CodeAction codeAction : 
codeGenerator.getCodeActions(cc, params)) {
+                            result.add(Either.forRight(codeAction));
+                        }
                     }
-                }
-                //introduce hints
-                Range range = params.getRange();
-                int startOffset = Utils.getOffset(doc, range.getStart());
-                int endOffset = Utils.getOffset(doc, range.getEnd());
-                if (!range.getStart().equals(range.getEnd())) {
-                    for (ErrorDescription err : IntroduceHint.computeError(cc, 
startOffset, endOffset, new EnumMap<IntroduceKind, Fix>(IntroduceKind.class), 
new EnumMap<IntroduceKind, String>(IntroduceKind.class), new AtomicBoolean())) {
-                        for (Fix fix : err.getFixes().getFixes()) {
-                            if (fix instanceof IntroduceFixBase) {
-                                try {
-                                    ModificationResult changes = 
((IntroduceFixBase) fix).getModificationResult();
-                                    if (changes != null) {
-                                        List<Either<TextDocumentEdit, 
ResourceOperation>> documentChanges = new ArrayList<>();
-                                        Set<? extends FileObject> fos = 
changes.getModifiedFileObjects();
-                                        if (fos.size() == 1) {
-                                            FileObject fileObject = 
fos.iterator().next();
-                                            List<? extends 
ModificationResult.Difference> diffs = changes.getDifferences(fileObject);
-                                            if (diffs != null) {
-                                                List<TextEdit> edits = new 
ArrayList<>();
-                                                for 
(ModificationResult.Difference diff : diffs) {
-                                                    String newText = 
diff.getNewText();
-                                                    edits.add(new TextEdit(new 
Range(Utils.createPosition(fileObject, diff.getStartPosition().getOffset()),
-                                                                               
      Utils.createPosition(fileObject, diff.getEndPosition().getOffset())),
-                                                                           
newText != null ? newText : ""));
+                    //introduce hints
+                    if (!range.getStart().equals(range.getEnd())) {
+                        for (ErrorDescription err : 
IntroduceHint.computeError(cc, startOffset, endOffset, new 
EnumMap<IntroduceKind, Fix>(IntroduceKind.class), new EnumMap<IntroduceKind, 
String>(IntroduceKind.class), new AtomicBoolean())) {
+                            for (Fix fix : err.getFixes().getFixes()) {
+                                if (fix instanceof IntroduceFixBase) {
+                                    try {
+                                        ModificationResult changes = 
((IntroduceFixBase) fix).getModificationResult();
+                                        if (changes != null) {
+                                            List<Either<TextDocumentEdit, 
ResourceOperation>> documentChanges = new ArrayList<>();
+                                            Set<? extends FileObject> fos = 
changes.getModifiedFileObjects();
+                                            if (fos.size() == 1) {
+                                                FileObject fileObject = 
fos.iterator().next();
+                                                List<? extends 
ModificationResult.Difference> diffs = changes.getDifferences(fileObject);
+                                                if (diffs != null) {
+                                                    List<TextEdit> edits = new 
ArrayList<>();
+                                                    for 
(ModificationResult.Difference diff : diffs) {
+                                                        String newText = 
diff.getNewText();
+                                                        edits.add(new 
TextEdit(new Range(Utils.createPosition(fileObject, 
diff.getStartPosition().getOffset()),
+                                                                               
          Utils.createPosition(fileObject, diff.getEndPosition().getOffset())),
+                                                                               
newText != null ? newText : ""));
+                                                    }
+                                                    
documentChanges.add(Either.forLeft(new TextDocumentEdit(new 
VersionedTextDocumentIdentifier(Utils.toUri(fileObject), -1), edits)));
                                                 }
-                                                
documentChanges.add(Either.forLeft(new TextDocumentEdit(new 
VersionedTextDocumentIdentifier(Utils.toUri(fileObject), -1), edits)));
-                                            }
-                                            CodeAction codeAction = new 
CodeAction(fix.getText());
-                                            
codeAction.setKind(CodeActionKind.RefactorExtract);
-                                            codeAction.setEdit(new 
WorkspaceEdit(documentChanges));
-                                            int renameOffset = 
((IntroduceFixBase) fix).getNameOffset(changes);
-                                            if (renameOffset >= 0) {
-                                                codeAction.setCommand(new 
Command("Rename", "java.rename.element.at", 
Collections.singletonList(renameOffset)));
+                                                CodeAction codeAction = new 
CodeAction(fix.getText());
+                                                
codeAction.setKind(CodeActionKind.RefactorExtract);
+                                                codeAction.setEdit(new 
WorkspaceEdit(documentChanges));
+                                                int renameOffset = 
((IntroduceFixBase) fix).getNameOffset(changes);
+                                                if (renameOffset >= 0) {
+                                                    codeAction.setCommand(new 
Command("Rename", "java.rename.element.at", 
Collections.singletonList(renameOffset)));
+                                                }
+                                                
result.add(Either.forRight(codeAction));
                                             }
-                                            
result.add(Either.forRight(codeAction));
                                         }
+                                    } catch 
(GeneratorUtils.DuplicateMemberException dme) {
                                     }
-                                } catch 
(GeneratorUtils.DuplicateMemberException dme) {
                                 }
                             }
                         }
                     }
-                }
-                HintsInvoker.join(new 
HintsInvoker(HintsSettings.getGlobalSettings(), startOffset, endOffset, new 
AtomicBoolean())
-                        // compute nonrecursive hints
-                        .computeHints(cc, new 
TreePath(cc.getCompilationUnit()), false, 
RulesManager.getInstance().readHints(cc, null, new 
AtomicBoolean()).values().stream().collect(ArrayList::new, ArrayList::addAll, 
ArrayList::addAll), new ArrayList<MessageImpl>()))
-                        .stream().forEach(err -> {
-                            // check if cursor/selection is in errors range
-                            if (err.getRange().getBegin().getOffset() <= 
startOffset && err.getRange().getEnd().getOffset() >= endOffset) {
-                                for (Fix f : err.getFixes().getFixes()) {
-                                    if (f instanceof JavaFixImpl) {
-                                        try {
-                                            JavaFix jf = ((JavaFixImpl) f).jf;
-                                            List<TextEdit> edits = 
modify2TextEdits(js, wc -> {
-                                                
wc.toPhase(JavaSource.Phase.RESOLVED);
-                                                Map<FileObject, byte[]> 
resourceContentChanges = new HashMap<FileObject, byte[]>();
-                                                
JavaFixImpl.Accessor.INSTANCE.process(jf, wc, true, resourceContentChanges, 
/*Ignored in editor:*/ new ArrayList<>());
-                                            });
-                                            // check for edit presence
-                                            if (edits.size() > 0 && 
!containsEdit(result, edits)) {
-                                                TextDocumentEdit te = new 
TextDocumentEdit(new 
VersionedTextDocumentIdentifier(params.getTextDocument().getUri(), -1), edits);
-                                                CodeAction action = new 
CodeAction(f.getText());
-                                                
action.setKind(CodeActionKind.RefactorRewrite);
-                                                action.setEdit(new 
WorkspaceEdit(Collections.singletonList(Either.forLeft(te))));
-                                                
result.add(Either.forRight(action));
-                                                // add only first relevant fix
-                                                break;
-                                            }
-                                        } catch (IOException ex) {
-                                            //TODO: include stack trace:
-                                            client.logMessage(new 
MessageParams(MessageType.Error, ex.getMessage()));
-                                        }
-                                    }
-                                }
-                            }
-                        });
-            }, true);
+                }, true);
+            }
         } catch (IOException ex) {
             //TODO: include stack trace:
             client.logMessage(new MessageParams(MessageType.Error, 
ex.getMessage()));
@@ -905,20 +882,6 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
         return CompletableFuture.completedFuture(result);
     }
 
-    private boolean containsEdit(List<Either<Command, CodeAction>> results, 
List<TextEdit> edit) {
-        for (Either<Command, CodeAction> result : results) {
-            List<Either<TextDocumentEdit, ResourceOperation>> documentChanges 
= result.getRight().getEdit().getDocumentChanges();
-            if (documentChanges != null) {
-                for (Either<TextDocumentEdit, ResourceOperation> change : 
documentChanges) {
-                    if (change.getLeft().getEdits().equals(edit)) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
     private ConcurrentHashMap<String, Boolean> upToDateTests = new 
ConcurrentHashMap<>();
 
     @Override
@@ -1433,15 +1396,15 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
             return BACKGROUND_TASKS.create(() -> {
                 Document originalDoc = openedDocuments.get(uri);
                 long originalVersion = documentVersion(originalDoc);
-                List<Diagnostic> errorDiags = computeDiags(u, 
ErrorProvider.Kind.ERRORS, originalVersion);
+                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, 
ErrorProvider.Kind.HINTS, originalVersion);
+                        List<Diagnostic> hintDiags = computeDiags(u, -1, 
ErrorProvider.Kind.HINTS, originalVersion);
                         Document doc = openedDocuments.get(uri);
                         if (documentVersion(doc) == originalVersion) {
                             publishDiagnostics(uri, hintDiags);
-                        }
+                }
                     }).schedule(DELAY);
                 }
             });
@@ -1450,7 +1413,7 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
 
     private static final int DELAY = 500;
 
-    private List<Diagnostic> computeDiags(String uri, ErrorProvider.Kind 
errorKind, long originalVersion) {
+    private List<Diagnostic> computeDiags(String uri, int offset, 
ErrorProvider.Kind errorKind, long originalVersion) {
         List<Diagnostic> result = new ArrayList<>();
         FileObject file = fromURI(uri);
         if (file == null) {
@@ -1466,7 +1429,7 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
                                                     
.lookup(ErrorProvider.class);
             List<? extends org.netbeans.api.lsp.Diagnostic> errors;
             if (errorProvider != null) {
-                ErrorProvider.Context context = new 
ErrorProvider.Context(file, errorKind);
+                ErrorProvider.Context context = new 
ErrorProvider.Context(file, offset, errorKind);
                 class CancelListener implements DocumentListener {
                     @Override
                     public void insertUpdate(DocumentEvent e) {
@@ -1505,7 +1468,9 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
                 String id = err.getCode();
                 id2Errors.put(id, err);
             }
-            doc.putProperty("lsp-errors-" + keyPrefix, id2Errors);
+            if (offset < 0) {
+                doc.putProperty("lsp-errors-" + keyPrefix, id2Errors);
+            }
             Map<String, org.netbeans.api.lsp.Diagnostic> mergedId2Errors = new 
HashMap<>();
             for (String k : ERROR_KEYS) {
                 Map<String, org.netbeans.api.lsp.Diagnostic> prevErrors = 
(Map<String, org.netbeans.api.lsp.Diagnostic>) doc.getProperty("lsp-errors-" + 
k);
@@ -1513,7 +1478,7 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
                     mergedId2Errors.putAll(prevErrors);
                 }
             }
-            for (Entry<String, org.netbeans.api.lsp.Diagnostic> id2Error : 
mergedId2Errors.entrySet()) {
+            for (Entry<String, org.netbeans.api.lsp.Diagnostic> id2Error : 
(offset < 0 ? mergedId2Errors : id2Errors).entrySet()) {
                 org.netbeans.api.lsp.Diagnostic err = id2Error.getValue();
                 Diagnostic diag = new Diagnostic(new 
Range(Utils.createPosition(file, err.getStartPosition().getOffset()),
                                                            
Utils.createPosition(file, err.getEndPosition().getOffset())),
@@ -1528,6 +1493,9 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
                 diag.setCode(id2Error.getKey());
                 result.add(diag);
             }
+            if (offset >= 0) {
+                mergedId2Errors.putAll(id2Errors);
+            }
             doc.putProperty("lsp-errors", mergedId2Errors);
         } catch (IOException ex) {
             throw new IllegalStateException(ex);
@@ -1539,6 +1507,15 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
         return errorKind.name().toLowerCase(Locale.ROOT);
     }
 
+    private String kind(org.netbeans.api.lsp.Diagnostic.Severity severity) {
+        switch (severity) {
+            case Hint:
+                return CodeActionKind.RefactorRewrite;
+            default:
+                return CodeActionKind.QuickFix;
+        }
+    }
+
     private FileObject fromURI(String uri) {
         return fromURI(uri, false);
     }
diff --git a/java/java.lsp.server/vscode/package-lock.json 
b/java/java.lsp.server/vscode/package-lock.json
index 3775aa2..df54329 100644
--- a/java/java.lsp.server/vscode/package-lock.json
+++ b/java/java.lsp.server/vscode/package-lock.json
@@ -365,9 +365,9 @@
                        }
                },
                "glob-parent": {
-                       "version": "5.1.1",
-                       "resolved": 
"https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz";,
-                       "integrity": 
"sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+                       "version": "5.1.2",
+                       "resolved": 
"https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz";,
+                       "integrity": 
"sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
                        "dev": true,
                        "requires": {
                                "is-glob": "^4.0.1"
@@ -553,9 +553,9 @@
                        }
                },
                "lodash": {
-                       "version": "4.17.19",
-                       "resolved": 
"https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz";,
-                       "integrity": 
"sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
+                       "version": "4.17.21",
+                       "resolved": 
"https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz";,
+                       "integrity": 
"sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
                        "dev": true
                },
                "log-symbols": {
diff --git a/java/java.lsp.server/vscode/package.json 
b/java/java.lsp.server/vscode/package.json
index 6a1b0fe..517dfb2 100644
--- a/java/java.lsp.server/vscode/package.json
+++ b/java/java.lsp.server/vscode/package.json
@@ -367,5 +367,8 @@
                "vscode-languageclient": "6.1.3",
                "vscode-test-adapter-api": "^1.9.0",
                "vscode-test-adapter-util": "^0.7.1"
-       }
+       },
+       "extensionDependencies": [
+               "hbenl.vscode-test-explorer"
+       ]
 }

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to