From df7fdd65154f66632ad5473b539238f62a6ee363 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 9 Nov 2020 16:15:17 -0800 Subject: [PATCH 1/6] search: fix freezing ui on long lines Fixes https://github.com/microsoft/vscode/issues/109902 --- .vscode/launch.json | 5 +- .../services/search/common/search.ts | 48 ++++++++++++------- .../search/test/common/search.test.ts | 14 ++++++ 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 646b99c7943..a83c164f3c2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -41,10 +41,7 @@ "port": 5876, "outFiles": [ "${workspaceFolder}/out/**/*.js" - ], - "presentation": { - "hidden": true, - } + ] }, { "type": "node", diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index 212cc51ea37..259af6cff37 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -24,6 +24,8 @@ export const VIEW_ID = 'workbench.view.search'; export const SEARCH_EXCLUDE_CONFIG = 'search.exclude'; +const SEARCH_SINGLE_RANGE_DIVIDER = '...'; + export const ISearchService = createDecorator('searchService'); /** @@ -260,24 +262,31 @@ export class TextSearchMatch implements ITextSearchMatch { // Trim preview if this is one match and a single-line match with a preview requested. // Otherwise send the full text, like for replace or for showing multiple previews. // TODO this is fishy. - if (previewOptions && previewOptions.matchLines === 1 && (!Array.isArray(range) || range.length === 1) && isSingleLineRange(range)) { - const oneRange = Array.isArray(range) ? range[0] : range; - + const ranges = Array.isArray(range) ? range : [range]; + if (previewOptions && previewOptions.matchLines === 1 && isSingleLineRangeList(ranges)) { // 1 line preview requested text = getNLines(text, previewOptions.matchLines); + + let result = ''; + let shift = 0; + let lastEnd = 0; const leadingChars = Math.floor(previewOptions.charsPerLine / 5); - const previewStart = Math.max(oneRange.startColumn - leadingChars, 0); - const previewText = text.substring(previewStart, previewOptions.charsPerLine + previewStart); + const matches: ISearchRange[] = []; + for (const range of ranges) { + const previewStart = Math.max(range.startColumn - leadingChars, 0); + const previewEnd = range.startColumn + previewOptions.charsPerLine; + if (previewStart > lastEnd + leadingChars) { + result += SEARCH_SINGLE_RANGE_DIVIDER + text.slice(previewStart, previewEnd); + shift += previewStart - (lastEnd + SEARCH_SINGLE_RANGE_DIVIDER.length); + } else { + result += text.slice(lastEnd, previewEnd); + } - const endColInPreview = (oneRange.endLineNumber - oneRange.startLineNumber + 1) <= previewOptions.matchLines ? - Math.min(previewText.length, oneRange.endColumn - previewStart) : // if number of match lines will not be trimmed by previewOptions - previewText.length; // if number of lines is trimmed + matches.push(new OneLineRange(0, range.startColumn - shift, range.endColumn - shift)); + lastEnd = previewEnd; + } - const oneLineRange = new OneLineRange(0, oneRange.startColumn - previewStart, endColInPreview); - this.preview = { - text: previewText, - matches: Array.isArray(range) ? [oneLineRange] : oneLineRange - }; + this.preview = { text: result, matches: matches.length === 1 ? matches[0] : matches }; } else { const firstMatchLine = Array.isArray(range) ? range[0].startLineNumber : range.startLineNumber; @@ -289,10 +298,15 @@ export class TextSearchMatch implements ITextSearchMatch { } } -function isSingleLineRange(range: ISearchRange | ISearchRange[]): boolean { - return Array.isArray(range) ? - range[0].startLineNumber === range[0].endLineNumber : - range.startLineNumber === range.endLineNumber; +function isSingleLineRangeList(ranges: ISearchRange[]): boolean { + const line = ranges[0].startLineNumber; + for (const r of ranges) { + if (r.startLineNumber !== line || r.endLineNumber !== line) { + return false; + } + } + + return true; } export class SearchRange implements ISearchRange { diff --git a/src/vs/workbench/services/search/test/common/search.test.ts b/src/vs/workbench/services/search/test/common/search.test.ts index 94088dcb341..2656fe8c0c7 100644 --- a/src/vs/workbench/services/search/test/common/search.test.ts +++ b/src/vs/workbench/services/search/test/common/search.test.ts @@ -95,6 +95,20 @@ suite('TextSearchResult', () => { assert.equal((result.preview.matches).endColumn, 3); }); + test('compacts multiple ranges on long lines', () => { + const previewOptions: ITextSearchPreviewOptions = { + matchLines: 1, + charsPerLine: 10 + }; + + const range1 = new SearchRange(5, 4, 5, 7); + const range2 = new SearchRange(5, 53, 5, 56); + const range3 = new SearchRange(5, 61, 5, 64); + const result = new TextSearchMatch('foo bar 1234567890123456789012345678901234567890 foo bar baz bar', [range1, range2, range3], previewOptions); + assert.deepEqual(result.preview.matches, [new SearchRange(0, 4, 0, 7), new SearchRange(0, 19, 0, 22), new SearchRange(0, 27, 0, 30)]); + assert.equal(result.preview.text, 'foo bar 123456...o bar baz bar'); + }); + // test('all lines of multiline match', () => { // const previewOptions: ITextSearchPreviewOptions = { // matchLines: 5, From 809db2993bc0f4ef6c4d9ec2211caa673010b19f Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 10 Nov 2020 12:08:59 -0800 Subject: [PATCH 2/6] fixup! --- src/vs/workbench/services/search/common/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index 259af6cff37..31040e096e6 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -286,7 +286,7 @@ export class TextSearchMatch implements ITextSearchMatch { lastEnd = previewEnd; } - this.preview = { text: result, matches: matches.length === 1 ? matches[0] : matches }; + this.preview = { text: result, matches: Array.isArray(this.ranges) ? matches : matches[0] }; } else { const firstMatchLine = Array.isArray(range) ? range[0].startLineNumber : range.startLineNumber; From 046654ae65746bbc8ee0f3edeecbf71bd9788dc3 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 10 Nov 2020 15:57:03 -0800 Subject: [PATCH 3/6] make search editor ranges work for hidden text --- extensions/search-result/src/extension.ts | 53 ++++++++++++++----- .../services/search/common/search.ts | 13 +++-- .../search/test/common/search.test.ts | 10 ++-- 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/extensions/search-result/src/extension.ts b/extensions/search-result/src/extension.ts index ba6f3cf7b82..086a51e69d8 100644 --- a/extensions/search-result/src/extension.ts +++ b/extensions/search-result/src/extension.ts @@ -8,6 +8,7 @@ import * as pathUtils from 'path'; const FILE_LINE_REGEX = /^(\S.*):$/; const RESULT_LINE_REGEX = /^(\s+)(\d+)(:| )(\s+)(.*)$/; +const ELISION_REGEX = /\.{3}\(([0-9]+) characters skipped\)\.{3}/g; const SEARCH_RESULT_SELECTOR = { language: 'search-result', exclusive: true }; const DIRECTIVES = ['# Query:', '# Flags:', '# Including:', '# Excluding:', '# ContextLines:']; const FLAGS = ['RegExp', 'CaseSensitive', 'IgnoreExcludeSettings', 'WordMatch']; @@ -80,12 +81,18 @@ export function activate(context: vscode.ExtensionContext) { return lineResult.allLocations; } - const translateRangeSidewaysBy = (r: vscode.Range, n: number) => - r.with({ start: new vscode.Position(r.start.line, Math.max(0, n - r.start.character)), end: new vscode.Position(r.end.line, Math.max(0, n - r.end.character)) }); + const location = lineResult.locations.find(l => l.originSelectionRange.contains(position)); + if (!location) { + return []; + } + const targetPos = new vscode.Position( + location.targetSelectionRange.start.line, + location.targetSelectionRange.start.character + (position.character - location.originSelectionRange.start.character) + ); return [{ - ...lineResult.location, - targetSelectionRange: translateRangeSidewaysBy(lineResult.location.targetSelectionRange!, position.character - 1) + ...location, + targetSelectionRange: new vscode.Range(targetPos, targetPos), }]; } }), @@ -93,7 +100,7 @@ export function activate(context: vscode.ExtensionContext) { vscode.languages.registerDocumentLinkProvider(SEARCH_RESULT_SELECTOR, { async provideDocumentLinks(document: vscode.TextDocument, token: vscode.CancellationToken): Promise { return parseSearchResults(document, token) - .filter(({ type }) => type === 'file') + .filter(isFileLine) .map(({ location }) => ({ range: location.originSelectionRange!, target: location.targetUri })); } }), @@ -162,7 +169,7 @@ function relativePathToUri(path: string, resultsUri: vscode.Uri): vscode.Uri | u } type ParsedSearchFileLine = { type: 'file', location: vscode.LocationLink, allLocations: vscode.LocationLink[], path: string }; -type ParsedSearchResultLine = { type: 'result', location: vscode.LocationLink, isContext: boolean, prefixRange: vscode.Range }; +type ParsedSearchResultLine = { type: 'result', locations: Required[], isContext: boolean, prefixRange: vscode.Range }; type ParsedSearchResults = Array; const isFileLine = (line: ParsedSearchResultLine | ParsedSearchFileLine): line is ParsedSearchFileLine => line.type === 'file'; const isResultLine = (line: ParsedSearchResultLine | ParsedSearchFileLine): line is ParsedSearchResultLine => line.type === 'result'; @@ -211,17 +218,35 @@ function parseSearchResults(document: vscode.TextDocument, token?: vscode.Cancel const lineNumber = +_lineNumber - 1; const resultStart = (indentation + _lineNumber + seperator + resultIndentation).length; const metadataOffset = (indentation + _lineNumber + seperator).length; + const targetRange = new vscode.Range(Math.max(lineNumber - 3, 0), 0, lineNumber + 3, line.length); - const location: vscode.LocationLink = { - targetRange: new vscode.Range(Math.max(lineNumber - 3, 0), 0, lineNumber + 3, line.length), - targetSelectionRange: new vscode.Range(lineNumber, metadataOffset, lineNumber, metadataOffset), - targetUri: currentTarget, - originSelectionRange: new vscode.Range(i, resultStart, i, line.length), - }; + let lastEnd = resultStart; + let offset = 0; + let locations: Required[] = []; + ELISION_REGEX.lastIndex = resultStart - 1; + for (let match: RegExpExecArray | null; (match = ELISION_REGEX.exec(line));) { + locations.push({ + targetRange, + targetSelectionRange: new vscode.Range(lineNumber, offset, lineNumber, offset), + targetUri: currentTarget, + originSelectionRange: new vscode.Range(i, lastEnd, i, ELISION_REGEX.lastIndex), + }); - currentTargetLocations?.push(location); + offset += (ELISION_REGEX.lastIndex - lastEnd) + Number(match[1]); + lastEnd = ELISION_REGEX.lastIndex + match[0].length; + } - links[i] = { type: 'result', location, isContext: seperator === ' ', prefixRange: new vscode.Range(i, 0, i, metadataOffset) }; + if (lastEnd < line.length) { + locations.push({ + targetRange, + targetSelectionRange: new vscode.Range(lineNumber, offset, lineNumber, offset), + targetUri: currentTarget, + originSelectionRange: new vscode.Range(i, lastEnd, i, line.length), + }); + } + + currentTargetLocations?.push(...locations); + links[i] = { type: 'result', locations, isContext: seperator === ' ', prefixRange: new vscode.Range(i, 0, i, metadataOffset) }; } } diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index 31040e096e6..3636b6468b6 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -24,7 +24,11 @@ export const VIEW_ID = 'workbench.view.search'; export const SEARCH_EXCLUDE_CONFIG = 'search.exclude'; -const SEARCH_SINGLE_RANGE_DIVIDER = '...'; +// Warning: this pattern is used in the search editor to detect offsets. If you +// change this, also change the search-result built-in extension +const SEARCH_ELIDED_PREFIX = '...('; +const SEARCH_ELIDED_SUFFIX = ' characters skipped)...'; +const SEARCH_ELIDED_MIN_LEN = (SEARCH_ELIDED_PREFIX.length + SEARCH_ELIDED_SUFFIX.length + 5) * 2; export const ISearchService = createDecorator('searchService'); @@ -275,9 +279,10 @@ export class TextSearchMatch implements ITextSearchMatch { for (const range of ranges) { const previewStart = Math.max(range.startColumn - leadingChars, 0); const previewEnd = range.startColumn + previewOptions.charsPerLine; - if (previewStart > lastEnd + leadingChars) { - result += SEARCH_SINGLE_RANGE_DIVIDER + text.slice(previewStart, previewEnd); - shift += previewStart - (lastEnd + SEARCH_SINGLE_RANGE_DIVIDER.length); + if (previewStart > lastEnd + leadingChars + SEARCH_ELIDED_MIN_LEN) { + const elision = SEARCH_ELIDED_PREFIX + (previewStart - lastEnd) + SEARCH_ELIDED_SUFFIX; + result += elision + text.slice(previewStart, previewEnd); + shift += previewStart - (lastEnd + elision.length); } else { result += text.slice(lastEnd, previewEnd); } diff --git a/src/vs/workbench/services/search/test/common/search.test.ts b/src/vs/workbench/services/search/test/common/search.test.ts index 2656fe8c0c7..0f044eb2229 100644 --- a/src/vs/workbench/services/search/test/common/search.test.ts +++ b/src/vs/workbench/services/search/test/common/search.test.ts @@ -102,11 +102,11 @@ suite('TextSearchResult', () => { }; const range1 = new SearchRange(5, 4, 5, 7); - const range2 = new SearchRange(5, 53, 5, 56); - const range3 = new SearchRange(5, 61, 5, 64); - const result = new TextSearchMatch('foo bar 1234567890123456789012345678901234567890 foo bar baz bar', [range1, range2, range3], previewOptions); - assert.deepEqual(result.preview.matches, [new SearchRange(0, 4, 0, 7), new SearchRange(0, 19, 0, 22), new SearchRange(0, 27, 0, 30)]); - assert.equal(result.preview.text, 'foo bar 123456...o bar baz bar'); + const range2 = new SearchRange(5, 133, 5, 136); + const range3 = new SearchRange(5, 141, 5, 144); + const result = new TextSearchMatch('foo bar 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 foo bar baz bar', [range1, range2, range3], previewOptions); + assert.deepEqual(result.preview.matches, [new SearchRange(0, 4, 0, 7), new SearchRange(0, 46, 0, 49), new SearchRange(0, 54, 0, 57)]); + assert.equal(result.preview.text, 'foo bar 123456...(117 characters skipped)...o bar baz bar'); }); // test('all lines of multiline match', () => { From 00f32f9a26db6559edb443dfb022d232f806a480 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 10 Nov 2020 16:04:00 -0800 Subject: [PATCH 4/6] make search editor ranges work for hidden text --- extensions/search-result/src/extension.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/search-result/src/extension.ts b/extensions/search-result/src/extension.ts index 086a51e69d8..6682c1473bf 100644 --- a/extensions/search-result/src/extension.ts +++ b/extensions/search-result/src/extension.ts @@ -223,17 +223,17 @@ function parseSearchResults(document: vscode.TextDocument, token?: vscode.Cancel let lastEnd = resultStart; let offset = 0; let locations: Required[] = []; - ELISION_REGEX.lastIndex = resultStart - 1; + ELISION_REGEX.lastIndex = resultStart; for (let match: RegExpExecArray | null; (match = ELISION_REGEX.exec(line));) { locations.push({ targetRange, targetSelectionRange: new vscode.Range(lineNumber, offset, lineNumber, offset), targetUri: currentTarget, - originSelectionRange: new vscode.Range(i, lastEnd, i, ELISION_REGEX.lastIndex), + originSelectionRange: new vscode.Range(i, lastEnd, i, ELISION_REGEX.lastIndex - match[0].length), }); - offset += (ELISION_REGEX.lastIndex - lastEnd) + Number(match[1]); - lastEnd = ELISION_REGEX.lastIndex + match[0].length; + offset += (ELISION_REGEX.lastIndex - lastEnd - match[0].length) + Number(match[1]); + lastEnd = ELISION_REGEX.lastIndex; } if (lastEnd < line.length) { From f5898a0e59801a94cbd746bdcb034371c1059e3c Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 10 Nov 2020 22:45:08 -0800 Subject: [PATCH 5/6] surround match in zero-width spaces to avoid clobbering --- extensions/search-result/src/extension.ts | 2 +- src/vs/workbench/services/search/common/search.ts | 4 ++-- src/vs/workbench/services/search/test/common/search.test.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/search-result/src/extension.ts b/extensions/search-result/src/extension.ts index 6682c1473bf..e24e3f54f92 100644 --- a/extensions/search-result/src/extension.ts +++ b/extensions/search-result/src/extension.ts @@ -8,7 +8,7 @@ import * as pathUtils from 'path'; const FILE_LINE_REGEX = /^(\S.*):$/; const RESULT_LINE_REGEX = /^(\s+)(\d+)(:| )(\s+)(.*)$/; -const ELISION_REGEX = /\.{3}\(([0-9]+) characters skipped\)\.{3}/g; +const ELISION_REGEX = /\.{3}\(\u200b([0-9]+) characters skipped\u200b\)\.{3}/g; const SEARCH_RESULT_SELECTOR = { language: 'search-result', exclusive: true }; const DIRECTIVES = ['# Query:', '# Flags:', '# Including:', '# Excluding:', '# ContextLines:']; const FLAGS = ['RegExp', 'CaseSensitive', 'IgnoreExcludeSettings', 'WordMatch']; diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index 3636b6468b6..b0155dae3fc 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -26,8 +26,8 @@ export const SEARCH_EXCLUDE_CONFIG = 'search.exclude'; // Warning: this pattern is used in the search editor to detect offsets. If you // change this, also change the search-result built-in extension -const SEARCH_ELIDED_PREFIX = '...('; -const SEARCH_ELIDED_SUFFIX = ' characters skipped)...'; +const SEARCH_ELIDED_PREFIX = '...(\u200b'; +const SEARCH_ELIDED_SUFFIX = ' characters skipped\u200b)...'; const SEARCH_ELIDED_MIN_LEN = (SEARCH_ELIDED_PREFIX.length + SEARCH_ELIDED_SUFFIX.length + 5) * 2; export const ISearchService = createDecorator('searchService'); diff --git a/src/vs/workbench/services/search/test/common/search.test.ts b/src/vs/workbench/services/search/test/common/search.test.ts index 0f044eb2229..55310a25f7e 100644 --- a/src/vs/workbench/services/search/test/common/search.test.ts +++ b/src/vs/workbench/services/search/test/common/search.test.ts @@ -105,8 +105,8 @@ suite('TextSearchResult', () => { const range2 = new SearchRange(5, 133, 5, 136); const range3 = new SearchRange(5, 141, 5, 144); const result = new TextSearchMatch('foo bar 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 foo bar baz bar', [range1, range2, range3], previewOptions); - assert.deepEqual(result.preview.matches, [new SearchRange(0, 4, 0, 7), new SearchRange(0, 46, 0, 49), new SearchRange(0, 54, 0, 57)]); - assert.equal(result.preview.text, 'foo bar 123456...(117 characters skipped)...o bar baz bar'); + assert.deepEqual(result.preview.matches, [new SearchRange(0, 4, 0, 7), new SearchRange(0, 48, 0, 51), new SearchRange(0, 56, 0, 59)]); + assert.equal(result.preview.text, 'foo bar 123456...(\u200b117 characters skipped\u200b)...o bar baz bar'); }); // test('all lines of multiline match', () => { From 49d1396aeb154bd57789330799dfa59c81469f89 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Wed, 11 Nov 2020 10:11:04 -0800 Subject: [PATCH 6/6] update pattern and add to grammar --- extensions/search-result/src/extension.ts | 2 +- extensions/search-result/syntaxes/generateTMLanguage.js | 5 +++++ .../search-result/syntaxes/searchResult.tmLanguage.json | 4 ++++ src/vs/workbench/services/search/common/search.ts | 4 ++-- src/vs/workbench/services/search/test/common/search.test.ts | 4 ++-- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/extensions/search-result/src/extension.ts b/extensions/search-result/src/extension.ts index e24e3f54f92..6bc5a573c95 100644 --- a/extensions/search-result/src/extension.ts +++ b/extensions/search-result/src/extension.ts @@ -8,7 +8,7 @@ import * as pathUtils from 'path'; const FILE_LINE_REGEX = /^(\S.*):$/; const RESULT_LINE_REGEX = /^(\s+)(\d+)(:| )(\s+)(.*)$/; -const ELISION_REGEX = /\.{3}\(\u200b([0-9]+) characters skipped\u200b\)\.{3}/g; +const ELISION_REGEX = /⟪ ([0-9]+) characters skipped ⟫/g; const SEARCH_RESULT_SELECTOR = { language: 'search-result', exclusive: true }; const DIRECTIVES = ['# Query:', '# Flags:', '# Including:', '# Excluding:', '# ContextLines:']; const FLAGS = ['RegExp', 'CaseSensitive', 'IgnoreExcludeSettings', 'WordMatch']; diff --git a/extensions/search-result/syntaxes/generateTMLanguage.js b/extensions/search-result/syntaxes/generateTMLanguage.js index fb74d3696ef..c0170e514f9 100644 --- a/extensions/search-result/syntaxes/generateTMLanguage.js +++ b/extensions/search-result/syntaxes/generateTMLanguage.js @@ -83,6 +83,7 @@ const scopes = { meta: 'meta.resultLine.search', metaSingleLine: 'meta.resultLine.singleLine.search', metaMultiLine: 'meta.resultLine.multiLine.search', + elision: 'comment meta.resultLine.elision', prefix: { meta: 'constant.numeric.integer meta.resultLinePrefix.search', metaContext: 'meta.resultLinePrefix.contextLinePrefix.search', @@ -220,6 +221,10 @@ const plainText = [ '4': { name: [scopes.resultBlock.result.prefix.meta, scopes.resultBlock.result.prefix.metaContext].join(' ') }, '5': { name: scopes.resultBlock.result.prefix.lineNumber }, } + }, + { + match: '⟪ [0-9]+ characters skipped ⟫', + name: [scopes.resultBlock.meta, scopes.resultBlock.result.elision].join(' '), } ]; diff --git a/extensions/search-result/syntaxes/searchResult.tmLanguage.json b/extensions/search-result/syntaxes/searchResult.tmLanguage.json index e2687fe8a72..e319191c41f 100644 --- a/extensions/search-result/syntaxes/searchResult.tmLanguage.json +++ b/extensions/search-result/syntaxes/searchResult.tmLanguage.json @@ -263,6 +263,10 @@ "name": "meta.resultLinePrefix.lineNumber.search" } } + }, + { + "match": "⟪ [0-9]+ characters skipped ⟫", + "name": "meta.resultBlock.search comment meta.resultLine.elision" } ], "repository": { diff --git a/src/vs/workbench/services/search/common/search.ts b/src/vs/workbench/services/search/common/search.ts index b0155dae3fc..cfa4b7f2b06 100644 --- a/src/vs/workbench/services/search/common/search.ts +++ b/src/vs/workbench/services/search/common/search.ts @@ -26,8 +26,8 @@ export const SEARCH_EXCLUDE_CONFIG = 'search.exclude'; // Warning: this pattern is used in the search editor to detect offsets. If you // change this, also change the search-result built-in extension -const SEARCH_ELIDED_PREFIX = '...(\u200b'; -const SEARCH_ELIDED_SUFFIX = ' characters skipped\u200b)...'; +const SEARCH_ELIDED_PREFIX = '⟪ '; +const SEARCH_ELIDED_SUFFIX = ' characters skipped ⟫'; const SEARCH_ELIDED_MIN_LEN = (SEARCH_ELIDED_PREFIX.length + SEARCH_ELIDED_SUFFIX.length + 5) * 2; export const ISearchService = createDecorator('searchService'); diff --git a/src/vs/workbench/services/search/test/common/search.test.ts b/src/vs/workbench/services/search/test/common/search.test.ts index 55310a25f7e..0eecae8c6df 100644 --- a/src/vs/workbench/services/search/test/common/search.test.ts +++ b/src/vs/workbench/services/search/test/common/search.test.ts @@ -105,8 +105,8 @@ suite('TextSearchResult', () => { const range2 = new SearchRange(5, 133, 5, 136); const range3 = new SearchRange(5, 141, 5, 144); const result = new TextSearchMatch('foo bar 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 foo bar baz bar', [range1, range2, range3], previewOptions); - assert.deepEqual(result.preview.matches, [new SearchRange(0, 4, 0, 7), new SearchRange(0, 48, 0, 51), new SearchRange(0, 56, 0, 59)]); - assert.equal(result.preview.text, 'foo bar 123456...(\u200b117 characters skipped\u200b)...o bar baz bar'); + assert.deepEqual(result.preview.matches, [new SearchRange(0, 4, 0, 7), new SearchRange(0, 42, 0, 45), new SearchRange(0, 50, 0, 53)]); + assert.equal(result.preview.text, 'foo bar 123456⟪ 117 characters skipped ⟫o bar baz bar'); }); // test('all lines of multiline match', () => {