From cd73b23142c5f9939970d41af04bf760ee74c733 Mon Sep 17 00:00:00 2001 From: Daniel Fiori Date: Sun, 17 Jul 2022 19:29:10 -0400 Subject: [PATCH 1/4] Re-enable support for editor.indentSize setting This change allows the indentation size to be distinct from the tab width, when using spaces for indentation. This commit simply reverts e2049cdc and portions of a60beb9d, which had removed this feature. --- .../config/editorConfigurationSchema.ts | 28 ++-- src/vs/editor/common/model.ts | 2 +- .../test/browser/snippetSession.test.ts | 2 +- .../common/model/textModelWithTokens.test.ts | 4 +- .../workbench/api/browser/mainThreadEditor.ts | 9 ++ .../workbench/api/common/extHost.protocol.ts | 2 + .../workbench/api/common/extHostTextEditor.ts | 71 +++++++-- .../test/browser/extHostTextEditor.test.ts | 149 +++++++++++++++++- src/vscode-dts/vscode.d.ts | 11 +- 9 files changed, 245 insertions(+), 33 deletions(-) diff --git a/src/vs/editor/common/config/editorConfigurationSchema.ts b/src/vs/editor/common/config/editorConfigurationSchema.ts index 50f727fa7dc5d..1e43222cb7c58 100644 --- a/src/vs/editor/common/config/editorConfigurationSchema.ts +++ b/src/vs/editor/common/config/editorConfigurationSchema.ts @@ -26,20 +26,20 @@ const editorConfiguration: IConfigurationNode = { minimum: 1, markdownDescription: nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") }, - // 'editor.indentSize': { - // 'anyOf': [ - // { - // type: 'string', - // enum: ['tabSize'] - // }, - // { - // type: 'number', - // minimum: 1 - // } - // ], - // default: 'tabSize', - // markdownDescription: nls.localize('indentSize', "The number of spaces used for indentation or 'tabSize' to use the value from `#editor.tabSize#`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") - // }, + 'editor.indentSize': { + 'anyOf': [ + { + type: 'string', + enum: ['tabSize'] + }, + { + type: 'number', + minimum: 1 + } + ], + default: 'tabSize', + markdownDescription: nls.localize('indentSize', "The number of spaces used for indentation or 'tabSize' to use the value from `#editor.tabSize#`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.") + }, 'editor.insertSpaces': { type: 'boolean', default: EDITOR_MODEL_DEFAULTS.insertSpaces, diff --git a/src/vs/editor/common/model.ts b/src/vs/editor/common/model.ts index 354026fdcb5f2..05896a2bf7f5b 100644 --- a/src/vs/editor/common/model.ts +++ b/src/vs/editor/common/model.ts @@ -436,7 +436,7 @@ export class TextModelResolvedOptions { bracketPairColorizationOptions: BracketPairColorizationOptions; }) { this.tabSize = Math.max(1, src.tabSize | 0); - this.indentSize = src.tabSize | 0; + this.indentSize = Math.max(1, src.indentSize | 0); this.insertSpaces = Boolean(src.insertSpaces); this.defaultEOL = src.defaultEOL | 0; this.trimAutoWhitespace = Boolean(src.trimAutoWhitespace); diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts index 137dfc2bb9f03..aab47e06c9a71 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts @@ -706,7 +706,7 @@ suite('SnippetSession', function () { test('Tabs don\'t get replaced with spaces in snippet transformations #103818', function () { const model = editor.getModel()!; model.setValue('\n{\n \n}'); - model.updateOptions({ insertSpaces: true, tabSize: 2 }); + model.updateOptions({ insertSpaces: true, indentSize: 2 }); editor.setSelections([new Selection(1, 1, 1, 1), new Selection(3, 6, 3, 6)]); const session = new SnippetSession(editor, [ 'function animate () {', diff --git a/src/vs/editor/test/common/model/textModelWithTokens.test.ts b/src/vs/editor/test/common/model/textModelWithTokens.test.ts index 4d4bfcafcc498..39add3ef2877c 100644 --- a/src/vs/editor/test/common/model/textModelWithTokens.test.ts +++ b/src/vs/editor/test/common/model/textModelWithTokens.test.ts @@ -699,7 +699,7 @@ suite('TextModelWithTokens regression tests', () => { }); suite('TextModel.getLineIndentGuide', () => { - function assertIndentGuides(lines: [number, number, number, number, string][], tabSize: number): void { + function assertIndentGuides(lines: [number, number, number, number, string][], indentSize: number): void { const languageId = 'testLang'; const disposables = new DisposableStore(); const instantiationService = createModelServices(disposables); @@ -708,7 +708,7 @@ suite('TextModel.getLineIndentGuide', () => { const text = lines.map(l => l[4]).join('\n'); const model = disposables.add(instantiateTextModel(instantiationService, text, languageId)); - model.updateOptions({ tabSize: tabSize }); + model.updateOptions({ indentSize: indentSize }); const actualIndents = model.guides.getLinesIndentGuides(1, model.getLineCount()); diff --git a/src/vs/workbench/api/browser/mainThreadEditor.ts b/src/vs/workbench/api/browser/mainThreadEditor.ts index 638fe8aa4747b..cbc28f4d953f8 100644 --- a/src/vs/workbench/api/browser/mainThreadEditor.ts +++ b/src/vs/workbench/api/browser/mainThreadEditor.ts @@ -80,6 +80,7 @@ export class MainThreadTextEditorProperties { return { insertSpaces: modelOptions.insertSpaces, tabSize: modelOptions.tabSize, + indentSize: modelOptions.indentSize, cursorStyle: cursorStyle, lineNumbers: lineNumbers }; @@ -146,6 +147,7 @@ export class MainThreadTextEditorProperties { } return ( a.tabSize === b.tabSize + && a.indentSize === b.indentSize && a.insertSpaces === b.insertSpaces && a.cursorStyle === b.cursorStyle && a.lineNumbers === b.lineNumbers @@ -376,6 +378,13 @@ export class MainThreadTextEditor { if (typeof newConfiguration.tabSize !== 'undefined') { newOpts.tabSize = newConfiguration.tabSize; } + if (typeof newConfiguration.indentSize !== 'undefined') { + if (newConfiguration.indentSize === 'tabSize') { + newOpts.indentSize = newOpts.tabSize || creationOpts.tabSize; + } else { + newOpts.indentSize = newConfiguration.indentSize; + } + } this._model.updateOptions(newOpts); } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 8df19f84b7692..7e90c0dd10061 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -203,6 +203,7 @@ export interface MainThreadDocumentsShape extends IDisposable { export interface ITextEditorConfigurationUpdate { tabSize?: number | 'auto'; + indentSize?: number | 'tabSize'; insertSpaces?: boolean | 'auto'; cursorStyle?: TextEditorCursorStyle; lineNumbers?: RenderLineNumbersType; @@ -210,6 +211,7 @@ export interface ITextEditorConfigurationUpdate { export interface IResolvedTextEditorConfiguration { tabSize: number; + indentSize: number; insertSpaces: boolean; cursorStyle: TextEditorCursorStyle; lineNumbers: RenderLineNumbersType; diff --git a/src/vs/workbench/api/common/extHostTextEditor.ts b/src/vs/workbench/api/common/extHostTextEditor.ts index f025cc805c474..427c6f5a9f94a 100644 --- a/src/vs/workbench/api/common/extHostTextEditor.ts +++ b/src/vs/workbench/api/common/extHostTextEditor.ts @@ -143,6 +143,7 @@ export class ExtHostTextEditorOptions { private _logService: ILogService; private _tabSize!: number; + private _indentSize!: number; private _insertSpaces!: boolean; private _cursorStyle!: TextEditorCursorStyle; private _lineNumbers!: TextEditorLineNumbersStyle; @@ -164,6 +165,12 @@ export class ExtHostTextEditorOptions { set tabSize(value: number | string) { that._setTabSize(value); }, + get indentSize(): number | string { + return that._indentSize; + }, + set indentSize(value: number | string) { + that._setIndentSize(value); + }, get insertSpaces(): boolean | string { return that._insertSpaces; }, @@ -187,6 +194,7 @@ export class ExtHostTextEditorOptions { public _accept(source: IResolvedTextEditorConfiguration): void { this._tabSize = source.tabSize; + this._indentSize = source.indentSize; this._insertSpaces = source.insertSpaces; this._cursorStyle = source.cursorStyle; this._lineNumbers = TypeConverters.TextEditorLineNumbersStyle.to(source.lineNumbers); @@ -231,6 +239,45 @@ export class ExtHostTextEditorOptions { })); } + // --- internal: indentSize + + private _validateIndentSize(value: number | string): number | 'tabSize' | null { + if (value === 'tabSize') { + return 'tabSize'; + } + if (typeof value === 'number') { + const r = Math.floor(value); + return (r > 0 ? r : null); + } + if (typeof value === 'string') { + const r = parseInt(value, 10); + if (isNaN(r)) { + return null; + } + return (r > 0 ? r : null); + } + return null; + } + + private _setIndentSize(value: number | string) { + const indentSize = this._validateIndentSize(value); + if (indentSize === null) { + // ignore invalid call + return; + } + if (typeof indentSize === 'number') { + if (this._indentSize === indentSize) { + // nothing to do + return; + } + // reflect the new indentSize value immediately + this._indentSize = indentSize; + } + this._warnOnError('setIndentSize', this._proxy.$trySetOptions(this._id, { + indentSize: indentSize + })); + } + // --- internal: insert spaces private _validateInsertSpaces(value: boolean | string): boolean | 'auto' { @@ -298,18 +345,18 @@ export class ExtHostTextEditorOptions { } } - // if (typeof newOptions.indentSize !== 'undefined') { - // const indentSize = this._validateIndentSize(newOptions.indentSize); - // if (indentSize === 'tabSize') { - // hasUpdate = true; - // bulkConfigurationUpdate.indentSize = indentSize; - // } else if (typeof indentSize === 'number' && this._indentSize !== indentSize) { - // // reflect the new indentSize value immediately - // this._indentSize = indentSize; - // hasUpdate = true; - // bulkConfigurationUpdate.indentSize = indentSize; - // } - // } + if (typeof newOptions.indentSize !== 'undefined') { + const indentSize = this._validateIndentSize(newOptions.indentSize); + if (indentSize === 'tabSize') { + hasUpdate = true; + bulkConfigurationUpdate.indentSize = indentSize; + } else if (typeof indentSize === 'number' && this._indentSize !== indentSize) { + // reflect the new indentSize value immediately + this._indentSize = indentSize; + hasUpdate = true; + bulkConfigurationUpdate.indentSize = indentSize; + } + } if (typeof newOptions.insertSpaces !== 'undefined') { const insertSpaces = this._validateInsertSpaces(newOptions.insertSpaces); diff --git a/src/vs/workbench/api/test/browser/extHostTextEditor.test.ts b/src/vs/workbench/api/test/browser/extHostTextEditor.test.ts index accded46c5d62..d5d4b12f3edd9 100644 --- a/src/vs/workbench/api/test/browser/extHostTextEditor.test.ts +++ b/src/vs/workbench/api/test/browser/extHostTextEditor.test.ts @@ -21,7 +21,7 @@ suite('ExtHostTextEditor', () => { ], '\n', 1, 'text', false); setup(() => { - editor = new ExtHostTextEditor('fake', null!, new NullLogService(), new Lazy(() => doc.document), [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4 }, [], 1); + editor = new ExtHostTextEditor('fake', null!, new NullLogService(), new Lazy(() => doc.document), [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4, indentSize: 4 }, [], 1); }); test('disposed editor', () => { @@ -48,7 +48,7 @@ suite('ExtHostTextEditor', () => { applyCount += 1; return Promise.resolve(true); } - }, new NullLogService(), new Lazy(() => doc.document), [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4 }, [], 1); + }, new NullLogService(), new Lazy(() => doc.document), [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4, indentSize: 4 }, [], 1); await editor.value.edit(edit => { }); assert.strictEqual(applyCount, 0); @@ -90,6 +90,7 @@ suite('ExtHostTextEditorOptions', () => { }; opts = new ExtHostTextEditorOptions(mockProxy, '1', { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -104,6 +105,7 @@ suite('ExtHostTextEditorOptions', () => { function assertState(opts: ExtHostTextEditorOptions, expected: IResolvedTextEditorConfiguration): void { const actual = { tabSize: opts.value.tabSize, + indentSize: opts.value.indentSize, insertSpaces: opts.value.insertSpaces, cursorStyle: opts.value.cursorStyle, lineNumbers: opts.value.lineNumbers @@ -115,6 +117,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.tabSize = 4; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -126,6 +129,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.tabSize = 1; assertState(opts, { tabSize: 1, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -137,6 +141,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.tabSize = 2.3; assertState(opts, { tabSize: 2, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -148,6 +153,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.tabSize = '2'; assertState(opts, { tabSize: 2, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -159,6 +165,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.tabSize = 'auto'; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -170,6 +177,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.tabSize = null!; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -181,6 +189,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.tabSize = -5; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -192,6 +201,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.tabSize = 'hello'; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -203,6 +213,127 @@ suite('ExtHostTextEditorOptions', () => { opts.value.tabSize = '-17'; assertState(opts, { tabSize: 4, + indentSize: 4, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, []); + }); + + test('can set indentSize to the same value', () => { + opts.value.indentSize = 4; + assertState(opts, { + tabSize: 4, + indentSize: 4, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, []); + }); + + test('can change indentSize to positive integer', () => { + opts.value.indentSize = 1; + assertState(opts, { + tabSize: 4, + indentSize: 1, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, [{ indentSize: 1 }]); + }); + + test('can change indentSize to positive float', () => { + opts.value.indentSize = 2.3; + assertState(opts, { + tabSize: 4, + indentSize: 2, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, [{ indentSize: 2 }]); + }); + + test('can change indentSize to a string number', () => { + opts.value.indentSize = '2'; + assertState(opts, { + tabSize: 4, + indentSize: 2, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, [{ indentSize: 2 }]); + }); + + test('indentSize can request to use tabSize', () => { + opts.value.indentSize = 'tabSize'; + assertState(opts, { + tabSize: 4, + indentSize: 4, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, [{ indentSize: 'tabSize' }]); + }); + + test('indentSize cannot request indentation detection', () => { + opts.value.indentSize = 'auto'; + assertState(opts, { + tabSize: 4, + indentSize: 4, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, []); + }); + + test('ignores invalid indentSize 1', () => { + opts.value.indentSize = null!; + assertState(opts, { + tabSize: 4, + indentSize: 4, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, []); + }); + + test('ignores invalid indentSize 2', () => { + opts.value.indentSize = -5; + assertState(opts, { + tabSize: 4, + indentSize: 4, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, []); + }); + + test('ignores invalid indentSize 3', () => { + opts.value.indentSize = 'hello'; + assertState(opts, { + tabSize: 4, + indentSize: 4, + insertSpaces: false, + cursorStyle: TextEditorCursorStyle.Line, + lineNumbers: RenderLineNumbersType.On + }); + assert.deepStrictEqual(calls, []); + }); + + test('ignores invalid indentSize 4', () => { + opts.value.indentSize = '-17'; + assertState(opts, { + tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -214,6 +345,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.insertSpaces = false; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -225,6 +357,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.insertSpaces = true; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: true, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -236,6 +369,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.insertSpaces = 'false'; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -247,6 +381,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.insertSpaces = 'hello'; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: true, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -258,6 +393,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.insertSpaces = 'auto'; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -269,6 +405,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.cursorStyle = TextEditorCursorStyle.Line; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -280,6 +417,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.cursorStyle = TextEditorCursorStyle.Block; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Block, lineNumbers: RenderLineNumbersType.On @@ -291,6 +429,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.lineNumbers = TextEditorLineNumbersStyle.On; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -302,6 +441,7 @@ suite('ExtHostTextEditorOptions', () => { opts.value.lineNumbers = TextEditorLineNumbersStyle.Off; assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.Off @@ -312,12 +452,14 @@ suite('ExtHostTextEditorOptions', () => { test('can do bulk updates 0', () => { opts.assign({ tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: TextEditorLineNumbersStyle.On }); assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -332,6 +474,7 @@ suite('ExtHostTextEditorOptions', () => { }); assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: true, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -346,6 +489,7 @@ suite('ExtHostTextEditorOptions', () => { }); assertState(opts, { tabSize: 3, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Line, lineNumbers: RenderLineNumbersType.On @@ -360,6 +504,7 @@ suite('ExtHostTextEditorOptions', () => { }); assertState(opts, { tabSize: 4, + indentSize: 4, insertSpaces: false, cursorStyle: TextEditorCursorStyle.Block, lineNumbers: RenderLineNumbersType.Relative diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 8ddc0b0377fd9..9476595d8966e 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -641,13 +641,22 @@ declare module 'vscode' { /** * The size in spaces a tab takes. This is used for two purposes: * - the rendering width of a tab character; - * - the number of spaces to insert when {@link TextEditorOptions.insertSpaces insertSpaces} is true. + * - the number of spaces to insert when {@link TextEditorOptions.insertSpaces insertSpaces} is true + * and `indentSize` is set to `"tab"`. * * When getting a text editor's options, this property will always be a number (resolved). * When setting a text editor's options, this property is optional and it can be a number or `"auto"`. */ tabSize?: number | string; + /** + * The number of spaces to insert when [insertSpaces](#TextEditorOptions.insertSpaces) is true. + * + * When getting a text editor's options, this property will always be a number (resolved). + * When setting a text editor's options, this property is optional and it can be a number or `"tabSize"`. + */ + indentSize?: number | string; + /** * When pressing Tab insert {@link TextEditorOptions.tabSize n} spaces. * When getting a text editor's options, this property will always be a boolean (resolved). From 4b7774b30e681e56987b52d05632464c4e882ffd Mon Sep 17 00:00:00 2001 From: zeroimpl Date: Sun, 17 Jul 2022 21:34:43 -0400 Subject: [PATCH 2/4] Update indentation action items and status bar text Make the "Indent Using Spaces" action not affect the displayed tab width. Add a new "Change Tab Display Size" action to change that independently. If the indentSize and tabSize are different, show both in the status bar. Also for the indentation actions, replace the "Configured Tab Size" hint with a "Selected Tab Size" and "Default Tab Size" options, when it is ambiguous. --- .../indentation/browser/indentation.ts | 48 +++++++++++++++---- .../browser/parts/editor/editorStatus.ts | 7 ++- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/vs/editor/contrib/indentation/browser/indentation.ts b/src/vs/editor/contrib/indentation/browser/indentation.ts index fcb7848bf4e63..581782957ce80 100644 --- a/src/vs/editor/contrib/indentation/browser/indentation.ts +++ b/src/vs/editor/contrib/indentation/browser/indentation.ts @@ -208,7 +208,7 @@ export class IndentationToTabsAction extends EditorAction { export class ChangeIndentationSizeAction extends EditorAction { - constructor(private readonly insertSpaces: boolean, opts: IActionOptions) { + constructor(private readonly insertSpaces: boolean, private readonly displaySizeOnly: boolean, opts: IActionOptions) { super(opts); } @@ -222,11 +222,20 @@ export class ChangeIndentationSizeAction extends EditorAction { } const creationOpts = modelService.getCreationOptions(model.getLanguageId(), model.uri, model.isForSimpleWidget); + const modelOpts = model.getOptions(); const picks = [1, 2, 3, 4, 5, 6, 7, 8].map(n => ({ id: n.toString(), label: n.toString(), // add description for tabSize value set in the configuration - description: n === creationOpts.tabSize ? nls.localize('configuredTabSize', "Configured Tab Size") : undefined + description: ( + n === creationOpts.tabSize && n === modelOpts.tabSize + ? nls.localize('configuredTabSize', "Configured Tab Size") + : n === creationOpts.tabSize + ? nls.localize('defaultTabSize', "Default Tab Size") + : n === modelOpts.tabSize + ? nls.localize('selectedTabSize', "Selected Tab Size") + : undefined + ) })); // auto focus the tabSize set for the current editor @@ -236,10 +245,18 @@ export class ChangeIndentationSizeAction extends EditorAction { quickInputService.pick(picks, { placeHolder: nls.localize({ key: 'selectTabWidth', comment: ['Tab corresponds to the tab key'] }, "Select Tab Size for Current File"), activeItem: picks[autoFocusIndex] }).then(pick => { if (pick) { if (model && !model.isDisposed()) { - model.updateOptions({ - tabSize: parseInt(pick.label, 10), - insertSpaces: this.insertSpaces - }); + const pickedVal = parseInt(pick.label, 10); + if (this.displaySizeOnly) { + model.updateOptions({ + tabSize: pickedVal + }); + } else { + model.updateOptions({ + tabSize: this.insertSpaces ? undefined : pickedVal, + indentSize: pickedVal, + insertSpaces: this.insertSpaces + }); + } } } }); @@ -252,7 +269,7 @@ export class IndentUsingTabs extends ChangeIndentationSizeAction { public static readonly ID = 'editor.action.indentUsingTabs'; constructor() { - super(false, { + super(false, false, { id: IndentUsingTabs.ID, label: nls.localize('indentUsingTabs', "Indent Using Tabs"), alias: 'Indent Using Tabs', @@ -266,7 +283,7 @@ export class IndentUsingSpaces extends ChangeIndentationSizeAction { public static readonly ID = 'editor.action.indentUsingSpaces'; constructor() { - super(true, { + super(true, false, { id: IndentUsingSpaces.ID, label: nls.localize('indentUsingSpaces', "Indent Using Spaces"), alias: 'Indent Using Spaces', @@ -275,6 +292,20 @@ export class IndentUsingSpaces extends ChangeIndentationSizeAction { } } +export class ChangeTabDisplaySize extends ChangeIndentationSizeAction { + + public static readonly ID = 'editor.action.changeTabDisplaySize'; + + constructor() { + super(true, true, { + id: ChangeTabDisplaySize.ID, + label: nls.localize('changeTabDisplaySize', "Change Tab Display Size"), + alias: 'Change Tab Display Size', + precondition: undefined + }); + } +} + export class DetectIndentation extends EditorAction { public static readonly ID = 'editor.action.detectIndentation'; @@ -694,6 +725,7 @@ registerEditorAction(IndentationToSpacesAction); registerEditorAction(IndentationToTabsAction); registerEditorAction(IndentUsingTabs); registerEditorAction(IndentUsingSpaces); +registerEditorAction(ChangeTabDisplaySize); registerEditorAction(DetectIndentation); registerEditorAction(ReindentLinesAction); registerEditorAction(ReindentSelectedLinesAction); diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 48245d942a3ce..47c43a0b3328c 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -19,7 +19,7 @@ import { Disposable, MutableDisposable, DisposableStore } from 'vs/base/common/l import { IEditorAction } from 'vs/editor/common/editorCommon'; import { EndOfLineSequence } from 'vs/editor/common/model'; import { TrimTrailingWhitespaceAction } from 'vs/editor/contrib/linesOperations/browser/linesOperations'; -import { IndentUsingSpaces, IndentUsingTabs, DetectIndentation, IndentationToSpacesAction, IndentationToTabsAction } from 'vs/editor/contrib/indentation/browser/indentation'; +import { IndentUsingSpaces, IndentUsingTabs, ChangeTabDisplaySize, DetectIndentation, IndentationToSpacesAction, IndentationToTabsAction } from 'vs/editor/contrib/indentation/browser/indentation'; import { BaseBinaryResourceEditor } from 'vs/workbench/browser/parts/editor/binaryEditor'; import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -381,6 +381,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { const picks: QuickPickInput[] = [ activeTextEditorControl.getAction(IndentUsingSpaces.ID), activeTextEditorControl.getAction(IndentUsingTabs.ID), + activeTextEditorControl.getAction(ChangeTabDisplaySize.ID), activeTextEditorControl.getAction(DetectIndentation.ID), activeTextEditorControl.getAction(IndentationToSpacesAction.ID), activeTextEditorControl.getAction(IndentationToTabsAction.ID), @@ -756,7 +757,9 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { const modelOpts = model.getOptions(); update.indentation = ( modelOpts.insertSpaces - ? localize('spacesSize', "Spaces: {0}", modelOpts.indentSize) + ? modelOpts.tabSize === modelOpts.indentSize + ? localize('spacesSize', "Spaces: {0}", modelOpts.indentSize) + : localize('spacesAndTabsSize', "Spaces: {0} (Tab Size: {1})", modelOpts.indentSize, modelOpts.tabSize) : localize({ key: 'tabSize', comment: ['Tab corresponds to the tab key'] }, "Tab Size: {0}", modelOpts.tabSize) ); } From 817d4180c1b79ec2c29fa3d3192d5c626059820b Mon Sep 17 00:00:00 2001 From: Daniel Fiori Date: Mon, 1 Aug 2022 14:02:34 -0400 Subject: [PATCH 3/4] Fix typo in documentation for tabSize Co-authored-by: Magnus Ihse Bursie --- src/vscode-dts/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 9476595d8966e..06204c6b85320 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -642,7 +642,7 @@ declare module 'vscode' { * The size in spaces a tab takes. This is used for two purposes: * - the rendering width of a tab character; * - the number of spaces to insert when {@link TextEditorOptions.insertSpaces insertSpaces} is true - * and `indentSize` is set to `"tab"`. + * and `indentSize` is set to `"tabSize"`. * * When getting a text editor's options, this property will always be a number (resolved). * When setting a text editor's options, this property is optional and it can be a number or `"auto"`. From 484e0cbddbbc5ad5c24872bb5eb3bbd59bcef890 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 16 Nov 2022 13:01:00 +0100 Subject: [PATCH 4/4] Create a new API proposal with `TextEditorOptions.indentSize` --- .../indentation/browser/indentation.ts | 2 +- .../workbench/api/common/extHostTextEditor.ts | 4 +-- .../test/browser/extHostTextEditor.test.ts | 8 ++--- .../common/extensionsApiProposals.ts | 1 + src/vscode-dts/vscode.d.ts | 11 +------ .../vscode.proposed.indentSize.d.ts | 29 +++++++++++++++++++ 6 files changed, 38 insertions(+), 17 deletions(-) create mode 100644 src/vscode-dts/vscode.proposed.indentSize.d.ts diff --git a/src/vs/editor/contrib/indentation/browser/indentation.ts b/src/vs/editor/contrib/indentation/browser/indentation.ts index 581782957ce80..8e737485cf626 100644 --- a/src/vs/editor/contrib/indentation/browser/indentation.ts +++ b/src/vs/editor/contrib/indentation/browser/indentation.ts @@ -233,7 +233,7 @@ export class ChangeIndentationSizeAction extends EditorAction { : n === creationOpts.tabSize ? nls.localize('defaultTabSize', "Default Tab Size") : n === modelOpts.tabSize - ? nls.localize('selectedTabSize', "Selected Tab Size") + ? nls.localize('currentTabSize', "Current Tab Size") : undefined ) })); diff --git a/src/vs/workbench/api/common/extHostTextEditor.ts b/src/vs/workbench/api/common/extHostTextEditor.ts index 427c6f5a9f94a..316e0fe076acc 100644 --- a/src/vs/workbench/api/common/extHostTextEditor.ts +++ b/src/vs/workbench/api/common/extHostTextEditor.ts @@ -165,10 +165,10 @@ export class ExtHostTextEditorOptions { set tabSize(value: number | string) { that._setTabSize(value); }, - get indentSize(): number | string { + get indentSize(): number | 'tabSize' { return that._indentSize; }, - set indentSize(value: number | string) { + set indentSize(value: number | 'tabSize') { that._setIndentSize(value); }, get insertSpaces(): boolean | string { diff --git a/src/vs/workbench/api/test/browser/extHostTextEditor.test.ts b/src/vs/workbench/api/test/browser/extHostTextEditor.test.ts index d5d4b12f3edd9..0793a57fff6fa 100644 --- a/src/vs/workbench/api/test/browser/extHostTextEditor.test.ts +++ b/src/vs/workbench/api/test/browser/extHostTextEditor.test.ts @@ -258,7 +258,7 @@ suite('ExtHostTextEditorOptions', () => { }); test('can change indentSize to a string number', () => { - opts.value.indentSize = '2'; + opts.value.indentSize = '2'; assertState(opts, { tabSize: 4, indentSize: 2, @@ -282,7 +282,7 @@ suite('ExtHostTextEditorOptions', () => { }); test('indentSize cannot request indentation detection', () => { - opts.value.indentSize = 'auto'; + opts.value.indentSize = 'auto'; assertState(opts, { tabSize: 4, indentSize: 4, @@ -318,7 +318,7 @@ suite('ExtHostTextEditorOptions', () => { }); test('ignores invalid indentSize 3', () => { - opts.value.indentSize = 'hello'; + opts.value.indentSize = 'hello'; assertState(opts, { tabSize: 4, indentSize: 4, @@ -330,7 +330,7 @@ suite('ExtHostTextEditorOptions', () => { }); test('ignores invalid indentSize 4', () => { - opts.value.indentSize = '-17'; + opts.value.indentSize = '-17'; assertState(opts, { tabSize: 4, indentSize: 4, diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index 37133b8e76b04..d9336a794c482 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -36,6 +36,7 @@ export const allApiProposals = Object.freeze({ findTextInFiles: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.findTextInFiles.d.ts', fsChunks: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.fsChunks.d.ts', idToken: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.idToken.d.ts', + indentSize: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.indentSize.d.ts', inlineCompletionsAdditions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.inlineCompletionsAdditions.d.ts', interactiveWindow: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.interactiveWindow.d.ts', ipc: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.ipc.d.ts', diff --git a/src/vscode-dts/vscode.d.ts b/src/vscode-dts/vscode.d.ts index 08c8da576d6c8..7399790e37523 100644 --- a/src/vscode-dts/vscode.d.ts +++ b/src/vscode-dts/vscode.d.ts @@ -641,22 +641,13 @@ declare module 'vscode' { /** * The size in spaces a tab takes. This is used for two purposes: * - the rendering width of a tab character; - * - the number of spaces to insert when {@link TextEditorOptions.insertSpaces insertSpaces} is true - * and `indentSize` is set to `"tabSize"`. + * - the number of spaces to insert when {@link TextEditorOptions.insertSpaces insertSpaces} is true. * * When getting a text editor's options, this property will always be a number (resolved). * When setting a text editor's options, this property is optional and it can be a number or `"auto"`. */ tabSize?: number | string; - /** - * The number of spaces to insert when [insertSpaces](#TextEditorOptions.insertSpaces) is true. - * - * When getting a text editor's options, this property will always be a number (resolved). - * When setting a text editor's options, this property is optional and it can be a number or `"tabSize"`. - */ - indentSize?: number | string; - /** * When pressing Tab insert {@link TextEditorOptions.tabSize n} spaces. * When getting a text editor's options, this property will always be a boolean (resolved). diff --git a/src/vscode-dts/vscode.proposed.indentSize.d.ts b/src/vscode-dts/vscode.proposed.indentSize.d.ts new file mode 100644 index 0000000000000..0ce01fa218aca --- /dev/null +++ b/src/vscode-dts/vscode.proposed.indentSize.d.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + /** + * Represents a {@link TextEditor text editor}'s {@link TextEditor.options options}. + */ + export interface TextEditorOptions { + /** + * The size in spaces a tab takes. This is used for two purposes: + * - the rendering width of a tab character; + * - the number of spaces to insert when {@link TextEditorOptions.insertSpaces insertSpaces} is true + * and `indentSize` is set to `"tabSize"`. + * + * When getting a text editor's options, this property will always be a number (resolved). + * When setting a text editor's options, this property is optional and it can be a number or `"auto"`. + */ + tabSize?: number | string; + /** + * The number of spaces to insert when [insertSpaces](#TextEditorOptions.insertSpaces) is true. + * + * When getting a text editor's options, this property will always be a number (resolved). + * When setting a text editor's options, this property is optional and it can be a number or `"tabSize"`. + */ + indentSize?: number | 'tabSize'; + } +}