Skip to content

Commit 93f0951

Browse files
committed
Only search for label match if different from insertText match
and escape HTML label when no query is used
1 parent f324c69 commit 93f0951

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

packages/jupyterlab-lsp/src/features/completion/model.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ describe('LSPCompleterModel', () => {
3535
model = new LSPCompleterModel();
3636
});
3737

38+
it('returns escaped when no query', () => {
39+
model.setCompletionItems([jupyter_icon_completion]);
40+
model.query = '';
41+
42+
let markedItems = model.completionItems();
43+
expect(markedItems[0].label).to.be.equal(
44+
'<i class="jp-icon-jupyter"></i> Jupyter'
45+
);
46+
});
47+
3848
it('marks html correctly', () => {
3949
model.setCompletionItems([jupyter_icon_completion]);
4050
model.query = 'Jup';
@@ -73,4 +83,23 @@ describe('LSPCompleterModel', () => {
7383
filteredItems = model.completionItems();
7484
expect(filteredItems.length).to.equal(0);
7585
});
86+
87+
it('marks appropriate part of label when filterText matches', () => {
88+
model.setCompletionItems([jupyter_icon_completion]);
89+
// font is in filterText but not in label
90+
model.query = 'font';
91+
92+
// nothing should get highlighted
93+
let markedItems = model.completionItems();
94+
expect(markedItems[0].label).to.be.equal(
95+
'<i class="jp-icon-jupyter"></i> Jupyter'
96+
);
97+
98+
// i is in both label and filterText
99+
model.query = 'i';
100+
markedItems = model.completionItems();
101+
expect(markedItems[0].label).to.be.equal(
102+
'&lt;<mark>i</mark> class="jp-icon-jupyter"&gt;&lt;/i&gt; Jupyter'
103+
);
104+
});
76105
});

packages/jupyterlab-lsp/src/features/completion/model.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,12 @@ export class GenericCompleterModel<
7373

7474
let matched: boolean;
7575

76+
let filterText: string = null;
77+
let filterMatch: StringExt.IMatchResult;
78+
7679
if (query) {
77-
const filterText = this.getFilterText(item);
78-
let filterMatch = StringExt.matchSumOfSquares(filterText, query);
80+
filterText = this.getFilterText(item);
81+
filterMatch = StringExt.matchSumOfSquares(filterText, query);
7982
matched = !!filterMatch;
8083
} else {
8184
matched = true;
@@ -86,25 +89,32 @@ export class GenericCompleterModel<
8689
// If the matches are substrings of label, highlight them
8790
// in this part of the label that can be highlighted (must be a prefix),
8891
// which is intended to avoid highlighting matches in function arguments etc.
89-
const labelPrefix = escapeHTML(this.getHighlightableLabelRegion(item));
92+
let labelMatch: StringExt.IMatchResult;
93+
if (query) {
94+
let labelPrefix = escapeHTML(this.getHighlightableLabelRegion(item));
95+
if (labelPrefix == filterText) {
96+
labelMatch = filterMatch;
97+
} else {
98+
labelMatch = StringExt.matchSumOfSquares(labelPrefix, query);
99+
}
100+
}
90101

91-
let match = StringExt.matchSumOfSquares(labelPrefix, query);
92102
let label: string;
93103
let score: number;
94104

95-
if (match) {
105+
if (labelMatch) {
96106
// Highlight label text if there's a match
97107
// there won't be a match if filter text includes additional keywords
98108
// for easier search that are not a part of the label
99109
let marked = StringExt.highlight(
100110
escapeHTML(item.label),
101-
match.indices,
111+
labelMatch.indices,
102112
this._markFragment
103113
);
104114
label = marked.join('');
105-
score = match.score;
115+
score = labelMatch.score;
106116
} else {
107-
label = item.label;
117+
label = escapeHTML(item.label);
108118
score = 0;
109119
}
110120
// preserve getters (allow for lazily retrieved documentation)

0 commit comments

Comments
 (0)