Skip to content

Commit c081cac

Browse files
committed
Add option for smartSelect to ignore subwords
Fixes microsoft#97257
1 parent 3196eb9 commit c081cac

File tree

6 files changed

+39
-7
lines changed

6 files changed

+39
-7
lines changed

src/vs/editor/common/config/editorOptions.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4603,6 +4603,7 @@ class EditorSuggest extends BaseEditorOption<EditorOption.suggest, ISuggestOptio
46034603

46044604
export interface ISmartSelectOptions {
46054605
selectLeadingAndTrailingWhitespace?: boolean;
4606+
selectSubwords?: boolean;
46064607
}
46074608

46084609
/**
@@ -4616,13 +4617,19 @@ class SmartSelect extends BaseEditorOption<EditorOption.smartSelect, ISmartSelec
46164617
super(
46174618
EditorOption.smartSelect, 'smartSelect',
46184619
{
4619-
selectLeadingAndTrailingWhitespace: true
4620+
selectLeadingAndTrailingWhitespace: true,
4621+
selectSubwords: true,
46204622
},
46214623
{
46224624
'editor.smartSelect.selectLeadingAndTrailingWhitespace': {
46234625
description: nls.localize('selectLeadingAndTrailingWhitespace', "Whether leading and trailing whitespace should always be selected."),
46244626
default: true,
46254627
type: 'boolean'
4628+
},
4629+
'editor.smartSelect.selectSubwords': {
4630+
description: nls.localize('selectSubwords', "Whether subwords (like 'foo' in 'fooBar' or 'foo_bar') should be selected."),
4631+
default: true,
4632+
type: 'boolean'
46264633
}
46274634
}
46284635
);
@@ -4633,7 +4640,8 @@ class SmartSelect extends BaseEditorOption<EditorOption.smartSelect, ISmartSelec
46334640
return this.defaultValue;
46344641
}
46354642
return {
4636-
selectLeadingAndTrailingWhitespace: boolean((input as ISmartSelectOptions).selectLeadingAndTrailingWhitespace, this.defaultValue.selectLeadingAndTrailingWhitespace)
4643+
selectLeadingAndTrailingWhitespace: boolean((input as ISmartSelectOptions).selectLeadingAndTrailingWhitespace, this.defaultValue.selectLeadingAndTrailingWhitespace),
4644+
selectSubwords: boolean((input as ISmartSelectOptions).selectSubwords, this.defaultValue.selectSubwords),
46374645
};
46384646
}
46394647
}

src/vs/editor/contrib/smartSelect/browser/smartSelect.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,13 @@ registerEditorAction(ShrinkSelectionAction);
208208

209209
export interface SelectionRangesOptions {
210210
selectLeadingAndTrailingWhitespace: boolean;
211+
selectSubwords: boolean;
211212
}
212213

213214
export async function provideSelectionRanges(registry: LanguageFeatureRegistry<languages.SelectionRangeProvider>, model: ITextModel, positions: Position[], options: SelectionRangesOptions, token: CancellationToken): Promise<Range[][]> {
214215

215216
const providers = registry.all(model)
216-
.concat(new WordSelectionRangeProvider()); // ALWAYS have word based selection range
217+
.concat(new WordSelectionRangeProvider(options.selectSubwords)); // ALWAYS have word based selection range
217218

218219
if (providers.length === 1) {
219220
// add word selection and bracket selection when no provider exists
@@ -313,7 +314,7 @@ CommandsRegistry.registerCommand('_executeSelectionRangeProvider', async functio
313314
const reference = await accessor.get(ITextModelService).createModelReference(resource);
314315

315316
try {
316-
return provideSelectionRanges(registry, reference.object.textEditorModel, positions, { selectLeadingAndTrailingWhitespace: true }, CancellationToken.None);
317+
return provideSelectionRanges(registry, reference.object.textEditorModel, positions, { selectLeadingAndTrailingWhitespace: true, selectSubwords: true }, CancellationToken.None);
317318
} finally {
318319
reference.dispose();
319320
}

src/vs/editor/contrib/smartSelect/browser/wordSelections.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@ import { SelectionRange, SelectionRangeProvider } from 'vs/editor/common/languag
1212

1313
export class WordSelectionRangeProvider implements SelectionRangeProvider {
1414

15+
constructor(private readonly selectSubwords = true) { }
16+
1517
provideSelectionRanges(model: ITextModel, positions: Position[]): SelectionRange[][] {
1618
const result: SelectionRange[][] = [];
1719
for (const position of positions) {
1820
const bucket: SelectionRange[] = [];
1921
result.push(bucket);
20-
this._addInWordRanges(bucket, model, position);
22+
if (this.selectSubwords) {
23+
this._addInWordRanges(bucket, model, position);
24+
}
2125
this._addWordRanges(bucket, model, position);
2226
this._addWhitespaceLine(bucket, model, position);
2327
bucket.push({ range: model.getFullModelRange() });

src/vs/editor/contrib/smartSelect/test/browser/smartSelect.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ suite('SmartSelect', () => {
6767
async function assertGetRangesToPosition(text: string[], lineNumber: number, column: number, ranges: Range[], selectLeadingAndTrailingWhitespace = true): Promise<void> {
6868
const uri = URI.file('test.js');
6969
const model = modelService.createModel(text.join('\n'), new StaticLanguageSelector(languageId), uri);
70-
const [actual] = await provideSelectionRanges(providers, model, [new Position(lineNumber, column)], { selectLeadingAndTrailingWhitespace }, CancellationToken.None);
70+
const [actual] = await provideSelectionRanges(providers, model, [new Position(lineNumber, column)], { selectLeadingAndTrailingWhitespace, selectSubwords: true }, CancellationToken.None);
7171
const actualStr = actual!.map(r => new Range(r.startLineNumber, r.startColumn, r.endLineNumber, r.endColumn).toString());
7272
const desiredStr = ranges.reverse().map(r => String(r));
7373

@@ -294,6 +294,24 @@ suite('SmartSelect', () => {
294294
);
295295
});
296296

297+
test('in-word ranges with selectSubwords=false', async () => {
298+
299+
await assertRanges(new WordSelectionRangeProvider(false), 'f|ooBar',
300+
new Range(1, 1, 1, 7),
301+
new Range(1, 1, 1, 7),
302+
);
303+
304+
await assertRanges(new WordSelectionRangeProvider(false), 'f|oo_Ba',
305+
new Range(1, 1, 1, 7),
306+
new Range(1, 1, 1, 7),
307+
);
308+
309+
await assertRanges(new WordSelectionRangeProvider(false), 'f|oo-Ba',
310+
new Range(1, 1, 1, 7),
311+
new Range(1, 1, 1, 7),
312+
);
313+
});
314+
297315
test('Default selection should select current word/hump first in camelCase #67493', async function () {
298316

299317
await assertRanges(new WordSelectionRangeProvider(), 'Abs|tractSmartSelect',

src/vs/monaco.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4682,6 +4682,7 @@ declare namespace monaco.editor {
46824682

46834683
export interface ISmartSelectOptions {
46844684
selectLeadingAndTrailingWhitespace?: boolean;
4685+
selectSubwords?: boolean;
46854686
}
46864687

46874688
/**

src/vs/workbench/api/test/browser/extHostLanguageFeatures.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,7 @@ suite('ExtHostLanguageFeatures', function () {
12521252

12531253
await rpcProtocol.sync();
12541254

1255-
provideSelectionRanges(languageFeaturesService.selectionRangeProvider, model, [new Position(1, 17)], { selectLeadingAndTrailingWhitespace: true }, CancellationToken.None).then(ranges => {
1255+
provideSelectionRanges(languageFeaturesService.selectionRangeProvider, model, [new Position(1, 17)], { selectLeadingAndTrailingWhitespace: true, selectSubwords: true }, CancellationToken.None).then(ranges => {
12561256
assert.strictEqual(ranges.length, 1);
12571257
assert.ok(ranges[0].length >= 2);
12581258
});

0 commit comments

Comments
 (0)