diff --git a/src/vs/editor/common/modes/snippetsRegistry.ts b/src/vs/editor/common/modes/snippetsRegistry.ts index 6b861eca8d257382e24fb75bd731f95d6b0c296b..f9e96fbdac734241f616cef52fd7ee048004a294 100644 --- a/src/vs/editor/common/modes/snippetsRegistry.ts +++ b/src/vs/editor/common/modes/snippetsRegistry.ts @@ -102,12 +102,31 @@ class SnippetsRegistry implements ISnippetsRegistry { } } -export function getNonWhitespacePrefix(model: IReadOnlyModel, position: IPosition) : string { +export interface ISimpleModel { + getLineContent(lineNumber): string; +} + +export function getNonWhitespacePrefix(model: ISimpleModel, position: IPosition) : string { + /** + * Do not analyze more characters + */ + const MAX_PREFIX_LENGTH = 100; + let line = model.getLineContent(position.lineNumber).substr(0, position.column - 1); - let match = line.match(/[^\s]+$/); - if (match) { - return match[0]; + + let minChIndex = Math.max(0, line.length - MAX_PREFIX_LENGTH); + for (let chIndex = line.length - 1; chIndex >= minChIndex; chIndex--) { + let ch = line.charAt(chIndex); + + if (/\s/.test(ch)) { + return line.substr(chIndex + 1); + } } + + if (minChIndex === 0) { + return line; + } + return ''; } diff --git a/src/vs/editor/test/common/modes/snippetsRegistry.test.ts b/src/vs/editor/test/common/modes/snippetsRegistry.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f869753e0b36a53460f92cb3b6aa00e8d92facef --- /dev/null +++ b/src/vs/editor/test/common/modes/snippetsRegistry.test.ts @@ -0,0 +1,79 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import {getNonWhitespacePrefix} from 'vs/editor/common/modes/snippetsRegistry'; + +suite('getNonWhitespacePrefix', () => { + + function assertGetNonWhitespacePrefix(line:string, column:number, expected:string): void { + let model = { + getLineContent: (lineNumber:number) => line + }; + let actual = getNonWhitespacePrefix(model, { lineNumber: 1, column: column }); + assert.equal(actual, expected); + } + + test('empty line', () => { + assertGetNonWhitespacePrefix('', 1, ''); + }); + + test('singleWordLine', () => { + assertGetNonWhitespacePrefix('something', 1, ''); + assertGetNonWhitespacePrefix('something', 2, 's'); + assertGetNonWhitespacePrefix('something', 3, 'so'); + assertGetNonWhitespacePrefix('something', 4, 'som'); + assertGetNonWhitespacePrefix('something', 5, 'some'); + assertGetNonWhitespacePrefix('something', 6, 'somet'); + assertGetNonWhitespacePrefix('something', 7, 'someth'); + assertGetNonWhitespacePrefix('something', 8, 'somethi'); + assertGetNonWhitespacePrefix('something', 9, 'somethin'); + assertGetNonWhitespacePrefix('something', 10, 'something'); + }); + + test('two word line', () => { + assertGetNonWhitespacePrefix('something interesting', 1, ''); + assertGetNonWhitespacePrefix('something interesting', 2, 's'); + assertGetNonWhitespacePrefix('something interesting', 3, 'so'); + assertGetNonWhitespacePrefix('something interesting', 4, 'som'); + assertGetNonWhitespacePrefix('something interesting', 5, 'some'); + assertGetNonWhitespacePrefix('something interesting', 6, 'somet'); + assertGetNonWhitespacePrefix('something interesting', 7, 'someth'); + assertGetNonWhitespacePrefix('something interesting', 8, 'somethi'); + assertGetNonWhitespacePrefix('something interesting', 9, 'somethin'); + assertGetNonWhitespacePrefix('something interesting', 10, 'something'); + assertGetNonWhitespacePrefix('something interesting', 11, ''); + assertGetNonWhitespacePrefix('something interesting', 12, 'i'); + assertGetNonWhitespacePrefix('something interesting', 13, 'in'); + assertGetNonWhitespacePrefix('something interesting', 14, 'int'); + assertGetNonWhitespacePrefix('something interesting', 15, 'inte'); + assertGetNonWhitespacePrefix('something interesting', 16, 'inter'); + assertGetNonWhitespacePrefix('something interesting', 17, 'intere'); + assertGetNonWhitespacePrefix('something interesting', 18, 'interes'); + assertGetNonWhitespacePrefix('something interesting', 19, 'interest'); + assertGetNonWhitespacePrefix('something interesting', 20, 'interesti'); + assertGetNonWhitespacePrefix('something interesting', 21, 'interestin'); + assertGetNonWhitespacePrefix('something interesting', 22, 'interesting'); + }); + + test('many separators', () => { + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions?redirectlocale=en-US&redirectslug=JavaScript%2FGuide%2FRegular_Expressions#special-white-space + // \s matches a single white space character, including space, tab, form feed, line feed. + // Equivalent to [ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]. + + assertGetNonWhitespacePrefix('something interesting', 22, 'interesting'); + assertGetNonWhitespacePrefix('something\tinteresting', 22, 'interesting'); + assertGetNonWhitespacePrefix('something\finteresting', 22, 'interesting'); + assertGetNonWhitespacePrefix('something\vinteresting', 22, 'interesting'); + assertGetNonWhitespacePrefix('something\u00a0interesting', 22, 'interesting'); + assertGetNonWhitespacePrefix('something\u2000interesting', 22, 'interesting'); + assertGetNonWhitespacePrefix('something\u2028interesting', 22, 'interesting'); + assertGetNonWhitespacePrefix('something\u3000interesting', 22, 'interesting'); + assertGetNonWhitespacePrefix('something\ufeffinteresting', 22, 'interesting'); + + }); +});