You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by db...@apache.org on 2021/11/29 15:48:58 UTC
[netbeans] branch master updated: Micronaut data finder methods code completion (#3333)
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 c73b134 Micronaut data finder methods code completion (#3333)
c73b134 is described below
commit c73b134cf520288a4ee5101885fb4039253ec496
Author: Dusan Balek <du...@oracle.com>
AuthorDate: Mon Nov 29 16:48:37 2021 +0100
Micronaut data finder methods code completion (#3333)
---
enterprise/micronaut/nbproject/project.xml | 11 +-
.../MicronautConfigCompletionCollector.java | 4 +-
.../completion/MicronautConfigCompletionItem.java | 329 ----------------
.../MicronautConfigCompletionProvider.java | 162 +++++++-
.../MicronautDataCompletionCollector.java | 53 +++
.../MicronautDataCompletionProvider.java | 103 +++++
.../completion/MicronautDataCompletionTask.java | 434 +++++++++++++++++++++
.../newproject/MicronautProjectWizardIterator.java | 8 +-
.../refactor/MicronautRefactoringFactory.java | 4 +-
ide/editor.completion/apichanges.xml | 15 +
ide/editor.completion/nbproject/project.properties | 2 +-
.../CompletionSupportSpiPackageAccessor.java | 41 ++
.../editor/completion/SimpleCompletionItem.java | 172 ++++++++
.../completion/support/CompletionUtilities.java | 228 ++++++++++-
java/java.lsp.server/vscode/src/extension.ts | 2 +-
15 files changed, 1222 insertions(+), 346 deletions(-)
diff --git a/enterprise/micronaut/nbproject/project.xml b/enterprise/micronaut/nbproject/project.xml
index b307a94..61dc5d8 100644
--- a/enterprise/micronaut/nbproject/project.xml
+++ b/enterprise/micronaut/nbproject/project.xml
@@ -117,7 +117,7 @@
<compile-dependency/>
<run-dependency>
<release-version>1</release-version>
- <specification-version>1.56</specification-version>
+ <specification-version>1.60</specification-version>
</run-dependency>
</dependency>
<dependency>
@@ -165,6 +165,15 @@
</run-dependency>
</dependency>
<dependency>
+ <code-name-base>org.netbeans.modules.java.lexer</code-name-base>
+ <build-prerequisite/>
+ <compile-dependency/>
+ <run-dependency>
+ <release-version>1</release-version>
+ <specification-version>1.50</specification-version>
+ </run-dependency>
+ </dependency>
+ <dependency>
<code-name-base>org.netbeans.modules.java.project</code-name-base>
<build-prerequisite/>
<compile-dependency/>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java
index 8a96082..06d40ba 100644
--- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java
@@ -77,7 +77,7 @@ public class MicronautConfigCompletionCollector implements CompletionCollector {
ArrayUtilities.appendSpaces(insertText, indentLevelSize);
}
}
- return CompletionCollector.newBuilder(propName).kind(Completion.Kind.Property).sortText(String.format("%4d%s", 10, propName))
+ return CompletionCollector.newBuilder(propName).kind(Completion.Kind.Property).sortText(String.format("%04d%s", 10, propName))
.insertText(insertText.toString()).insertTextFormat(insertTextFormat).build();
}
@@ -112,7 +112,7 @@ public class MicronautConfigCompletionCollector implements CompletionCollector {
}
}
CompletionCollector.Builder builder = CompletionCollector.newBuilder(property.getId()).kind(Completion.Kind.Property)
- .sortText(String.format("%4d%s", property.isDeprecated() ? 30 : 20, property.getId())).insertText(insertText.toString())
+ .sortText(String.format("%04d%s", property.isDeprecated() ? 30 : 20, property.getId())).insertText(insertText.toString())
.insertTextFormat(insertTextFormat).documentation(new MicronautConfigDocumentation(property).getText());
if (property.isDeprecated()) {
builder.addTag(Completion.Tag.Deprecated);
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionItem.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionItem.java
deleted file mode 100644
index 1a4e71d..0000000
--- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionItem.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * 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.micronaut.completion;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics;
-import java.awt.event.InputEvent;
-import java.awt.event.KeyEvent;
-import java.util.regex.Pattern;
-import javax.swing.ImageIcon;
-import javax.swing.text.Document;
-import javax.swing.text.JTextComponent;
-import org.netbeans.api.editor.completion.Completion;
-import org.netbeans.api.editor.document.LineDocument;
-import org.netbeans.api.editor.document.LineDocumentUtils;
-import org.netbeans.lib.editor.codetemplates.api.CodeTemplateManager;
-import org.netbeans.lib.editor.util.ArrayUtilities;
-import org.netbeans.modules.editor.indent.api.IndentUtils;
-import org.netbeans.spi.editor.completion.CompletionItem;
-import org.netbeans.spi.editor.completion.CompletionTask;
-import org.netbeans.spi.editor.completion.support.CompletionUtilities;
-import org.netbeans.swing.plaf.LFCustoms;
-import org.openide.util.Exceptions;
-import org.openide.util.ImageUtilities;
-import org.openide.xml.XMLUtil;
-import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
-
-/**
- *
- * @author Dusan Balek
- */
-public abstract class MicronautConfigCompletionItem implements CompletionItem {
-
- public static final String PROPERTY_NAME_COLOR = getHTMLColor(64, 64, 217);
- private static final String ICON = "org/netbeans/modules/editor/resources/completion/field_16.png"; //NOI18N
-
- public static MicronautConfigCompletionItem createTopLevelPropertyItem(String propName, int offset, int baseIndent, int indentLevelSize) {
- return new TopLevelItem(propName, offset, baseIndent, indentLevelSize);
- }
-
- public static MicronautConfigCompletionItem createPropertyItem(ConfigurationMetadataProperty property, int offset, int baseIndent, int indentLevelSize, int idx) {
- return new PropertyItem(property, offset, baseIndent, indentLevelSize, idx);
- }
-
- protected final String propName;
- protected final int offset;
- protected final int baseIndent;
- protected final int indentLevelSize;
- private ImageIcon icon;
-
- private MicronautConfigCompletionItem(String propName, int offset, int baseIndent, int indentLevelSize) {
- this.propName = propName;
- this.offset = offset;
- this.baseIndent = baseIndent;
- this.indentLevelSize = indentLevelSize;
- }
-
- @Override
- public void defaultAction(JTextComponent component) {
- if (component != null) {
- Completion.get().hideDocumentation();
- Completion.get().hideCompletion();
- process(component, false);
- }
- }
-
- @Override
- public void processKeyEvent(KeyEvent evt) {
- if (evt.getID() == KeyEvent.KEY_PRESSED && evt.getKeyCode() == KeyEvent.VK_ENTER && (evt.getModifiers() & InputEvent.CTRL_MASK) > 0) {
- JTextComponent component = (JTextComponent)evt.getSource();
- Completion.get().hideDocumentation();
- Completion.get().hideCompletion();
- process(component, true);
- evt.consume();
- }
- }
-
- @Override
- public int getPreferredWidth(Graphics g, Font defaultFont) {
- return CompletionUtilities.getPreferredWidth(getLeftHtmlText(), getRightHtmlText(), g, defaultFont);
- }
-
- @Override
- public void render(Graphics g, Font defaultFont, Color defaultColor, Color backgroundColor, int width, int height, boolean selected) {
- CompletionUtilities.renderHtml(getIcon(), getLeftHtmlText(), getRightHtmlText(), g, defaultFont, defaultColor, width, height, selected);
- }
-
- @Override
- public CompletionTask createDocumentationTask() {
- return null;
- }
-
- @Override
- public CompletionTask createToolTipTask() {
- return null;
- }
-
- @Override
- public boolean instantSubstitution(JTextComponent component) {
- return false;
- }
-
- @Override
- public CharSequence getSortText() {
- return propName;
- }
-
- @Override
- public CharSequence getInsertPrefix() {
- return propName;
- }
-
- protected String getLeftHtmlText() {
- return null;
- }
-
- protected String getRightHtmlText() {
- return null;
- }
-
- protected ImageIcon getIcon() {
- if (icon == null) {
- icon = ImageUtilities.loadImageIcon(ICON, false);
- }
- return icon;
- }
-
- protected abstract void process(JTextComponent component, boolean overwrite);
-
- private static final class TopLevelItem extends MicronautConfigCompletionItem {
-
- private TopLevelItem(String propName, int offset, int baseIndent, int indentLevelSize) {
- super(propName, offset, baseIndent, indentLevelSize);
- }
-
- @Override
- public int getSortPriority() {
- return 10;
- }
-
- @Override
- protected String getLeftHtmlText() {
- return PROPERTY_NAME_COLOR + "<b>" + propName + "</b></font>";
- }
-
- @Override
- protected void process(JTextComponent component, boolean overwrite) {
- try {
- Document doc = component.getDocument();
- LineDocument lineDocument = LineDocumentUtils.as(doc, LineDocument.class);
- if (lineDocument != null) {
- int caretOffset = component.getCaretPosition();
- int end = LineDocumentUtils.getWordEnd(lineDocument, caretOffset);
- if (overwrite && LineDocumentUtils.getWordStart(lineDocument, end) == offset) {
- String textEnd = doc.getText(end, 1);
- if (baseIndent < 0 && textEnd.endsWith(".") || textEnd.endsWith(":")) {
- end++;
- }
- doc.remove(offset, Math.max(caretOffset, end) - offset);
- } else if (offset < caretOffset) {
- doc.remove(offset, caretOffset - offset);
- }
- StringBuilder sb = new StringBuilder();
- if (baseIndent < 0) {
- sb.append("*".equals(propName) ? "${PAR#1 default=\"\"}" : propName).append(".${cursor completionInvoke}");
- } else {
- int lineStart = LineDocumentUtils.getLineStart(lineDocument, caretOffset);
- int lineIndent = IndentUtils.lineIndent(doc, lineStart);
- ArrayUtilities.appendSpaces(sb, baseIndent - lineIndent);
- sb.append("*".equals(propName) ? "${PAR#1 default=\"\"}" : propName).append(":\n");
- ArrayUtilities.appendSpaces(sb, baseIndent + indentLevelSize);
- sb.append("${cursor completionInvoke}");
- }
- CodeTemplateManager.get(doc).createTemporary(sb.toString()).insert(component);
- }
- } catch (Exception ex) {
- Exceptions.printStackTrace(ex);
- }
- }
- }
-
- private static final class PropertyItem extends MicronautConfigCompletionItem {
-
- private static final Pattern FQN = Pattern.compile("(\\w+\\.)+(\\w+)");
- private final ConfigurationMetadataProperty property;
- private final int idx;
- private String left;
- private String right;
-
- private PropertyItem(ConfigurationMetadataProperty property, int offset, int baseIndent, int indentLevelSize, int idx) {
- super(property.getId(), offset, baseIndent, indentLevelSize);
- this.property = property;
- this.idx = idx;
- }
-
- @Override
- public CompletionTask createDocumentationTask() {
- return MicronautConfigCompletionProvider.createDocTask(property);
- }
-
- @Override
- public int getSortPriority() {
- return property.isDeprecated() ? 30 : 20;
- }
-
- @Override
- protected String getLeftHtmlText() {
- if (left == null) {
- if (property.isDeprecated()) {
- left = PROPERTY_NAME_COLOR + "<s>" + propName + "</s></font>";
- } else {
- left = PROPERTY_NAME_COLOR + propName + "</font>";
- }
- }
- return left;
- }
-
- @Override
- protected String getRightHtmlText() {
- if (right == null) {
- String type = property.getType();
- right = type != null ? escape(FQN.matcher(type).replaceAll("$2")) : "";
- }
- return right;
- }
-
- @Override
- protected void process(JTextComponent component, boolean overwrite) {
- try {
- Document doc = component.getDocument();
- LineDocument lineDocument = LineDocumentUtils.as(doc, LineDocument.class);
- if (lineDocument != null) {
- int caretOffset = component.getCaretPosition();
- int end = LineDocumentUtils.getWordEnd(lineDocument, caretOffset);
- if (overwrite && LineDocumentUtils.getWordStart(lineDocument, end) == offset) {
- String textEnd = doc.getText(end, 1);
- while(baseIndent < 0 && textEnd.endsWith(".")) {
- end = LineDocumentUtils.getWordEnd(lineDocument, end + 1);
- textEnd = doc.getText(end, 1);
- }
- if (baseIndent < 0 && textEnd.endsWith("=") || textEnd.endsWith(":")) {
- end++;
- }
- doc.remove(offset, Math.max(caretOffset, end) - offset);
- } else if (offset < caretOffset) {
- doc.remove(offset, caretOffset - offset);
- }
- StringBuilder sb = new StringBuilder();
- String name = propName.substring(idx);
- String[] parts = name.split("\\.");
- if (baseIndent < 0) {
- int num = 1;
- for (int i = 0; i < parts.length; i++) {
- String part = parts[i];
- if ("*".equals(part)) {
- sb.append("${PAR#" + num++ + " default=\"\"}");
- } else {
- sb.append(part);
- }
- if (i < parts.length - 1) {
- sb.append(".");
- } else {
- sb.append("=${cursor}");
- }
- }
- } else {
- int lineStart = LineDocumentUtils.getLineStart(lineDocument, caretOffset);
- int lineIndent = IndentUtils.lineIndent(doc, lineStart);
- ArrayUtilities.appendSpaces(sb, baseIndent - lineIndent);
- int indent = baseIndent;
- int num = 1;
- for (int i = 0; i < parts.length; i++) {
- String part = parts[i];
- if ("*".equals(part)) {
- sb.append("${PAR#" + num++ + " default=\"\"}");
- } else {
- sb.append(part);
- }
- if (i < parts.length - 1) {
- sb.append(":\n");
- ArrayUtilities.appendSpaces(sb, (indent = indent + indentLevelSize));
- } else {
- sb.append(": ${cursor}");
- }
- }
- }
- CodeTemplateManager.get(doc).createTemporary(sb.toString()).insert(component);
- }
- } catch (Exception ex) {
- Exceptions.printStackTrace(ex);
- }
- }
- }
-
- private static String getHTMLColor(int r, int g, int b) {
- Color c = LFCustoms.shiftColor(new Color(r, g, b));
- return "<font color=#" //NOI18N
- + LFCustoms.getHexString(c.getRed())
- + LFCustoms.getHexString(c.getGreen())
- + LFCustoms.getHexString(c.getBlue())
- + ">"; //NOI18N
- }
-
- private static String escape(String s) {
- if (s != null) {
- try {
- return XMLUtil.toAttributeValue(s);
- } catch (Exception ex) {}
- }
- return s;
- }
-}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java
index d4f6f02..92456a7 100644
--- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java
@@ -18,20 +18,33 @@
*/
package org.netbeans.modules.micronaut.completion;
+import java.awt.Color;
+import java.util.regex.Pattern;
+import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import org.netbeans.api.editor.document.EditorDocumentUtils;
+import org.netbeans.api.editor.document.LineDocument;
+import org.netbeans.api.editor.document.LineDocumentUtils;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
+import org.netbeans.lib.editor.codetemplates.api.CodeTemplateManager;
+import org.netbeans.lib.editor.util.ArrayUtilities;
+import org.netbeans.modules.editor.indent.api.IndentUtils;
import org.netbeans.modules.micronaut.MicronautConfigProperties;
import org.netbeans.modules.micronaut.MicronautConfigUtilities;
+import org.netbeans.spi.editor.completion.CompletionItem;
import org.netbeans.spi.editor.completion.CompletionProvider;
import org.netbeans.spi.editor.completion.CompletionResultSet;
import org.netbeans.spi.editor.completion.CompletionTask;
import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery;
import org.netbeans.spi.editor.completion.support.AsyncCompletionTask;
+import org.netbeans.spi.editor.completion.support.CompletionUtilities;
+import org.netbeans.swing.plaf.LFCustoms;
import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
+import org.openide.xml.XMLUtil;
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
/**
@@ -40,6 +53,8 @@ import org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope
*/
public class MicronautConfigCompletionProvider implements CompletionProvider {
+ public static final String PROPERTY_NAME_COLOR = getHTMLColor(64, 64, 217);
+
@MimeRegistration(mimeType = "text/x-yaml", service = CompletionProvider.class)
public static MicronautConfigCompletionProvider createYamlProvider() {
return new MicronautConfigCompletionProvider();
@@ -75,12 +90,29 @@ public class MicronautConfigCompletionProvider implements CompletionProvider {
return 0;
}
- static CompletionTask createDocTask(ConfigurationMetadataProperty element) {
- return new AsyncCompletionTask(new MicronautConfigDocumentationQuery(element));
+ private static String getHTMLColor(int r, int g, int b) {
+ Color c = LFCustoms.shiftColor(new Color(r, g, b));
+ return "<font color=#" //NOI18N
+ + LFCustoms.getHexString(c.getRed())
+ + LFCustoms.getHexString(c.getGreen())
+ + LFCustoms.getHexString(c.getBlue())
+ + ">"; //NOI18N
+ }
+
+ private static String escape(String s) {
+ if (s != null) {
+ try {
+ return XMLUtil.toAttributeValue(s);
+ } catch (Exception ex) {}
+ }
+ return s;
}
private static class MicronautConfigCompletionQuery extends AsyncCompletionQuery {
+ private static final String ICON = "org/netbeans/modules/editor/resources/completion/field_16.png"; //NOI18N
+ private static final Pattern FQN = Pattern.compile("(\\w+\\.)+(\\w+)");
+
private final Project project;
public MicronautConfigCompletionQuery(Project project) {
@@ -89,17 +121,133 @@ public class MicronautConfigCompletionProvider implements CompletionProvider {
@Override
protected void query(CompletionResultSet resultSet, Document doc, int caretOffset) {
- resultSet.addAllItems(new MicronautConfigCompletionTask().query(doc, caretOffset, project, new MicronautConfigCompletionTask.ItemFactory<MicronautConfigCompletionItem>() {
+ resultSet.addAllItems(new MicronautConfigCompletionTask().query(doc, caretOffset, project, new MicronautConfigCompletionTask.ItemFactory<CompletionItem>() {
@Override
- public MicronautConfigCompletionItem createPropertyItem(ConfigurationMetadataProperty property, int offset, int baseIndent, int indentLevelSize, int idx) {
+ public CompletionItem createPropertyItem(ConfigurationMetadataProperty property, int offset, int baseIndent, int indentLevelSize, int idx) {
resultSet.setAnchorOffset(offset);
- return MicronautConfigCompletionItem.createPropertyItem(property, offset, baseIndent, indentLevelSize, idx);
+ String propName = property.getId();
+ String propType = property.getType();
+ CompletionUtilities.CompletionItemBuilder builder = CompletionUtilities.newCompletionItemBuilder(propName)
+ .iconResource(ICON)
+ .leftHtmlText(property.isDeprecated()
+ ? PROPERTY_NAME_COLOR + "<s>" + propName + "</s></font>"
+ : PROPERTY_NAME_COLOR + propName + "</font>")
+ .sortPriority(property.isDeprecated() ? 30 : 20)
+ .documentationTask(() -> {
+ return new AsyncCompletionTask(new MicronautConfigDocumentationQuery(property));
+ })
+ .onSelect(ctx -> {
+ try {
+ Document doc = ctx.getComponent().getDocument();
+ LineDocument lineDocument = LineDocumentUtils.as(doc, LineDocument.class);
+ if (lineDocument != null) {
+ int caretOffset = ctx.getComponent().getCaretPosition();
+ int end = LineDocumentUtils.getWordEnd(lineDocument, caretOffset);
+ if (ctx.isOverwrite() && LineDocumentUtils.getWordStart(lineDocument, end) == offset) {
+ String textEnd = doc.getText(end, 1);
+ while(baseIndent < 0 && textEnd.endsWith(".")) {
+ end = LineDocumentUtils.getWordEnd(lineDocument, end + 1);
+ textEnd = doc.getText(end, 1);
+ }
+ if (baseIndent < 0 && textEnd.endsWith("=") || textEnd.endsWith(":")) {
+ end++;
+ }
+ doc.remove(offset, Math.max(caretOffset, end) - offset);
+ } else if (offset < caretOffset) {
+ doc.remove(offset, caretOffset - offset);
+ }
+ StringBuilder sb = new StringBuilder();
+ String name = propName.substring(idx);
+ String[] parts = name.split("\\.");
+ if (baseIndent < 0) {
+ int num = 1;
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ if ("*".equals(part)) {
+ sb.append("${PAR#" + num++ + " default=\"\"}");
+ } else {
+ sb.append(part);
+ }
+ if (i < parts.length - 1) {
+ sb.append(".");
+ } else {
+ sb.append("=${cursor}");
+ }
+ }
+ } else {
+ int lineStart = LineDocumentUtils.getLineStart(lineDocument, caretOffset);
+ int lineIndent = IndentUtils.lineIndent(doc, lineStart);
+ ArrayUtilities.appendSpaces(sb, baseIndent - lineIndent);
+ int indent = baseIndent;
+ int num = 1;
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ if ("*".equals(part)) {
+ sb.append("${PAR#" + num++ + " default=\"\"}");
+ } else {
+ sb.append(part);
+ }
+ if (i < parts.length - 1) {
+ sb.append(":\n");
+ ArrayUtilities.appendSpaces(sb, (indent = indent + indentLevelSize));
+ } else {
+ sb.append(": ${cursor}");
+ }
+ }
+ }
+ CodeTemplateManager.get(doc).createTemporary(sb.toString()).insert(ctx.getComponent());
+ }
+ } catch (BadLocationException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ });
+ if (propType != null) {
+ builder.rightHtmlText(escape(FQN.matcher(propType).replaceAll("$2")));
+ }
+ return builder.build();
}
@Override
- public MicronautConfigCompletionItem createTopLevelPropertyItem(String propName, int offset, int baseIndent, int indentLevelSize) {
+ public CompletionItem createTopLevelPropertyItem(String propName, int offset, int baseIndent, int indentLevelSize) {
resultSet.setAnchorOffset(offset);
- return MicronautConfigCompletionItem.createTopLevelPropertyItem(propName, offset, baseIndent, indentLevelSize);
+ return CompletionUtilities.newCompletionItemBuilder(propName)
+ .iconResource(ICON)
+ .leftHtmlText(PROPERTY_NAME_COLOR + "<b>" + propName + "</b></font>")
+ .sortPriority(10)
+ .onSelect(ctx -> {
+ try {
+ Document doc = ctx.getComponent().getDocument();
+ LineDocument lineDocument = LineDocumentUtils.as(doc, LineDocument.class);
+ if (lineDocument != null) {
+ int caretOffset = ctx.getComponent().getCaretPosition();
+ int end = LineDocumentUtils.getWordEnd(lineDocument, caretOffset);
+ if (ctx.isOverwrite() && LineDocumentUtils.getWordStart(lineDocument, end) == offset) {
+ String textEnd = doc.getText(end, 1);
+ if (baseIndent < 0 && textEnd.endsWith(".") || textEnd.endsWith(":")) {
+ end++;
+ }
+ doc.remove(offset, Math.max(caretOffset, end) - offset);
+ } else if (offset < caretOffset) {
+ doc.remove(offset, caretOffset - offset);
+ }
+ StringBuilder sb = new StringBuilder();
+ if (baseIndent < 0) {
+ sb.append("*".equals(propName) ? "${PAR#1 default=\"\"}" : propName).append(".${cursor completionInvoke}");
+ } else {
+ int lineStart = LineDocumentUtils.getLineStart(lineDocument, caretOffset);
+ int lineIndent = IndentUtils.lineIndent(doc, lineStart);
+ ArrayUtilities.appendSpaces(sb, baseIndent - lineIndent);
+ sb.append("*".equals(propName) ? "${PAR#1 default=\"\"}" : propName).append(":\n");
+ ArrayUtilities.appendSpaces(sb, baseIndent + indentLevelSize);
+ sb.append("${cursor completionInvoke}");
+ }
+ CodeTemplateManager.get(doc).createTemporary(sb.toString()).insert(ctx.getComponent());
+ }
+ } catch (BadLocationException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ })
+ .build();
}
}));
resultSet.finish();
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java
new file mode 100644
index 0000000..3f5abd0
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.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.micronaut.completion;
+
+import java.util.function.Consumer;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.lsp.Completion;
+import org.netbeans.spi.lsp.CompletionCollector;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+@MimeRegistration(mimeType = "text/x-java", service = CompletionCollector.class)
+public class MicronautDataCompletionCollector implements CompletionCollector {
+
+ @Override
+ public boolean collectCompletions(Document doc, int offset, Completion.Context context, Consumer<Completion> consumer) {
+ new MicronautDataCompletionTask().query(doc, offset, new MicronautDataCompletionTask.ItemFactory<Completion>() {
+ @Override
+ public Completion createFinderMethodItem(String name, String returnType, int offset) {
+ Builder builder = CompletionCollector.newBuilder(name).kind(Completion.Kind.Method).sortText(String.format("%04d%s", 10, name));
+ if (returnType != null) {
+ builder.insertText(new StringBuilder("${1:").append(returnType).append("} ").append(name).append("$0()").toString());
+ builder.insertTextFormat(Completion.TextFormat.Snippet);
+ }
+ return builder.build();
+ }
+ @Override
+ public Completion createFinderMethodNameItem(String prefix, String name, int offset) {
+ return CompletionCollector.newBuilder(prefix + name).kind(Completion.Kind.Method).sortText(String.format("%04d%s", 10, name)).build();
+ }
+ }).stream().forEach(consumer);
+ return true;
+ }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionProvider.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionProvider.java
new file mode 100644
index 0000000..074657f
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionProvider.java
@@ -0,0 +1,103 @@
+/*
+ * 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.micronaut.completion;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.lib.editor.codetemplates.api.CodeTemplateManager;
+import org.netbeans.spi.editor.completion.CompletionItem;
+import org.netbeans.spi.editor.completion.CompletionProvider;
+import org.netbeans.spi.editor.completion.CompletionResultSet;
+import org.netbeans.spi.editor.completion.CompletionTask;
+import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery;
+import org.netbeans.spi.editor.completion.support.AsyncCompletionTask;
+import org.netbeans.spi.editor.completion.support.CompletionUtilities;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+@MimeRegistration(mimeType = "text/x-java", service = CompletionProvider.class, position = 250)
+public final class MicronautDataCompletionProvider implements CompletionProvider {
+
+ @Override
+ public CompletionTask createTask(int queryType, JTextComponent component) {
+ switch (queryType) {
+ case COMPLETION_ALL_QUERY_TYPE:
+ case COMPLETION_QUERY_TYPE:
+ return new AsyncCompletionTask(new MicronautDataCompletionQuery(), component);
+ }
+ return null;
+ }
+
+ @Override
+ public int getAutoQueryTypes(JTextComponent component, String typedText) {
+ return 0;
+ }
+
+ private static class MicronautDataCompletionQuery extends AsyncCompletionQuery {
+
+ private static final String ICON = "org/netbeans/modules/micronaut/resources/micronaut.png";
+
+ @Override
+ protected void query(CompletionResultSet resultSet, Document doc, int caretOffset) {
+ MicronautDataCompletionTask task = new MicronautDataCompletionTask();
+ resultSet.addAllItems(task.query(doc, caretOffset, new MicronautDataCompletionTask.ItemFactory<CompletionItem>() {
+ @Override
+ public CompletionItem createFinderMethodItem(String name, String returnType, int offset) {
+ CompletionUtilities.CompletionItemBuilder builder = CompletionUtilities.newCompletionItemBuilder(name)
+ .iconResource(ICON)
+ .leftHtmlText("<b>" + name + "</b>")
+ .sortPriority(10);
+ if (returnType != null) {
+ builder.onSelect(ctx -> {
+ final Document doc = ctx.getComponent().getDocument();
+ try {
+ doc.remove(offset, ctx.getComponent().getCaretPosition() - offset);
+ } catch (BadLocationException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ String template = "${PAR#1 default=\"" + returnType + "\"} " + name + "${cursor completionInvoke}()";
+ CodeTemplateManager.get(doc).createTemporary(template).insert(ctx.getComponent());
+ });
+ } else {
+ builder.startOffset(offset);
+ }
+ return builder.build();
+ }
+
+ @Override
+ public CompletionItem createFinderMethodNameItem(String prefix, String name, int offset) {
+ return CompletionUtilities.newCompletionItemBuilder(prefix + name)
+ .startOffset(offset)
+ .iconResource(ICON)
+ .leftHtmlText( prefix + "<b>" + name + "</b>")
+ .sortPriority(10)
+ .sortText(name)
+ .build();
+ }
+ }));
+ resultSet.setAnchorOffset(task.getAnchorOffset());
+ resultSet.finish();
+ }
+ }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionTask.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionTask.java
new file mode 100644
index 0000000..e025394
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionTask.java
@@ -0,0 +1,434 @@
+/*
+ * 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.micronaut.completion;
+
+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 com.sun.source.util.TreePath;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.prefs.PreferenceChangeEvent;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.prefs.Preferences;
+import java.util.regex.Pattern;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Types;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.mimelookup.MimeLookup;
+import org.netbeans.api.java.lexer.JavaTokenId;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.TreeUtilities;
+import org.netbeans.api.java.source.TypeUtilities;
+import org.netbeans.api.lexer.TokenSequence;
+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.openide.util.Exceptions;
+import org.openide.util.WeakListeners;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class MicronautDataCompletionTask {
+
+ private static final String REPOSITORY_ANNOTATION_NAME = "io.micronaut.data.annotation.Repository";
+ private static final String REPOSITORY_TYPE_NAME = "io.micronaut.data.repository.GenericRepository";
+ private static final String GET = "get";
+ private static final List<String> QUERY_PATTERNS = new ArrayList<>(Arrays.asList("find", "get", "query", "read", "retrieve", "search"));
+ private static final List<String> SPECIAL_QUERY_PATTERNS = new ArrayList<>(Arrays.asList("count", "countDistinct", "delete", "exists", "update"));
+ private static final List<String> QUERY_PROJECTIONS = new ArrayList<>(Arrays.asList("", "Avg", "Distinct", "Max", "Min", "Sum"));
+ private static final List<String> CRITERION_EXPRESSIONS = new ArrayList<>(Arrays.asList("", "After", "Before", "Contains", "StartingWith", "StartsWith", "EndingWith", "EndsWith",
+ "Equal", "Equals", "NotEqual", "NotEquals", "GreaterThan", "GreaterThanEquals", "LessThan", "LessThanEquals", "Like", "Ilike", "In", "InList", "InRange", "Between",
+ "IsNull", "IsNotNull", "IsEmpty", "IsNotEmpty", "True", "False"));
+ private static final List<String> COMPOSE_EXPRESSIONS = new ArrayList<>(Arrays.asList("And", "Or"));
+ private static final String BY = "By";
+ private static final String ORDER_BY = "OrderBy";
+ private static final String COUNT = "count";
+ private static final String EXISTS = "exists";
+ private static final String EMPTY = "";
+ private static final String COMPLETION_CASE_SENSITIVE = "completion-case-sensitive"; // NOI18N
+ private static final boolean COMPLETION_CASE_SENSITIVE_DEFAULT = true;
+ private static final String JAVA_COMPLETION_SUBWORDS = "javaCompletionSubwords"; //NOI18N
+ private static final boolean JAVA_COMPLETION_SUBWORDS_DEFAULT = false;
+ private static final PreferenceChangeListener preferencesTracker = new PreferenceChangeListener() {
+ @Override
+ public void preferenceChange(PreferenceChangeEvent evt) {
+ String settingName = evt == null ? null : evt.getKey();
+ if (settingName == null || COMPLETION_CASE_SENSITIVE.equals(settingName)) {
+ caseSensitive = preferences.getBoolean(COMPLETION_CASE_SENSITIVE, COMPLETION_CASE_SENSITIVE_DEFAULT);
+ }
+ if (settingName == null || JAVA_COMPLETION_SUBWORDS.equals(settingName)) {
+ javaCompletionSubwords = preferences.getBoolean(JAVA_COMPLETION_SUBWORDS, JAVA_COMPLETION_SUBWORDS_DEFAULT);
+ }
+ }
+ };
+ private static final AtomicBoolean inited = new AtomicBoolean(false);
+
+ private static Preferences preferences;
+ private static boolean caseSensitive = COMPLETION_CASE_SENSITIVE_DEFAULT;
+ private static boolean javaCompletionSubwords = JAVA_COMPLETION_SUBWORDS_DEFAULT;
+ private static String cachedPrefix = null;
+ private static Pattern cachedCamelCasePattern = null;
+ private static Pattern cachedSubwordsPattern = null;
+
+ private int anchorOffset;
+
+ public static interface ItemFactory<T> {
+ T createFinderMethodItem(String name, String returnType, int offset);
+ T createFinderMethodNameItem(String prefix, String name, int offset);
+ }
+
+ public <T> List<T> query(Document doc, int caretOffset, ItemFactory<T> factory) {
+ List<T> items = new ArrayList<>();
+ try {
+ ParserManager.parse(Collections.singleton(Source.create(doc)), new UserTask() {
+ @Override
+ public void run(ResultIterator resultIterator) throws Exception {
+ CompilationController cc = CompilationController.get(resultIterator.getParserResult(caretOffset));
+ cc.toPhase(JavaSource.Phase.PARSED);
+ anchorOffset = caretOffset;
+ String prefix = EMPTY;
+ TokenSequence<JavaTokenId> ts = cc.getTokenHierarchy().tokenSequence(JavaTokenId.language());
+ if (ts.move(anchorOffset) == 0 || !ts.moveNext()) {
+ ts.movePrevious();
+ }
+ int len = anchorOffset - ts.offset();
+ if (len > 0 && ts.token().length() >= len) {
+ if (ts.token().id() == JavaTokenId.IDENTIFIER || ts.token().id().primaryCategory().startsWith("keyword") ||
+ ts.token().id().primaryCategory().startsWith("string") || ts.token().id().primaryCategory().equals("literal")) {
+ prefix = ts.token().text().toString().substring(0, len);
+ anchorOffset = ts.offset();
+ }
+ }
+ Consumer consumer = (namePrefix, name, type) -> {
+ items.add(type != null ? factory.createFinderMethodItem(name, type, anchorOffset) : factory.createFinderMethodNameItem(namePrefix, name, anchorOffset));
+ };
+ TreeUtilities treeUtilities = cc.getTreeUtilities();
+ SourcePositions sp = cc.getTrees().getSourcePositions();
+ TreePath path = treeUtilities.pathFor(anchorOffset);
+ switch (path.getLeaf().getKind()) {
+ case CLASS:
+ case INTERFACE:
+ resolve(cc, path, prefix, true, consumer);
+ break;
+ case METHOD:
+ Tree returnType = ((MethodTree) path.getLeaf()).getReturnType();
+ if (returnType != null && findLastNonWhitespaceToken(ts, (int) sp.getEndPosition(path.getCompilationUnit(), returnType), anchorOffset) == null) {
+ resolve(cc, path.getParentPath(), prefix, false, consumer);
+ }
+ break;
+ case VARIABLE:
+ Tree type = ((VariableTree) path.getLeaf()).getType();
+ if (type != null && findLastNonWhitespaceToken(ts, (int) sp.getEndPosition(path.getCompilationUnit(), type), anchorOffset) == null) {
+ TreePath parentPath = path.getParentPath();
+ if (parentPath.getLeaf().getKind() == Tree.Kind.CLASS || parentPath.getLeaf().getKind() == Tree.Kind.INTERFACE) {
+ resolve(cc, parentPath, prefix, false, consumer);
+ }
+ }
+ break;
+
+ }
+ }
+ });
+ } catch (ParseException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ return items;
+ }
+
+ public int getAnchorOffset() {
+ return anchorOffset;
+ }
+
+ private <T> void resolve(CompilationController cc, TreePath path, String prefix, boolean full, Consumer consumer) throws IOException {
+ cc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
+ TypeUtilities tu = cc.getTypeUtilities();
+ TypeElement entity = getEntityFor(cc, path);
+ if (entity != null) {
+ Map<String, String> prop2Types = new HashMap<>();
+ for (ExecutableElement method : ElementFilter.methodsIn(entity.getEnclosedElements())) {
+ String methodName = method.getSimpleName().toString();
+ if (methodName.startsWith(GET) && method.getParameters().isEmpty()) {
+ prop2Types.put(methodName.substring(GET.length()), tu.getTypeName(method.getReturnType()).toString());
+ }
+ }
+ addFindByCompletions(entity, prop2Types, prefix, full, consumer);
+ }
+ }
+
+ private void addFindByCompletions(TypeElement entity, Map<String, String> prop2Types, String prefix, boolean full, Consumer consumer) {
+ for (String pattern : QUERY_PATTERNS) {
+ String name = pattern + BY;
+ if (prefix.length() >= name.length() && prefix.startsWith(name)) {
+ addPropertyCriterionCompletions(prop2Types, name, prefix, consumer);
+ } else if (startsWith(name, prefix)) {
+ consumer.accept(EMPTY, name, full ? entity.getSimpleName().toString() : null);
+ }
+ for (String projection : QUERY_PROJECTIONS) {
+ for (String propName : prop2Types.keySet()) {
+ name = pattern + projection + propName + BY;
+ if (prefix.length() >= name.length() && prefix.startsWith(name)) {
+ addPropertyCriterionCompletions(prop2Types, name, prefix, consumer);
+ } else if (startsWith(name, prefix)) {
+ consumer.accept(EMPTY, name, full ? prop2Types.get(propName) : null);
+ }
+ }
+ }
+ }
+ for (String pattern : SPECIAL_QUERY_PATTERNS) {
+ for (String propName : prop2Types.keySet()) {
+ String name = pattern + propName + BY;
+ if (prefix.length() >= name.length() && prefix.startsWith(name)) {
+ addPropertyCriterionCompletions(prop2Types, name, prefix, consumer);
+ } else if (startsWith(name, prefix)) {
+ consumer.accept(EMPTY, name, full ? name.startsWith(COUNT) ? "int" : name.startsWith(EXISTS) ? "boolean" : "void" : null);
+ }
+ }
+ }
+ }
+
+ private void addPropertyCriterionCompletions(Map<String, String> prop2Types, String namePrefix, String prefix, Consumer consumer) {
+ for (String propName : prop2Types.keySet()) {
+ for (String criterion : CRITERION_EXPRESSIONS) {
+ String name = propName + criterion;
+ if (prefix.length() >= namePrefix.length() + name.length() && prefix.startsWith(namePrefix + name)) {
+ addComposeAndOrderCompletions(prop2Types, namePrefix + name, prefix, consumer);
+ } else if (startsWith(namePrefix + name, prefix)) {
+ consumer.accept(namePrefix, name, null);
+ }
+ }
+ }
+ }
+
+ private void addComposeAndOrderCompletions(Map<String, String> prop2Types, String namePrefix, String prefix, Consumer consumer) {
+ for (String name : COMPOSE_EXPRESSIONS) {
+ if (prefix.length() >= namePrefix.length() + name.length() && prefix.startsWith(namePrefix + name)) {
+ addPropertyCriterionCompletions(prop2Types, namePrefix + name, prefix, consumer);
+ } else if (startsWith(namePrefix + name, prefix)) {
+ consumer.accept(namePrefix, name, null);
+ }
+ }
+ for (String propName : prop2Types.keySet()) {
+ String name = ORDER_BY + propName;
+ if (prefix.length() < namePrefix.length() + name.length() && startsWith(namePrefix + name, prefix)) {
+ consumer.accept(namePrefix, name, null);
+ }
+ }
+ }
+
+ private static TypeElement getEntityFor(CompilationInfo info, TreePath path) {
+ TypeElement te = (TypeElement) info.getTrees().getElement(path);
+ if (te.getModifiers().contains(Modifier.ABSTRACT)) {
+ if (checkForRepositoryAnnotation(te.getAnnotationMirrors())) {
+ Types types = info.getTypes();
+ TypeMirror repositoryType = types.erasure(info.getElements().getTypeElement(REPOSITORY_TYPE_NAME).asType());
+ for (TypeMirror iface : te.getInterfaces()) {
+ if (iface.getKind() == TypeKind.DECLARED && types.isSubtype(types.erasure(iface), repositoryType)) {
+ List<? extends TypeMirror> typeArguments = ((DeclaredType) iface).getTypeArguments();
+ if (!typeArguments.isEmpty()) {
+ TypeMirror entityType = typeArguments.get(0);
+ if (entityType != null && entityType.getKind() == TypeKind.DECLARED) {
+ return (TypeElement) ((DeclaredType) entityType).asElement();
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static boolean checkForRepositoryAnnotation(List<? extends AnnotationMirror> annotations) {
+ for (AnnotationMirror annotation : annotations) {
+ DeclaredType annotationType = annotation.getAnnotationType();
+ if (REPOSITORY_ANNOTATION_NAME.contentEquals(((TypeElement) annotationType.asElement()).getQualifiedName()) || checkForRepositoryAnnotation(annotationType.getAnnotationMirrors())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static TokenSequence<JavaTokenId> findLastNonWhitespaceToken(TokenSequence<JavaTokenId> ts, int startPos, int endPos) {
+ ts.move(endPos);
+ TokenSequence<JavaTokenId> last = previousNonWhitespaceToken(ts);
+ if (last == null || last.offset() < startPos) {
+ return null;
+ }
+ return last;
+ }
+
+ private static TokenSequence<JavaTokenId> previousNonWhitespaceToken(TokenSequence<JavaTokenId> ts) {
+ while (ts.movePrevious()) {
+ switch (ts.token().id()) {
+ case WHITESPACE:
+ case LINE_COMMENT:
+ case BLOCK_COMMENT:
+ case JAVADOC_COMMENT:
+ break;
+ default:
+ return ts;
+ }
+ }
+ return null;
+ }
+
+ private static boolean startsWith(String theString, String prefix) {
+ return isCamelCasePrefix(prefix) ? isCaseSensitive()
+ ? startsWithCamelCase(theString, prefix)
+ : startsWithCamelCase(theString, prefix) || startsWithPlain(theString, prefix)
+ : startsWithPlain(theString, prefix);
+ }
+
+ private static boolean isCamelCasePrefix(String prefix) {
+ if (prefix == null || prefix.length() < 2 || prefix.charAt(0) == '"') {
+ return false;
+ }
+ for (int i = 1; i < prefix.length(); i++) {
+ if (Character.isUpperCase(prefix.charAt(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isCaseSensitive() {
+ lazyInit();
+ return caseSensitive;
+ }
+
+ public static boolean isSubwordSensitive() {
+ lazyInit();
+ return javaCompletionSubwords;
+ }
+
+ private static boolean startsWithPlain(String theString, String prefix) {
+ if (theString == null || theString.length() == 0) {
+ return false;
+ }
+ if (prefix == null || prefix.length() == 0) {
+ return true;
+ }
+ if (isSubwordSensitive()) {
+ if (!prefix.equals(cachedPrefix)) {
+ cachedCamelCasePattern = null;
+ cachedSubwordsPattern = null;
+ }
+ if (cachedSubwordsPattern == null) {
+ cachedPrefix = prefix;
+ String patternString = createSubwordsPattern(prefix);
+ cachedSubwordsPattern = patternString != null ? Pattern.compile(patternString) : null;
+ }
+ if (cachedSubwordsPattern != null && cachedSubwordsPattern.matcher(theString).matches()) {
+ return true;
+ }
+ }
+ return isCaseSensitive() ? theString.startsWith(prefix) : theString.toLowerCase(Locale.ENGLISH).startsWith(prefix.toLowerCase(Locale.ENGLISH));
+ }
+
+ private static String createSubwordsPattern(String prefix) {
+ StringBuilder sb = new StringBuilder(3 + 8 * prefix.length());
+ sb.append(".*?");
+ for (int i = 0; i < prefix.length(); i++) {
+ char charAt = prefix.charAt(i);
+ if (!Character.isJavaIdentifierPart(charAt)) {
+ return null;
+ }
+ if (Character.isLowerCase(charAt)) {
+ sb.append("[");
+ sb.append(charAt);
+ sb.append(Character.toUpperCase(charAt));
+ sb.append("]");
+ } else {
+ //keep uppercase characters as beacons
+ // for example: java.lang.System.sIn -> setIn
+ sb.append(charAt);
+ }
+ sb.append(".*?");
+ }
+ return sb.toString();
+ }
+
+ private static boolean startsWithCamelCase(String theString, String prefix) {
+ if (theString == null || theString.length() == 0 || prefix == null || prefix.length() == 0) {
+ return false;
+ }
+ if (!prefix.equals(cachedPrefix)) {
+ cachedCamelCasePattern = null;
+ cachedSubwordsPattern = null;
+ }
+ if (cachedCamelCasePattern == null) {
+ StringBuilder sb = new StringBuilder();
+ int lastIndex = 0;
+ int index;
+ do {
+ index = findNextUpper(prefix, lastIndex + 1);
+ String token = prefix.substring(lastIndex, index == -1 ? prefix.length() : index);
+ sb.append(token);
+ sb.append(index != -1 ? "[\\p{javaLowerCase}\\p{Digit}_\\$]*" : ".*");
+ lastIndex = index;
+ } while (index != -1);
+ cachedPrefix = prefix;
+ cachedCamelCasePattern = Pattern.compile(sb.toString());
+ }
+ return cachedCamelCasePattern.matcher(theString).matches();
+ }
+
+ private static int findNextUpper(String text, int offset) {
+ for (int i = offset; i < text.length(); i++) {
+ if (Character.isUpperCase(text.charAt(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static void lazyInit() {
+ if (inited.compareAndSet(false, true)) {
+ preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
+ preferences.addPreferenceChangeListener(WeakListeners.create(PreferenceChangeListener.class, preferencesTracker, preferences));
+ preferencesTracker.preferenceChange(null);
+ }
+ }
+
+ @FunctionalInterface
+ private static interface Consumer {
+ void accept(String namePrefix, String name, String type);
+ }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautProjectWizardIterator.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautProjectWizardIterator.java
index 1ac79ce..f58b00c 100644
--- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautProjectWizardIterator.java
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautProjectWizardIterator.java
@@ -92,6 +92,7 @@ public class MicronautProjectWizardIterator implements WizardDescriptor.Progress
public Set instantiate(ProgressHandle handle) throws IOException {
try {
handle.start(4);
+ String projectName = (String) wiz.getProperty(PROJECT_NAME);
File projFile = FileUtil.normalizeFile((File) wiz.getProperty(PROJECT_LOCATION));
projFile.mkdirs();
handle.progress(1);
@@ -105,7 +106,7 @@ public class MicronautProjectWizardIterator implements WizardDescriptor.Progress
(Set<MicronautLaunchService.Feature>) wiz.getProperty(FEATURES));
handle.progress(2);
FileObject projDir = FileUtil.toFileObject(projFile);
- unzip(stream, projDir);
+ unzip(stream, projDir, projectName + '/');
handle.progress(3);
ProjectManager.getDefault().clearNonProjectCache();
Project prj = ProjectManager.getDefault().findProject(projDir);
@@ -207,11 +208,14 @@ public class MicronautProjectWizardIterator implements WizardDescriptor.Progress
public void removeChangeListener(ChangeListener l) {
}
- private static void unzip(InputStream stream, FileObject folder) throws IOException {
+ private static void unzip(InputStream stream, FileObject folder, String prefix) throws IOException {
try (ZipInputStream zis = new ZipInputStream(stream)) {
ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null) {
String entryName = zipEntry.getName();
+ if (entryName.startsWith(prefix)) {
+ entryName = entryName.substring(prefix.length());
+ }
if (zipEntry.isDirectory()) {
FileUtil.createFolder(folder, entryName);
} else {
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/refactor/MicronautRefactoringFactory.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/refactor/MicronautRefactoringFactory.java
index d90a62e..7760e26 100644
--- a/enterprise/micronaut/src/org/netbeans/modules/micronaut/refactor/MicronautRefactoringFactory.java
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/refactor/MicronautRefactoringFactory.java
@@ -38,7 +38,7 @@ import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.modules.micronaut.MicronautConfigProperties;
import org.netbeans.modules.micronaut.MicronautConfigUtilities;
-import org.netbeans.modules.micronaut.completion.MicronautConfigCompletionItem;
+import org.netbeans.modules.micronaut.completion.MicronautConfigCompletionProvider;
import org.netbeans.modules.refactoring.api.AbstractRefactoring;
import org.netbeans.modules.refactoring.api.Problem;
import org.netbeans.modules.refactoring.api.Scope;
@@ -210,7 +210,7 @@ public class MicronautRefactoringFactory implements RefactoringPluginFactory {
if (idx < 0) {
sb.append(text);
} else {
- sb.append(MicronautConfigCompletionItem.PROPERTY_NAME_COLOR).append("<b>");
+ sb.append(MicronautConfigCompletionProvider.PROPERTY_NAME_COLOR).append("<b>");
sb.append(text.substring(0, idx));
sb.append("</b></font>");
sb.append(text.substring(idx));
diff --git a/ide/editor.completion/apichanges.xml b/ide/editor.completion/apichanges.xml
index 25cd2a2..92daa52 100644
--- a/ide/editor.completion/apichanges.xml
+++ b/ide/editor.completion/apichanges.xml
@@ -84,6 +84,21 @@ is the proper place.
<!-- ACTUAL CHANGES BEGIN HERE: -->
<changes>
+ <change id="CompletionUtilities.newCompletionItemBuilder">
+ <api name="completion"/>
+ <summary>Addition of CompletionUtilities.newCompletionItemBuilder() method</summary>
+ <version major="1" minor="60"/>
+ <date day="26" month="11" year="2021"/>
+ <author login="dbalek"/>
+ <compatibility addition="yes"/>
+ <description>
+ <p>
+ <code>CompletionUtilities.newCompletionItemBuilder()</code> method was added
+ to allow for creation of simple <code>CompletionItem</code>s.
+ </p>
+ </description>
+ </change>
+
<change id="CompositeCompletionItem">
<api name="completion"/>
<summary>Addition of CompositeCompletionItem</summary>
diff --git a/ide/editor.completion/nbproject/project.properties b/ide/editor.completion/nbproject/project.properties
index 20de06b..8f0b16f 100644
--- a/ide/editor.completion/nbproject/project.properties
+++ b/ide/editor.completion/nbproject/project.properties
@@ -19,4 +19,4 @@ javac.compilerargs=-Xlint:unchecked
javac.source=1.8
javadoc.arch=${basedir}/arch.xml
javadoc.apichanges=${basedir}/apichanges.xml
-spec.version.base=1.59.0
+spec.version.base=1.60.0
diff --git a/ide/editor.completion/src/org/netbeans/modules/editor/completion/CompletionSupportSpiPackageAccessor.java b/ide/editor.completion/src/org/netbeans/modules/editor/completion/CompletionSupportSpiPackageAccessor.java
new file mode 100644
index 0000000..c09d0c9
--- /dev/null
+++ b/ide/editor.completion/src/org/netbeans/modules/editor/completion/CompletionSupportSpiPackageAccessor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.editor.completion;
+
+import javax.swing.text.JTextComponent;
+import org.netbeans.spi.editor.completion.support.CompletionUtilities;
+
+public abstract class CompletionSupportSpiPackageAccessor {
+
+ private static CompletionSupportSpiPackageAccessor INSTANCE;
+
+ public static CompletionSupportSpiPackageAccessor get() {
+ return INSTANCE;
+ }
+
+ public static void register(CompletionSupportSpiPackageAccessor accessor) {
+ if (INSTANCE != null) {
+ throw new IllegalStateException("Already registered");
+ }
+ INSTANCE = accessor;
+ }
+
+ public abstract CompletionUtilities.OnSelectContext createOnSelectContext(JTextComponent component, boolean overwrite);
+}
diff --git a/ide/editor.completion/src/org/netbeans/modules/editor/completion/SimpleCompletionItem.java b/ide/editor.completion/src/org/netbeans/modules/editor/completion/SimpleCompletionItem.java
new file mode 100644
index 0000000..f34c651
--- /dev/null
+++ b/ide/editor.completion/src/org/netbeans/modules/editor/completion/SimpleCompletionItem.java
@@ -0,0 +1,172 @@
+/*
+ * 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.editor.completion;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import javax.swing.ImageIcon;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.JTextComponent;
+import org.netbeans.api.editor.completion.Completion;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.spi.editor.completion.CompletionItem;
+import org.netbeans.spi.editor.completion.CompletionTask;
+import org.netbeans.spi.editor.completion.support.CompletionUtilities;
+import org.openide.util.ImageUtilities;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class SimpleCompletionItem implements CompletionItem {
+
+ private final String insertText;
+ private final int startOffset;
+ private final int endOffset;
+ private final String iconResource;
+ private final String leftHtmlText;
+ private final String rightHtmlText;
+ private final int sortPriority;
+ private final CharSequence sortText;
+ private final Supplier<CompletionTask> documentationTask;
+ private final Supplier<CompletionTask> tooltipTask;
+ private final Consumer<CompletionUtilities.OnSelectContext> onSelectCallback;
+
+ private ImageIcon icon;
+
+ public SimpleCompletionItem(String insertText, int startOffset, int endOffset, String iconResource, String leftHtmlText, String rightHtmlText,
+ int sortPriority, CharSequence sortText, Supplier<CompletionTask> documentationTask, Supplier<CompletionTask> tooltipTask,
+ Consumer<CompletionUtilities.OnSelectContext> onSelectCallback) {
+ this.insertText = insertText;
+ this.startOffset = startOffset;
+ this.endOffset = endOffset;
+ this.iconResource = iconResource;
+ this.leftHtmlText = leftHtmlText;
+ this.rightHtmlText = rightHtmlText;
+ this.sortPriority = sortPriority;
+ this.sortText = sortText;
+ this.documentationTask = documentationTask;
+ this.tooltipTask = tooltipTask;
+ this.onSelectCallback = onSelectCallback;
+ }
+
+ @Override
+ public void defaultAction(JTextComponent component) {
+ if (component != null) {
+ Completion.get().hideDocumentation();
+ Completion.get().hideCompletion();
+ process(component, false);
+ }
+ }
+
+ @Override
+ public void processKeyEvent(KeyEvent evt) {
+ if (evt.getID() == KeyEvent.KEY_PRESSED && evt.getKeyCode() == KeyEvent.VK_ENTER && (evt.getModifiers() & InputEvent.CTRL_MASK) > 0) {
+ JTextComponent component = (JTextComponent)evt.getSource();
+ Completion.get().hideDocumentation();
+ Completion.get().hideCompletion();
+ process(component, true);
+ evt.consume();
+ }
+ }
+
+ @Override
+ public int getPreferredWidth(Graphics g, Font defaultFont) {
+ return CompletionUtilities.getPreferredWidth(leftHtmlText != null ? leftHtmlText : insertText, rightHtmlText, g, defaultFont);
+ }
+
+ @Override
+ public void render(Graphics g, Font defaultFont, Color defaultColor, Color backgroundColor, int width, int height, boolean selected) {
+ CompletionUtilities.renderHtml(getIcon(), leftHtmlText != null ? leftHtmlText : insertText, rightHtmlText, g, defaultFont, defaultColor, width, height, selected);
+ }
+
+ @Override
+ public CompletionTask createDocumentationTask() {
+ if (documentationTask != null) {
+ return documentationTask.get();
+ }
+ return null;
+ }
+
+ @Override
+ public CompletionTask createToolTipTask() {
+ if (tooltipTask != null) {
+ tooltipTask.get();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean instantSubstitution(JTextComponent component) {
+ return false;
+ }
+
+ @Override
+ public int getSortPriority() {
+ return sortPriority;
+ }
+
+ @Override
+ public CharSequence getSortText() {
+ return sortText != null ? sortText : insertText;
+ }
+
+ @Override
+ public CharSequence getInsertPrefix() {
+ return insertText;
+ }
+
+ private void process(JTextComponent component, boolean overwrite) {
+ if (onSelectCallback != null) {
+ CompletionUtilities.OnSelectContext ctx = CompletionSupportSpiPackageAccessor.get().createOnSelectContext(component, overwrite);
+ onSelectCallback.accept(ctx);
+ } else {
+ final BaseDocument doc = (BaseDocument) component.getDocument();
+ doc.runAtomic (new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (startOffset < 0) {
+ if (overwrite && endOffset > component.getCaretPosition()) {
+ doc.remove(component.getCaretPosition(), endOffset - component.getCaretPosition());
+ }
+ doc.insertString(component.getCaretPosition(), insertText, null);
+ } else {
+ doc.remove(startOffset, (overwrite && endOffset > component.getCaretPosition() ? endOffset : component.getCaretPosition()) - startOffset);
+ doc.insertString(startOffset, insertText, null);
+ }
+ } catch (BadLocationException e) {
+ }
+ }
+ });
+ }
+ }
+
+ private ImageIcon getIcon() {
+ if (icon == null && iconResource != null) {
+ icon = ImageUtilities.loadImageIcon(iconResource, false);
+ }
+ return icon;
+ }
+}
diff --git a/ide/editor.completion/src/org/netbeans/spi/editor/completion/support/CompletionUtilities.java b/ide/editor.completion/src/org/netbeans/spi/editor/completion/support/CompletionUtilities.java
index fda21be..3d5cc35 100644
--- a/ide/editor.completion/src/org/netbeans/spi/editor/completion/support/CompletionUtilities.java
+++ b/ide/editor.completion/src/org/netbeans/spi/editor/completion/support/CompletionUtilities.java
@@ -23,8 +23,15 @@ import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import javax.swing.ImageIcon;
+import javax.swing.text.JTextComponent;
+import org.netbeans.modules.editor.completion.CompletionSupportSpiPackageAccessor;
import org.netbeans.modules.editor.completion.PatchedHtmlRenderer;
+import org.netbeans.modules.editor.completion.SimpleCompletionItem;
+import org.netbeans.spi.editor.completion.CompletionItem;
+import org.netbeans.spi.editor.completion.CompletionTask;
/**
* Various code completion utilities including completion item
@@ -36,6 +43,10 @@ import org.netbeans.modules.editor.completion.PatchedHtmlRenderer;
public final class CompletionUtilities {
+ static {
+ CompletionSupportSpiPackageAccessor.register(new SpiAccessor());
+ }
+
/**
* The gap between left edge and icon.
*/
@@ -160,5 +171,220 @@ public final class CompletionUtilities {
defaultFont, defaultColor, PatchedHtmlRenderer.STYLE_TRUNCATE, true, selected);
}
}
-
+
+ /**
+ * Creates a builder for simple {@link CompletionItem} instances.
+ *
+ * @param insertText a text to be inserted into a document when selecting the item.
+ * @return newly created builder
+ *
+ * @since 1.60
+ */
+ public static CompletionItemBuilder newCompletionItemBuilder(String insertText) {
+ return new CompletionItemBuilder(insertText);
+ }
+
+ /**
+ * Builder for simple {@link CompletionItem} instances.
+ * <br/>
+ * Example usage:
+ * <pre>
+ * CompletionUtilities.newCompletionItemBuilder(insertText)
+ * .startOffset(offset)
+ * .iconResource(iconPath)
+ * .leftHtmlText("<b>" + label + "</b>")
+ * .sortPriority(10)
+ * .sortText(label)
+ * .build();
+ * </pre>
+ *
+ * @since 1.60
+ */
+ public static final class CompletionItemBuilder {
+
+ private String insertText;
+ private int startOffset = -1;
+ private int endOffset = -1;
+ private String iconResource;
+ private String leftHtmlText;
+ private String rightHtmlText;
+ private int sortPriority = 10000;
+ private CharSequence sortText;
+ private Supplier<CompletionTask> documentationTask;
+ private Supplier<CompletionTask> tooltipTask;
+ private Consumer<OnSelectContext> onSelectCallback;
+
+ private CompletionItemBuilder(String insertText) {
+ this.insertText = insertText;
+ }
+
+ /**
+ * A text to be inserted into a document when selecting the item.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder insertText(String insertText) {
+ this.insertText = insertText;
+ return this;
+ }
+
+ /**
+ * Start offset of the region to be removed on the item's selection. If omitted,
+ * the caret offset would be used.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder startOffset(int offset) {
+ this.startOffset = offset;
+ return this;
+ }
+
+ /**
+ * Start offset of the region to be removed on the item's selection. If omitted,
+ * the caret offset would be used.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder endOffset(int offset) {
+ this.endOffset = offset;
+ return this;
+ }
+
+ /**
+ * Resource path of the icon. It may be null which means that no icon will be displayed.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder iconResource(String iconResource) {
+ this.iconResource = iconResource;
+ return this;
+ }
+
+ /**
+ * An html text that will be displayed on the left side of the item next to the icon.
+ * If omitted, insertText would be used instead.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder leftHtmlText(String leftHtmlText) {
+ this.leftHtmlText = leftHtmlText;
+ return this;
+ }
+
+ /**
+ * An html text that will be aligned to the right edge of the item.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder rightHtmlText(String rightHtmlText) {
+ this.rightHtmlText = rightHtmlText;
+ return this;
+ }
+
+ /**
+ * Item's priority. A lower value means a lower index of the item in the completion result list.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder sortPriority(int sortPriority) {
+ this.sortPriority = sortPriority;
+ return this;
+ }
+
+ /**
+ * A text used to sort items alphabetically. If omitted, insertText would be used instead.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder sortText(CharSequence sortText) {
+ this.sortText = sortText;
+ return this;
+ }
+
+ /**
+ * A task used to obtain a documentation associated with the item if there
+ * is any.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder documentationTask(Supplier<CompletionTask> task) {
+ this.documentationTask = task;
+ return this;
+ }
+
+ /**
+ * A task used to obtain a tooltip hint associated with the item if there
+ * is any.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder tooltipTask(Supplier<CompletionTask> task) {
+ this.tooltipTask = task;
+ return this;
+ }
+
+ /**
+ * A callback to process the item insertion. Should be used for complex cases
+ * when a simple insertText insertion is not sufficient.
+ *
+ * @since 1.60
+ */
+ public CompletionItemBuilder onSelect(Consumer<OnSelectContext> callback) {
+ this.onSelectCallback = callback;
+ return this;
+ }
+
+ /**
+ * Builds completion item.
+ *
+ * @since 1.60
+ */
+ public CompletionItem build() {
+ return new SimpleCompletionItem(insertText, startOffset, endOffset, iconResource, leftHtmlText, rightHtmlText,
+ sortPriority, sortText, documentationTask, tooltipTask, onSelectCallback);
+ }
+
+ }
+
+ /**
+ * A parameter passed to CompletionItemBuilder's onSelect callback.
+ *
+ * @since 1.60
+ */
+ public static final class OnSelectContext {
+
+ private final JTextComponent component;
+ private final boolean overwrite;
+
+ private OnSelectContext(JTextComponent component, boolean overwrite) {
+ this.component = component;
+ this.overwrite = overwrite;
+ }
+
+ /**
+ * A text component to which the completion item should be inserted.
+ *
+ * @since 1.60
+ */
+ public JTextComponent getComponent() {
+ return component;
+ }
+
+ /**
+ * If true, the inserted completion item should overwrite existing text.
+ *
+ * @since 1.60
+ */
+ public boolean isOverwrite() {
+ return overwrite;
+ }
+ }
+
+ private static final class SpiAccessor extends CompletionSupportSpiPackageAccessor {
+
+ @Override
+ public OnSelectContext createOnSelectContext(JTextComponent component, boolean overwrite) {
+ return new OnSelectContext(component, overwrite);
+ }
+ }
}
diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts
index e508215..57062e8 100644
--- a/java/java.lsp.server/vscode/src/extension.ts
+++ b/java/java.lsp.server/vscode/src/extension.ts
@@ -514,7 +514,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex
stdOut = null;
}
}
- let p = launcher.launch(info, "--modules", "--list");
+ let p = launcher.launch(info, "--modules", "--list", "-J-XX:PerfMaxStringConstLength=10240");
handleLog(log, "LSP server launching: " + p.pid);
p.stdout.on('data', function(d: any) {
logAndWaitForEnabled(d.toString(), true);
---------------------------------------------------------------------
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