Skip to content

Commit 902912b

Browse files
kaloyan-raevVitalii Parfonov
authored andcommitted
Fixes eclipse-che#2592: Filter code completion proposals from language server (eclipse-che#2658)
* Fixes eclipse-che#2592: Filter code completion proposals from language server Implements filtering based on the existing FuzzyMatches used for the GoToSymbolAction. Signed-off-by: Kaloyan Raev <kaloyan.r@zend.com> * Add empty line at end of file.
1 parent 13a1a52 commit 902912b

9 files changed

Lines changed: 136 additions & 25 deletions

File tree

ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/theme/Theme.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,13 @@ public interface Theme {
662662
*/
663663
String completionPopupItemSubtitleTextColor();
664664

665+
/**
666+
* Item highlight text color for completion popup.
667+
*
668+
* @return color
669+
*/
670+
String completionPopupItemHighlightTextColor();
671+
665672
/**
666673
* Background color of the window widget.
667674
*

ide/che-core-ide-api/src/main/resources/org/eclipse/che/ide/api/ui/style.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
@eval completionPopupSelectedItemBackgroundColor org.eclipse.che.ide.api.theme.Style.theme.completionPopupSelectedItemBackgroundColor();
147147
@eval completionPopupItemTextColor org.eclipse.che.ide.api.theme.Style.theme.completionPopupItemTextColor();
148148
@eval completionPopupItemSubtitleTextColor org.eclipse.che.ide.api.theme.Style.theme.completionPopupItemSubtitleTextColor();
149+
@eval completionPopupItemHighlightTextColor org.eclipse.che.ide.api.theme.Style.theme.completionPopupItemHighlightTextColor();
149150

150151
@eval editorInfoBorderColor org.eclipse.che.ide.api.theme.Style.getEditorInfoBorderColor();
151152
@eval editorInfoBorderShadowColor org.eclipse.che.ide.api.theme.Style.getEditorInfoBorderShadowColor();

ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/DarkTheme.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,11 @@ public String completionPopupItemSubtitleTextColor() {
506506
return "#727272";
507507
}
508508

509+
@Override
510+
public String completionPopupItemHighlightTextColor() {
511+
return "#4EABFF";
512+
}
513+
509514
@Override
510515
public String getWindowContentBackground() {
511516
return "#292C2F";

ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/theme/LightTheme.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,11 @@ public String completionPopupItemSubtitleTextColor() {
487487
return "#909090";
488488
}
489489

490+
@Override
491+
public String completionPopupItemHighlightTextColor() {
492+
return "#1A68AF";
493+
}
494+
490495
@Override
491496
public String getWindowContentBackground() {
492497
return "#ECECEC";

ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/popup/popup.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,3 @@
110110

111111
color: completionPopupItemTextColor;
112112
}
113-
114-
.label span {
115-
color: completionPopupItemSubtitleTextColor !important;
116-
}

plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/LanguageServerResources.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public interface LanguageServerResources extends ClientBundle {
2424

2525
LanguageServerResources INSTANCE = GWT.create(LanguageServerResources.class);
2626

27-
@Source("languageserver.css")
27+
@Source({"languageserver.css", "org/eclipse/che/ide/api/ui/style.css"})
2828
LSCss css();
2929

3030
@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 {
103103

104104
@ClassName("codeassistant-detail")
105105
String codeassistantDetail();
106+
107+
@ClassName("codeassistant-highlight")
108+
String codeassistantHighlight();
106109
}
107110

108111
interface QuickOpenListCss extends SimpleList.Css{

plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import com.google.gwt.user.client.ui.Label;
1818
import com.google.gwt.user.client.ui.Widget;
1919

20+
import java.util.List;
21+
2022
import org.eclipse.che.api.languageserver.shared.lsapi.CompletionItemDTO;
2123
import org.eclipse.che.api.languageserver.shared.lsapi.RangeDTO;
2224
import org.eclipse.che.api.languageserver.shared.lsapi.TextDocumentIdentifierDTO;
@@ -31,31 +33,35 @@
3133
import org.eclipse.che.ide.api.icon.Icon;
3234
import org.eclipse.che.ide.util.loging.Log;
3335
import org.eclipse.che.plugin.languageserver.ide.LanguageServerResources;
36+
import org.eclipse.che.plugin.languageserver.ide.filters.Match;
3437
import org.eclipse.che.plugin.languageserver.ide.service.TextDocumentServiceClient;
3538

3639
/**
3740
* @author Anatolii Bazko
3841
*/
3942
public class CompletionItemBasedCompletionProposal implements CompletionProposal {
4043

44+
private final CompletionItemDTO completionItem;
4145
private final TextDocumentServiceClient documentServiceClient;
4246
private final TextDocumentIdentifierDTO documentId;
4347
private final LanguageServerResources resources;
4448
private final Icon icon;
4549
private final ServerCapabilities serverCapabilities;
46-
private CompletionItemDTO completionItem;
50+
private final List<Match> highlights;
4751

4852
CompletionItemBasedCompletionProposal(CompletionItemDTO completionItem,
4953
TextDocumentServiceClient documentServiceClient,
5054
TextDocumentIdentifierDTO documentId,
5155
LanguageServerResources resources, Icon icon,
52-
ServerCapabilities serverCapabilities) {
56+
ServerCapabilities serverCapabilities,
57+
List<Match> highlights) {
5358
this.completionItem = completionItem;
5459
this.documentServiceClient = documentServiceClient;
5560
this.documentId = documentId;
5661
this.resources = resources;
5762
this.icon = icon;
5863
this.serverCapabilities = serverCapabilities;
64+
this.highlights = highlights;
5965
}
6066

6167
@Override
@@ -72,14 +78,48 @@ public Widget getAdditionalProposalInfo() {
7278

7379
@Override
7480
public String getDisplayString() {
81+
SafeHtmlBuilder builder = new SafeHtmlBuilder();
82+
83+
String label = completionItem.getLabel();
84+
int pos = 0;
85+
for (Match highlight : highlights) {
86+
if (highlight.getStart() == highlight.getEnd()) {
87+
continue;
88+
}
89+
90+
if (pos < highlight.getStart()) {
91+
appendPlain(builder, label.substring(pos, highlight.getStart()));
92+
}
93+
94+
appendHighlighted(builder, label.substring(highlight.getStart(), highlight.getEnd()));
95+
pos = highlight.getEnd();
96+
}
97+
98+
if (pos < label.length()) {
99+
appendPlain(builder, label.substring(pos));
100+
}
101+
75102
if (completionItem.getDetail() != null) {
76-
SafeHtmlBuilder builder = new SafeHtmlBuilder();
77-
builder.appendEscaped(completionItem.getLabel());
78-
builder.appendHtmlConstant(" <span class=\"" + resources.css().codeassistantDetail() + "\">");
79-
builder.appendEscaped(completionItem.getDetail());
80-
builder.appendHtmlConstant("</span>");
103+
appendDetail(builder, completionItem.getDetail());
81104
}
82-
return completionItem.getLabel();
105+
106+
return builder.toSafeHtml().asString();
107+
}
108+
109+
private void appendPlain(SafeHtmlBuilder builder, String text) {
110+
builder.appendEscaped(text);
111+
}
112+
113+
private void appendHighlighted(SafeHtmlBuilder builder, String text) {
114+
builder.appendHtmlConstant("<span class=\"" + resources.css().codeassistantHighlight() + "\">");
115+
builder.appendEscaped(text);
116+
builder.appendHtmlConstant("</span>");
117+
}
118+
119+
private void appendDetail(SafeHtmlBuilder builder, String text) {
120+
builder.appendHtmlConstant(" <span class=\"" + resources.css().codeassistantDetail() + "\">");
121+
builder.appendEscaped(text);
122+
builder.appendHtmlConstant("</span>");
83123
}
84124

85125
@Override

plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@
2626
import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal;
2727
import org.eclipse.che.ide.api.editor.texteditor.TextEditor;
2828
import org.eclipse.che.plugin.languageserver.ide.LanguageServerResources;
29+
import org.eclipse.che.plugin.languageserver.ide.filters.FuzzyMatches;
30+
import org.eclipse.che.plugin.languageserver.ide.filters.Match;
2931
import org.eclipse.che.plugin.languageserver.ide.service.TextDocumentServiceClient;
3032
import org.eclipse.che.plugin.languageserver.ide.util.DtoBuildHelper;
3133

34+
import java.util.ArrayList;
3235
import java.util.List;
3336

3437
import static com.google.common.collect.Lists.newArrayList;
@@ -41,40 +44,49 @@ public class LanguageServerCodeAssistProcessor implements CodeAssistProcessor {
4144
private final DtoBuildHelper dtoBuildHelper;
4245
private final LanguageServerResources resources;
4346
private final CompletionImageProvider imageProvider;
44-
private final ServerCapabilities serverCapabilities;
45-
private TextDocumentServiceClient documentServiceClient;
46-
private String lastErrorMessage;
47+
private final ServerCapabilities serverCapabilities;
48+
private final TextDocumentServiceClient documentServiceClient;
49+
private final FuzzyMatches fuzzyMatches;
50+
private String lastErrorMessage;
4751

4852
@Inject
4953
public LanguageServerCodeAssistProcessor(TextDocumentServiceClient documentServiceClient,
5054
DtoBuildHelper dtoBuildHelper,
5155
LanguageServerResources resources,
5256
CompletionImageProvider imageProvider,
53-
@Assisted ServerCapabilities serverCapabilities) {
57+
@Assisted ServerCapabilities serverCapabilities,
58+
FuzzyMatches fuzzyMatches) {
5459
this.documentServiceClient = documentServiceClient;
5560
this.dtoBuildHelper = dtoBuildHelper;
5661
this.resources = resources;
5762
this.imageProvider = imageProvider;
5863
this.serverCapabilities = serverCapabilities;
64+
this.fuzzyMatches = fuzzyMatches;
5965
}
6066

6167
@Override
6268
public void computeCompletionProposals(TextEditor editor, int offset, final CodeAssistCallback callback) {
6369
TextDocumentPositionParamsDTO documentPosition = dtoBuildHelper.createTDPP(editor.getDocument(), offset);
6470
final TextDocumentIdentifierDTO documentId = documentPosition.getTextDocument();
71+
String currentLine = editor.getDocument().getLineContent(documentPosition.getPosition().getLine());
72+
final String currentIdentifier = getCurrentIdentifier(currentLine, documentPosition.getPosition().getCharacter());
6573
this.lastErrorMessage = null;
6674
documentServiceClient.completion(documentPosition).then(new Operation<List<CompletionItemDTO>>() {
6775

6876
@Override
6977
public void apply(List<CompletionItemDTO> items) throws OperationException {
7078
List<CompletionProposal> proposals = newArrayList();
7179
for (CompletionItemDTO item : items) {
72-
proposals.add(new CompletionItemBasedCompletionProposal(item,
73-
documentServiceClient,
74-
documentId,
75-
resources,
76-
imageProvider.getIcon(item.getKind()),
77-
serverCapabilities));
80+
List<Match> highlights = filter(currentIdentifier, item);
81+
if (highlights != null ) {
82+
proposals.add(new CompletionItemBasedCompletionProposal(item,
83+
documentServiceClient,
84+
documentId,
85+
resources,
86+
imageProvider.getIcon(item.getKind()),
87+
serverCapabilities,
88+
highlights));
89+
}
7890
}
7991
callback.proposalComputed(proposals);
8092
}
@@ -91,4 +103,42 @@ public String getErrorMessage() {
91103
return lastErrorMessage;
92104
}
93105

106+
private String getCurrentIdentifier(String text, int offset) {
107+
int i = offset - 1;
108+
while (i >= 0 && isIdentifierChar(text.charAt(i))) {
109+
i--;
110+
}
111+
return text.substring(i + 1, offset);
112+
}
113+
114+
private boolean isIdentifierChar(char c) {
115+
return c >= 'a' && c <= 'z' ||
116+
c >= 'A' && c <= 'Z' ||
117+
c >= '0' && c <= '9' ||
118+
c >= '\u007f' && c <= '\u00ff' ||
119+
c == '$' ||
120+
c == '_' ||
121+
c == '-';
122+
}
123+
124+
private List<Match> filter(String word, CompletionItemDTO item) {
125+
return filter(word, item.getLabel(), item.getFilterText());
126+
}
127+
128+
private List<Match> filter(String word, String label, String filterText) {
129+
if (filterText == null || filterText.isEmpty()) {
130+
filterText = label;
131+
}
132+
133+
// check if the word matches the filterText
134+
if (fuzzyMatches.fuzzyMatch(word, filterText) != null) {
135+
// return the highlights based on the label
136+
List<Match> highlights = fuzzyMatches.fuzzyMatch(word, label);
137+
// return empty list of highlights if nothing matches the label
138+
return (highlights == null) ? new ArrayList<Match>() : highlights;
139+
}
140+
141+
return null;
142+
}
143+
94144
}

plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/resources/org/eclipse/che/plugin/languageserver/ide/languageserver.css

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,9 @@
4949
}
5050

5151
.codeassistant-detail {
52-
color: #326EED;
53-
}
52+
color: completionPopupItemSubtitleTextColor;
53+
}
54+
55+
.codeassistant-highlight {
56+
color: completionPopupItemHighlightTextColor;
57+
}

0 commit comments

Comments
 (0)