From 8f531e289b2aeeb63eba5ebddb36a75cea281aa4 Mon Sep 17 00:00:00 2001 From: Remi Schnekenburger Date: Tue, 14 Nov 2023 10:15:44 +0100 Subject: [PATCH] vscode support of editor.indentSize Also updates tabSize, as API does not correspond to documentation. Contributed on behalf of STMicroelectronics Signed-off-by: Remi Schnekenburger --- CHANGELOG.md | 1 + packages/monaco/src/browser/monaco-command.ts | 10 +-- .../browser/monaco-status-bar-contribution.ts | 3 +- .../src/browser/monaco-text-model-service.ts | 7 +- .../plugin-ext/src/common/plugin-api-rpc.ts | 2 + .../src/main/browser/text-editor-main.ts | 9 +++ packages/plugin-ext/src/plugin/text-editor.ts | 68 +++++++++++++++++-- packages/plugin/src/theia.d.ts | 8 +++ 8 files changed, 98 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b68de467d7f19..e2d7c89444bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [vscode] added support for `autoClosingPairs` in the `LanguageConfiguration ` VS Code API [#13088](https://github.com/eclipse-theia/theia/pull/13088) - contributed on behalf of STMicroelectronics - [task] prevent task widget title from being changed by task process [#13003](https://github.com/eclipse-theia/theia/pull/13003) - [vscode] added Notebook CodeActionKind [#13093](https://github.com/eclipse-theia/theia/pull/13093) - contributed on behalf of STMicroelectronics +- [vscode] added support for editor.indentSize API [#13105](https://github.com/eclipse-theia/theia/pull/13105) - contributed on behalf of STMicroelectronics - [vscode] added support to env.ondidChangeShell event [#13097](https://github.com/eclipse-theia/theia/pull/13097) - contributed on behalf of STMicroelectronics - [task] support `isDefault: false` in task group definition [#13075](https://github.com/eclipse-theia/theia/pull/13075) - contributed on behalf of STMicroelectronics diff --git a/packages/monaco/src/browser/monaco-command.ts b/packages/monaco/src/browser/monaco-command.ts index 8d22defd108f7..323f4408a655f 100644 --- a/packages/monaco/src/browser/monaco-command.ts +++ b/packages/monaco/src/browser/monaco-command.ts @@ -265,10 +265,12 @@ export class MonacoEditorCommandHandlers implements CommandContribution { ({ label: size === tabSize ? size + ' ' + nls.localizeByDefault('Configured Tab Size') : size.toString(), // eslint-disable-next-line @typescript-eslint/no-explicit-any - execute: () => model.updateOptions({ - tabSize: size || tabSize, - insertSpaces: useSpaces - }) + execute: () => + model.updateOptions({ + tabSize: size || tabSize, + indentSize: size || tabSize, + insertSpaces: useSpaces + }) }) ); this.quickInputService?.showQuickPick(tabSizeOptions, { placeholder: nls.localizeByDefault('Select Tab Size for Current File') }); diff --git a/packages/monaco/src/browser/monaco-status-bar-contribution.ts b/packages/monaco/src/browser/monaco-status-bar-contribution.ts index 4a7ba08752c5a..fae85805e9f1a 100644 --- a/packages/monaco/src/browser/monaco-status-bar-contribution.ts +++ b/packages/monaco/src/browser/monaco-status-bar-contribution.ts @@ -67,8 +67,9 @@ export class MonacoStatusBarContribution implements FrontendApplicationContribut if (editor && editorModel) { const modelOptions = editorModel.getOptions(); const tabSize = modelOptions.tabSize; + const indentSize = modelOptions.indentSize; const spaceOrTabSizeMessage = modelOptions.insertSpaces - ? nls.localizeByDefault('Spaces: {0}', tabSize) + ? nls.localizeByDefault('Spaces: {0}', indentSize) : nls.localizeByDefault('Tab Size: {0}', tabSize); this.statusBar.setElement('editor-status-tabbing-config', { text: spaceOrTabSizeMessage, diff --git a/packages/monaco/src/browser/monaco-text-model-service.ts b/packages/monaco/src/browser/monaco-text-model-service.ts index 8c7bd41749762..d4440b4d80946 100644 --- a/packages/monaco/src/browser/monaco-text-model-service.ts +++ b/packages/monaco/src/browser/monaco-text-model-service.ts @@ -127,12 +127,15 @@ export class MonacoTextModelService implements ITextModelService { protected readonly modelOptions: { [name: string]: (keyof ITextModelUpdateOptions | undefined) } = { 'editor.tabSize': 'tabSize', - 'editor.insertSpaces': 'insertSpaces' + 'editor.insertSpaces': 'insertSpaces', + 'editor.indentSize': 'indentSize' }; protected toModelOption(editorPreference: EditorPreferenceChange['preferenceName']): keyof ITextModelUpdateOptions | undefined { switch (editorPreference) { case 'editor.tabSize': return 'tabSize'; + // @monaco-uplift: uncomment this line once 'editor.indentSize' preference is available + // case 'editor.indentSize': return 'indentSize'; case 'editor.insertSpaces': return 'insertSpaces'; case 'editor.bracketPairColorization.enabled': case 'editor.bracketPairColorization.independentColorPoolPerBracketType': @@ -170,6 +173,8 @@ export class MonacoTextModelService implements ITextModelService { const overrideIdentifier = typeof arg === 'string' ? undefined : arg.languageId; return { tabSize: this.editorPreferences.get({ preferenceName: 'editor.tabSize', overrideIdentifier }, undefined, uri), + // @monaco-uplift: when available, switch to 'editor.indentSize' preference. + indentSize: this.editorPreferences.get({ preferenceName: 'editor.tabSize', overrideIdentifier }, undefined, uri), insertSpaces: this.editorPreferences.get({ preferenceName: 'editor.insertSpaces', overrideIdentifier }, undefined, uri), bracketColorizationOptions: { enabled: this.editorPreferences.get({ preferenceName: 'editor.bracketPairColorization.enabled', overrideIdentifier }, undefined, uri), diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index 6d56cd92712f6..71b67d64b82a7 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -1125,6 +1125,7 @@ export interface Selection { export interface TextEditorConfiguration { tabSize: number; + indentSize: number; insertSpaces: boolean; cursorStyle: TextEditorCursorStyle; lineNumbers: TextEditorLineNumbersStyle; @@ -1132,6 +1133,7 @@ export interface TextEditorConfiguration { export interface TextEditorConfigurationUpdate { tabSize?: number | 'auto'; + indentSize?: number | 'tabSize'; insertSpaces?: boolean | 'auto'; cursorStyle?: TextEditorCursorStyle; lineNumbers?: TextEditorLineNumbersStyle; diff --git a/packages/plugin-ext/src/main/browser/text-editor-main.ts b/packages/plugin-ext/src/main/browser/text-editor-main.ts index 1dea02aa16b8f..17656f9a85d2e 100644 --- a/packages/plugin-ext/src/main/browser/text-editor-main.ts +++ b/packages/plugin-ext/src/main/browser/text-editor-main.ts @@ -194,6 +194,13 @@ export class TextEditorMain implements Disposable { if (typeof newConfiguration.tabSize !== 'undefined') { newOpts.tabSize = newConfiguration.tabSize; } + if (typeof newConfiguration.indentSize !== 'undefined') { + if (newConfiguration.indentSize === 'tabSize') { + newOpts.indentSize = newConfiguration.tabSize; + } else if (typeof newConfiguration.indentSize == 'number') { + newOpts.indentSize = newConfiguration.indentSize; + } + } this.model.updateOptions(newOpts); } @@ -408,6 +415,7 @@ export class TextEditorPropertiesMain { const modelOptions = model.getOptions(); return { insertSpaces: modelOptions.insertSpaces, + indentSize: modelOptions.indentSize, tabSize: modelOptions.tabSize, cursorStyle, lineNumbers, @@ -443,6 +451,7 @@ export class TextEditorPropertiesMain { return ( a.tabSize === b.tabSize && a.insertSpaces === b.insertSpaces + && a.indentSize === b.indentSize && a.cursorStyle === b.cursorStyle && a.lineNumbers === b.lineNumbers ); diff --git a/packages/plugin-ext/src/plugin/text-editor.ts b/packages/plugin-ext/src/plugin/text-editor.ts index 02852b04cf469..85b87747107ba 100644 --- a/packages/plugin-ext/src/plugin/text-editor.ts +++ b/packages/plugin-ext/src/plugin/text-editor.ts @@ -277,7 +277,8 @@ export class TextEditorExt implements theia.TextEditor { } export class TextEditorOptionsExt implements theia.TextEditorOptions { - private _tabSize?: number; + private _tabSize: number; + private _indentSize: number | 'tabSize'; private _insertSpace: boolean; private _cursorStyle: TextEditorCursorStyle; private _lineNumbers: TextEditorLineNumbersStyle; @@ -289,12 +290,13 @@ export class TextEditorOptionsExt implements theia.TextEditorOptions { accept(source: TextEditorConfiguration): void { this._tabSize = source.tabSize; + this._indentSize = source.indentSize; this._insertSpace = source.insertSpaces; this._cursorStyle = source.cursorStyle; this._lineNumbers = source.lineNumbers; } - get tabSize(): number | string | undefined { + get tabSize(): number { return this._tabSize; } @@ -305,10 +307,10 @@ export class TextEditorOptionsExt implements theia.TextEditorOptions { } if (typeof tabSize === 'number') { - if (this.tabSize === tabSize) { + if (this._tabSize === tabSize) { return; } - this.tabSize = tabSize; + this._tabSize = tabSize; } warnOnError(this.proxy.$trySetOptions(this.id, { tabSize @@ -334,6 +336,51 @@ export class TextEditorOptionsExt implements theia.TextEditorOptions { return undefined; } + get indentSize(): number { + if (this._indentSize === 'tabSize') { + return this.tabSize; + } + return this._indentSize; + } + + set indentSize(val: number | string | undefined) { + const indentSize = this.validateIndentSize(val); + if (!indentSize) { + return; // ignore invalid values + } + + if (typeof indentSize === 'number') { + if (this._indentSize === indentSize) { + return; + } + this._indentSize = indentSize; + } else if (val === 'tabSize') { + this._indentSize = val; + } + warnOnError(this.proxy.$trySetOptions(this.id, { + indentSize + })); + } + + private validateIndentSize(val: number | string | undefined): number | 'tabSize' | undefined { + if (val === 'tabSize') { + return 'tabSize'; + } + + if (typeof val === 'number') { + const r = Math.floor(val); + return r > 0 ? r : undefined; + } + if (typeof val === 'string') { + const r = parseInt(val, undefined); + if (isNaN(r)) { + return undefined; + } + return r > 0 ? r : undefined; + } + return undefined; + } + get insertSpaces(): boolean | string { return this._insertSpace; } @@ -395,6 +442,19 @@ export class TextEditorOptionsExt implements theia.TextEditorOptions { } } + if (typeof newOptions.indentSize !== 'undefined') { + const indentSize = this.validateIndentSize(newOptions.indentSize); + if (indentSize === 'tabSize') { + hasUpdate = true; + configurationUpdate.indentSize = indentSize; + } else if (typeof indentSize === 'number' && this._indentSize !== indentSize) { + // reflect the new indentSize value immediately + this._indentSize = indentSize; + hasUpdate = true; + configurationUpdate.indentSize = indentSize; + } + } + if (typeof newOptions.insertSpaces !== 'undefined') { const insertSpaces = this.validateInsertSpaces(newOptions.insertSpaces); if (insertSpaces === 'auto') { diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index 3c8d947abdb74..90a9088e684de 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -1909,6 +1909,14 @@ export module '@theia/plugin' { */ tabSize?: number | string; + /** + * 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 `"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).