search: fix freezing ui on long lines

Fixes https://github.com/microsoft/vscode/issues/109902
This commit is contained in:
Connor Peet 2020-11-09 16:15:17 -08:00
parent e300dfcdd2
commit df7fdd6515
No known key found for this signature in database
GPG key ID: CF8FD2EA0DBC61BD
3 changed files with 46 additions and 21 deletions

5
.vscode/launch.json vendored
View file

@ -41,10 +41,7 @@
"port": 5876,
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"presentation": {
"hidden": true,
}
]
},
{
"type": "node",

View file

@ -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<ISearchService>('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 {

View file

@ -95,6 +95,20 @@ suite('TextSearchResult', () => {
assert.equal((<SearchRange>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,