diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java index 2736667a6e6..ce49eb44847 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java @@ -662,6 +662,13 @@ public interface Theme { */ String completionPopupItemSubtitleTextColor(); + /** + * Item highlight text color for completion popup. + * + * @return color + */ + String completionPopupItemHighlightTextColor(); + /** * Background color of the window widget. * diff --git a/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/ui/style.css b/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/ui/style.css index 7fe01b89902..a1bc24a5221 100644 --- a/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/ui/style.css +++ b/ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/ui/style.css @@ -146,6 +146,7 @@ @eval completionPopupSelectedItemBackgroundColor org.eclipse.che.ide.api.theme.Style.theme.completionPopupSelectedItemBackgroundColor(); @eval completionPopupItemTextColor org.eclipse.che.ide.api.theme.Style.theme.completionPopupItemTextColor(); @eval completionPopupItemSubtitleTextColor org.eclipse.che.ide.api.theme.Style.theme.completionPopupItemSubtitleTextColor(); +@eval completionPopupItemHighlightTextColor org.eclipse.che.ide.api.theme.Style.theme.completionPopupItemHighlightTextColor(); @eval editorInfoBorderColor org.eclipse.che.ide.api.theme.Style.getEditorInfoBorderColor(); @eval editorInfoBorderShadowColor org.eclipse.che.ide.api.theme.Style.getEditorInfoBorderShadowColor(); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java index a5b62bdd4f5..056ac6d55d0 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java @@ -506,6 +506,11 @@ public String completionPopupItemSubtitleTextColor() { return "#727272"; } + @Override + public String completionPopupItemHighlightTextColor() { + return "#4EABFF"; + } + @Override public String getWindowContentBackground() { return "#292C2F"; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java index dfddc812c03..d60ca22067c 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java @@ -487,6 +487,11 @@ public String completionPopupItemSubtitleTextColor() { return "#909090"; } + @Override + public String completionPopupItemHighlightTextColor() { + return "#1A68AF"; + } + @Override public String getWindowContentBackground() { return "#ECECEC"; diff --git a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/popup/popup.css b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/popup/popup.css index 88e600d203b..f0cdaa3e13f 100644 --- a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/popup/popup.css +++ b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/popup/popup.css @@ -110,7 +110,3 @@ color: completionPopupItemTextColor; } - -.label span { - color: completionPopupItemSubtitleTextColor !important; -} diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/LanguageServerResources.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/LanguageServerResources.java index a1c215b9c6e..17262506853 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/LanguageServerResources.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/LanguageServerResources.java @@ -24,7 +24,7 @@ public interface LanguageServerResources extends ClientBundle { LanguageServerResources INSTANCE = GWT.create(LanguageServerResources.class); - @Source("languageserver.css") + @Source({"languageserver.css", "org/eclipse/che/ide/api/ui/style.css"}) LSCss css(); @Source({"QuickOpenList.css", "org/eclipse/che/ide/ui/constants.css", "org/eclipse/che/ide/api/ui/style.css"}) @@ -103,6 +103,9 @@ interface LSCss extends CssResource { @ClassName("codeassistant-detail") String codeassistantDetail(); + + @ClassName("codeassistant-highlight") + String codeassistantHighlight(); } interface QuickOpenListCss extends SimpleList.Css{ diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java index 030182e67ec..09a940d9d97 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java @@ -17,6 +17,8 @@ import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Widget; +import java.util.List; + import org.eclipse.che.api.languageserver.shared.lsapi.CompletionItemDTO; import org.eclipse.che.api.languageserver.shared.lsapi.RangeDTO; import org.eclipse.che.api.languageserver.shared.lsapi.TextDocumentIdentifierDTO; @@ -31,6 +33,7 @@ import org.eclipse.che.ide.api.icon.Icon; import org.eclipse.che.ide.util.loging.Log; import org.eclipse.che.plugin.languageserver.ide.LanguageServerResources; +import org.eclipse.che.plugin.languageserver.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.service.TextDocumentServiceClient; /** @@ -38,24 +41,27 @@ */ public class CompletionItemBasedCompletionProposal implements CompletionProposal { + private final CompletionItemDTO completionItem; private final TextDocumentServiceClient documentServiceClient; private final TextDocumentIdentifierDTO documentId; private final LanguageServerResources resources; private final Icon icon; private final ServerCapabilities serverCapabilities; - private CompletionItemDTO completionItem; + private final List highlights; CompletionItemBasedCompletionProposal(CompletionItemDTO completionItem, TextDocumentServiceClient documentServiceClient, TextDocumentIdentifierDTO documentId, LanguageServerResources resources, Icon icon, - ServerCapabilities serverCapabilities) { + ServerCapabilities serverCapabilities, + List highlights) { this.completionItem = completionItem; this.documentServiceClient = documentServiceClient; this.documentId = documentId; this.resources = resources; this.icon = icon; this.serverCapabilities = serverCapabilities; + this.highlights = highlights; } @Override @@ -72,14 +78,48 @@ public Widget getAdditionalProposalInfo() { @Override public String getDisplayString() { + SafeHtmlBuilder builder = new SafeHtmlBuilder(); + + String label = completionItem.getLabel(); + int pos = 0; + for (Match highlight : highlights) { + if (highlight.getStart() == highlight.getEnd()) { + continue; + } + + if (pos < highlight.getStart()) { + appendPlain(builder, label.substring(pos, highlight.getStart())); + } + + appendHighlighted(builder, label.substring(highlight.getStart(), highlight.getEnd())); + pos = highlight.getEnd(); + } + + if (pos < label.length()) { + appendPlain(builder, label.substring(pos)); + } + if (completionItem.getDetail() != null) { - SafeHtmlBuilder builder = new SafeHtmlBuilder(); - builder.appendEscaped(completionItem.getLabel()); - builder.appendHtmlConstant(" "); - builder.appendEscaped(completionItem.getDetail()); - builder.appendHtmlConstant(""); + appendDetail(builder, completionItem.getDetail()); } - return completionItem.getLabel(); + + return builder.toSafeHtml().asString(); + } + + private void appendPlain(SafeHtmlBuilder builder, String text) { + builder.appendEscaped(text); + } + + private void appendHighlighted(SafeHtmlBuilder builder, String text) { + builder.appendHtmlConstant(""); + builder.appendEscaped(text); + builder.appendHtmlConstant(""); + } + + private void appendDetail(SafeHtmlBuilder builder, String text) { + builder.appendHtmlConstant(" "); + builder.appendEscaped(text); + builder.appendHtmlConstant(""); } @Override diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java index ff3396f12f5..a818a163172 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java @@ -26,9 +26,12 @@ import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; import org.eclipse.che.ide.api.editor.texteditor.TextEditor; import org.eclipse.che.plugin.languageserver.ide.LanguageServerResources; +import org.eclipse.che.plugin.languageserver.ide.filters.FuzzyMatches; +import org.eclipse.che.plugin.languageserver.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.service.TextDocumentServiceClient; import org.eclipse.che.plugin.languageserver.ide.util.DtoBuildHelper; +import java.util.ArrayList; import java.util.List; import static com.google.common.collect.Lists.newArrayList; @@ -41,27 +44,32 @@ public class LanguageServerCodeAssistProcessor implements CodeAssistProcessor { private final DtoBuildHelper dtoBuildHelper; private final LanguageServerResources resources; private final CompletionImageProvider imageProvider; - private final ServerCapabilities serverCapabilities; - private TextDocumentServiceClient documentServiceClient; - private String lastErrorMessage; + private final ServerCapabilities serverCapabilities; + private final TextDocumentServiceClient documentServiceClient; + private final FuzzyMatches fuzzyMatches; + private String lastErrorMessage; @Inject public LanguageServerCodeAssistProcessor(TextDocumentServiceClient documentServiceClient, DtoBuildHelper dtoBuildHelper, LanguageServerResources resources, CompletionImageProvider imageProvider, - @Assisted ServerCapabilities serverCapabilities) { + @Assisted ServerCapabilities serverCapabilities, + FuzzyMatches fuzzyMatches) { this.documentServiceClient = documentServiceClient; this.dtoBuildHelper = dtoBuildHelper; this.resources = resources; this.imageProvider = imageProvider; this.serverCapabilities = serverCapabilities; + this.fuzzyMatches = fuzzyMatches; } @Override public void computeCompletionProposals(TextEditor editor, int offset, final CodeAssistCallback callback) { TextDocumentPositionParamsDTO documentPosition = dtoBuildHelper.createTDPP(editor.getDocument(), offset); final TextDocumentIdentifierDTO documentId = documentPosition.getTextDocument(); + String currentLine = editor.getDocument().getLineContent(documentPosition.getPosition().getLine()); + final String currentIdentifier = getCurrentIdentifier(currentLine, documentPosition.getPosition().getCharacter()); this.lastErrorMessage = null; documentServiceClient.completion(documentPosition).then(new Operation>() { @@ -69,12 +77,16 @@ public void computeCompletionProposals(TextEditor editor, int offset, final Code public void apply(List items) throws OperationException { List proposals = newArrayList(); for (CompletionItemDTO item : items) { - proposals.add(new CompletionItemBasedCompletionProposal(item, - documentServiceClient, - documentId, - resources, - imageProvider.getIcon(item.getKind()), - serverCapabilities)); + List highlights = filter(currentIdentifier, item); + if (highlights != null ) { + proposals.add(new CompletionItemBasedCompletionProposal(item, + documentServiceClient, + documentId, + resources, + imageProvider.getIcon(item.getKind()), + serverCapabilities, + highlights)); + } } callback.proposalComputed(proposals); } @@ -91,4 +103,42 @@ public String getErrorMessage() { return lastErrorMessage; } + private String getCurrentIdentifier(String text, int offset) { + int i = offset - 1; + while (i >= 0 && isIdentifierChar(text.charAt(i))) { + i--; + } + return text.substring(i + 1, offset); + } + + private boolean isIdentifierChar(char c) { + return c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c >= '\u007f' && c <= '\u00ff' || + c == '$' || + c == '_' || + c == '-'; + } + + private List filter(String word, CompletionItemDTO item) { + return filter(word, item.getLabel(), item.getFilterText()); + } + + private List filter(String word, String label, String filterText) { + if (filterText == null || filterText.isEmpty()) { + filterText = label; + } + + // check if the word matches the filterText + if (fuzzyMatches.fuzzyMatch(word, filterText) != null) { + // return the highlights based on the label + List highlights = fuzzyMatches.fuzzyMatch(word, label); + // return empty list of highlights if nothing matches the label + return (highlights == null) ? new ArrayList() : highlights; + } + + return null; + } + } diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/resources/org/eclipse/che/plugin/languageserver/ide/languageserver.css b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/resources/org/eclipse/che/plugin/languageserver/ide/languageserver.css index 507937352d0..1d7afbb8552 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/resources/org/eclipse/che/plugin/languageserver/ide/languageserver.css +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/resources/org/eclipse/che/plugin/languageserver/ide/languageserver.css @@ -49,5 +49,9 @@ } .codeassistant-detail { - color: #326EED; -} \ No newline at end of file + color: completionPopupItemSubtitleTextColor; +} + +.codeassistant-highlight { + color: completionPopupItemHighlightTextColor; +}