Change:
Issue Type: <bBug</bany file which contains word consisting of letters with underscores (f.e. helloworld). For simplicity let's assume only one underscore is present. cursor in various places of this word and activate expand selection command (either via keyboard shortcut or keybinding) : 3a. cursor is not near underscore (underscore is not immediately to the left or right of cursor) - part of the word selected, bounded by word beginning/end and underscore - OK 3b. underscore is immediately left to the cursor - part of word to the right of cursor is selected - OK 3c. underscore is immediately right to the cursor - the whole word is selected - UNEXPECTED. For 3c I expected only part of the word selected as well, not the whole word. VS Code version: Code 1.42.0 (, 2020-02-06T10:51:34.058Z) OS version: WindowsNT x64 10.0. <details<summarySystem Info</summary </details<details<summaryExtensions (10)</summaryExtensionVersion ------ quick-open-prefill-selection0.0.1 vscode-eslint2.0.15 gitlens10.2.1 EditorConfig0.14.4 vscode-great-icons2.1.47 intellij-idea-keybindings0.2.37 camelcasenavigation1.1.1 material-icon-theme3.9.3 partial-diff1.4.1 terminal-tabs0.2.0 (5 theme extensions excluded) </details<!-- generated by issue reporter --
Tried to fix this in the PR PS - this is my first PR for a OSS, ever... please forgive me for any mistake or misconduct.

Discussion:
// -- bracket selections async function assertRanges(provider: SelectionRangeProvider, value: string, ...expected: IRange[]): Promise<void> { <ins> let index = value.indexOf('|'); value = value.replace('|', ''); </ins> let model = modelService.createModel(value, new StaticLanguageSelector(mode.getLanguageIdentifier()), URI.parse('fake:lang')); <del> let pos = model.getPositionAt(value.indexOf('|')); </del> <ins> let pos = model.getPositionAt(index); </ins> let all = await provider.provideSelectionRanges(model, [pos], CancellationToken.None); let ranges = all![0];

test('bracket selection', async () => { await assertRanges(new BracketSelectionRangeProvider(), '(|)', <del> new Range(1, 2, 1, 3), new Range(1, 1, 1, 4) </del> <ins> new Range(1, 2, 1, 2), new Range(1, 1, 1, 3) </ins> ); await assertRanges(new BracketSelectionRangeProvider(), '[[[](|)]]', <del> new Range(1, 6, 1, 7), new Range(1, 5, 1, 8), // () new Range(1, 3, 1, 8), new Range(1, 2, 1, 9), // [[]()] new Range(1, 2, 1, 9), new Range(1, 1, 1, 10), // [[[]()]] </del> <ins> new Range(1, 6, 1, 6), new Range(1, 5, 1, 7), // () new Range(1, 3, 1, 7), new Range(1, 2, 1, 8), // [[]()] new Range(1, 2, 1, 8), new Range(1, 1, 1, 9), // [[[]()]] </ins> ); await assertRanges(new BracketSelectionRangeProvider(), '[a[](|)a]', <del> new Range(1, 6, 1, 7), new Range(1, 5, 1, 8), new Range(1, 2, 1, 9), new Range(1, 1, 1, 10), </del> <ins> new Range(1, 6, 1, 6), new Range(1, 5, 1, 7), new Range(1, 2, 1, 8), new Range(1, 1, 1, 9), </ins> ); // no bracket

await assertRanges(new BracketSelectionRangeProvider(), '|[[[]()]]'); // edge <del> await assertRanges(new BracketSelectionRangeProvider(), '[|[[]()]]', new Range(1, 2, 1, 9), new Range(1, 1, 1, 10)); await assertRanges(new BracketSelectionRangeProvider(), '[[[]()]|]', new Range(1, 2, 1, 9), new Range(1, 1, 1, 10)); </del> <ins> await assertRanges(new BracketSelectionRangeProvider(), '[|[[]()]]', new Range(1, 2, 1, 8), new Range(1, 1, 1, 9)); await assertRanges(new BracketSelectionRangeProvider(), '[[[]()]|]', new Range(1, 2, 1, 8), new Range(1, 1, 1, 9)); </ins> <del> await assertRanges(new BracketSelectionRangeProvider(), 'aaa(aaa)bbb(b|b)ccc(ccc)', new Range(1, 13, 1, 16), new Range(1, 12, 1, 17)); await assertRanges(new BracketSelectionRangeProvider(), '(aaa(aaa)bbb(b|b)ccc(ccc))', new Range(1, 14, 1, 17), new Range(1, 13, 1, 18), new Range(1, 2, 1, 26), new Range(1, 1, 1, 27)); </del> <ins> await assertRanges(new BracketSelectionRangeProvider(), 'aaa(aaa)bbb(b|b)ccc(ccc)', new Range(1, 13, 1, 15), new Range(1, 12, 1, 16)); await assertRanges(new BracketSelectionRangeProvider(), '(aaa(aaa)bbb(b|b)ccc(ccc))', new Range(1, 14, 1, 16), new Range(1, 13, 1, 17), new Range(1, 2, 1, 25), new Range(1, 1, 1, 26)); </ins> }); test('bracket with leading/trailing', async () => { await assertRanges(new BracketSelectionRangeProvider(), 'for(a of b){n  foo(|);n}', <del> new Range(2, 7, 2, 8), new Range(2, 6, 2, 9), </del> <ins> new Range(2, 7, 2, 7), new Range(2, 6, 2, 8), </ins> new Range(1, 13, 3, 1), new Range(1, 12, 3, 2), new Range(1, 1, 3, 2), new Range(1, 1, 3, 2), ); await assertRanges(new BracketSelectionRangeProvider(), 'for(a of b)n{n  foo(|);n}', <del> new Range(3, 7, 3, 8), new Range(3, 6, 3, 9), </del> <ins> new Range(3, 7, 3, 7), new Range(3, 6, 3, 8), </ins> new Range(2, 2, 4, 1), new Range(2, 1, 4, 2), new Range(1, 1, 4, 2), new Range(1, 1, 4, 2), );

test('in-word ranges', async () => { await assertRanges(new WordSelectionRangeProvider(), 'f|ooBar', <del> new Range(1, 1, 1, 5), // foo new Range(1, 1, 1, 8), // fooBar new Range(1, 1, 1, 8), // doc </del> <ins> new Range(1, 1, 1, 4), // foo new Range(1, 1, 1, 7), // fooBar new Range(1, 1, 1, 7), // doc </ins> ); await assertRanges(new WordSelectionRangeProvider(), 'f|oo_Ba', <del> new Range(1, 1, 1, 5), new Range(1, 1, 1, 8), new Range(1, 1, 1, 8), </del> <ins> new Range(1, 1, 1, 4), new Range(1, 1, 1, 7), new Range(1, 1, 1, 7), </ins> ); await assertRanges(new WordSelectionRangeProvider(), 'f|oo-Ba', <del> new Range(1, 1, 1, 5), new Range(1, 1, 1, 8), new Range(1, 1, 1, 8), </del> <ins> new Range(1, 1, 1, 4), new Range(1, 1, 1, 7), new Range(1, 1, 1, 7), </ins> ); }); test('Default selection should select current word/hump first in camelCase #67493', async function () { await assertRanges(new WordSelectionRangeProvider(), 'Abs|tractSmartSelect', <del> new Range(1, 1, 1, 10), new Range(1, 1, 1, 21), new Range(1, 1, 1, 21), </del> <ins> new Range(1, 1, 1, 9), new Range(1, 1, 1, 20), new Range(1, 1, 1, 20), </ins> ); await assertRanges(new WordSelectionRangeProvider(), 'AbstractSma|rtSelect', <del> new Range(1, 9, 1, 15), new Range(1, 1, 1, 21), new Range(1, 1, 1, 21), </del> <ins> new Range(1, 9, 1, 14), new Range(1, 1, 1, 20), new Range(1, 1, 1, 20), </ins> ); await assertRanges(new WordSelectionRangeProvider(), 'Abstrac-Sma|rt-elect', <del> new Range(1, 9, 1, 15), new Range(1, 1, 1, 21), new Range(1, 1, 1, 21), </del> <ins> new Range(1, 9, 1, 14), new Range(1, 1, 1, 20), new Range(1, 1, 1, 20), </ins> ); await assertRanges(new WordSelectionRangeProvider(), 'Abstrac_Sma|rt_elect', <del> new Range(1, 9, 1, 15), new Range(1, 1, 1, 21), new Range(1, 1, 1, 21), </del> <ins> new Range(1, 9, 1, 14), new Range(1, 1, 1, 20), new Range(1, 1, 1, 20), </ins> ); await assertRanges(new WordSelectionRangeProvider(), 'Abstrac_Sma|rt-elect', <del> new Range(1, 9, 1, 15), new Range(1, 1, 1, 21), new Range(1, 1, 1, 21), </del> <ins> new Range(1, 9, 1, 14), new Range(1, 1, 1, 20), new Range(1, 1, 1, 20), </ins> ); await assertRanges(new WordSelectionRangeProvider(), 'Abstrac_Sma|rtSelect', <del> new Range(1, 9, 1, 15), new Range(1, 1, 1, 21), new Range(1, 1, 1, 21), </del> <ins> new Range(1, 9, 1, 14), new Range(1, 1, 1, 20), new Range(1, 1, 1, 20), </ins> ); });

reg.dispose(); }); <ins> test('Expand selection in words with underscores is inconsistent #90589', async function () { await assertRanges(new WordSelectionRangeProvider(), 'Hel|lo_World', new Range(1, 1, 1, 6), new Range(1, 1, 1, 12), new Range(1, 1, 1, 12), ); await assertRanges(new WordSelectionRangeProvider(), 'Hello_Wo|rld', new Range(1, 7, 1, 12), new Range(1, 1, 1, 12), new Range(1, 1, 1, 12), ); await assertRanges(new WordSelectionRangeProvider(), 'Hello|_World', new Range(1, 1, 1, 6), new Range(1, 1, 1, 12), new Range(1, 1, 1, 12), ); await assertRanges(new WordSelectionRangeProvider(), 'Hello_|World', new Range(1, 7, 1, 12), new Range(1, 1, 1, 12), new Range(1, 1, 1, 12), ); await assertRanges(new WordSelectionRangeProvider(), 'Hello|-World', new Range(1, 1, 1, 6), new Range(1, 1, 1, 12), new Range(1, 1, 1, 12), ); await assertRanges(new WordSelectionRangeProvider(), 'Hello-|World', new Range(1, 7, 1, 12), new Range(1, 1, 1, 12), new Range(1, 1, 1, 12), ); await assertRanges(new WordSelectionRangeProvider(), 'Hello|World', new Range(1, 6, 1, 11), new Range(1, 1, 1, 11), new Range(1, 1, 1, 11), ); }); </ins> });

// LEFT anchor (start) for (; start >= 0; start--) { let ch = word.charCodeAt(start); <del> if (ch === CharCode.Underline || ch === CharCode.Dash) { </del> <ins> if ((start !== offset) && (ch === CharCode.Underline || ch === CharCode.Dash)) { </ins> // foo-bar OR foo_bar break; } else if (isLowerAsciiLetter(ch) && isUpperAsciiLetter(lastCh)) {