From 5db2785600c8e33c189dc83640645f4a3696fe6e Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 21 Mar 2024 14:52:20 +0100 Subject: [PATCH 1/7] adding a todo and one more test --- .../test/browser/indentation.test.ts | 36 +++++++++++++++++++ .../codeEditor/test/node/autoindent.test.ts | 6 ++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts b/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts index a9bae82ae00..7b6842e48c9 100644 --- a/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts +++ b/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts @@ -741,6 +741,8 @@ suite('`Full` Auto Indent On Type - TypeScript/JavaScript', () => { // issue: Should indent after an equal sign is detected followed by whitespace characters. // This should be outdented when a semi-colon is detected indicating the end of the assignment. + // TODO: requires exploring indent/outdent pairs instead + const model = createTextModel([ 'const array =' ].join('\n'), languageId, {}); @@ -762,6 +764,8 @@ suite('`Full` Auto Indent On Type - TypeScript/JavaScript', () => { // https://github.com/microsoft/vscode/issues/43244 // issue: When a dot is written, we should detect that this is a method call and indent accordingly + // TODO: requires exploring indent/outdent pairs instead + const model = createTextModel([ 'const array = [1, 2, 3];', 'array.' @@ -785,6 +789,8 @@ suite('`Full` Auto Indent On Type - TypeScript/JavaScript', () => { // https://github.com/microsoft/vscode/issues/43244 // issue: When a dot is written, we should detect that this is a method call and indent accordingly + // TODO: requires exploring indent/outdent pairs instead + const model = createTextModel([ 'const array = [1, 2, 3]', ].join('\n'), languageId, {}); @@ -807,6 +813,8 @@ suite('`Full` Auto Indent On Type - TypeScript/JavaScript', () => { // https://github.com/microsoft/vscode/issues/43244 // Currently passes, but should pass with all the tests above too + // TODO: requires exploring indent/outdent pairs instead + const model = createTextModel([ 'const array = [1, 2, 3]', ' .filter(() => true)' @@ -825,10 +833,38 @@ suite('`Full` Auto Indent On Type - TypeScript/JavaScript', () => { }); }); + test.skip('issue #43244: keep indentation when chained methods called on object/array', () => { + + // https://github.com/microsoft/vscode/issues/43244 + // When the call chain is not finished yet, and we type a dot, we do not want to change the indentation + + // TODO: requires exploring indent/outdent pairs instead + + const model = createTextModel([ + 'const array = [1, 2, 3]', + ' .filter(() => true)', + ' ' + ].join('\n'), languageId, {}); + disposables.add(model); + + withTestCodeEditor(model, { autoIndent: "full" }, (editor, viewModel, instantiationService) => { + registerLanguage(instantiationService, languageId, Language.TypeScript, disposables); + editor.setSelection(new Selection(3, 5, 3, 5)); + viewModel.type("."); + assert.strictEqual(model.getValue(), [ + 'const array = [1, 2, 3]', + ' .filter(() => true)', + ' .' // here we don't want to increase the indentation because we have chained methods + ].join('\n')); + }); + }); + test.skip('issue #43244: outdent when a semi-color is detected indicating the end of the assignment', () => { // https://github.com/microsoft/vscode/issues/43244 + // TODO: requires exploring indent/outdent pairs instead + const model = createTextModel([ 'const array = [1, 2, 3]', ' .filter(() => true);' diff --git a/src/vs/workbench/contrib/codeEditor/test/node/autoindent.test.ts b/src/vs/workbench/contrib/codeEditor/test/node/autoindent.test.ts index 0378af3ac75..05fae9e47ae 100644 --- a/src/vs/workbench/contrib/codeEditor/test/node/autoindent.test.ts +++ b/src/vs/workbench/contrib/codeEditor/test/node/autoindent.test.ts @@ -282,10 +282,8 @@ suite('Auto-Reindentation - TypeScript/JavaScript', () => { // related: https://github.com/microsoft/vscode/issues/43244 // explanation: When you have an arrow function, you don't have { or }, but you would expect indentation to still be done in that way - /* - Notes: Currently the reindent edit operations does not call the onEnter rules - The reindent should also call the onEnter rules to get the correct indentation - */ + // TODO: requires exploring indent/outdent pairs instead + const fileContents = [ 'const add1 = (n) =>', ' n + 1;', From 163ff5fad451578a7048c717506c0da9453671a4 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 21 Mar 2024 16:19:55 +0100 Subject: [PATCH 2/7] polishing some tests --- .../contrib/indentation/test/browser/indentation.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts b/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts index 7b6842e48c9..779827baece 100644 --- a/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts +++ b/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts @@ -883,23 +883,23 @@ suite('`Full` Auto Indent On Type - TypeScript/JavaScript', () => { }); }); - test.skip('issue #43244: indent when lambda arrow function is detected, outdent when end is reached', () => { + test('issue #43244: indent when lambda arrow function is detected, outdent when end is reached', () => { // https://github.com/microsoft/vscode/issues/43244 const model = createTextModel([ 'const array = [1, 2, 3, 4, 5];', - 'array.map(v =>)' + 'array.map(_)' ].join('\n'), languageId, {}); disposables.add(model); withTestCodeEditor(model, { autoIndent: "full" }, (editor, viewModel, instantiationService) => { registerLanguage(instantiationService, languageId, Language.TypeScript, disposables); - editor.setSelection(new Selection(2, 15, 2, 15)); + editor.setSelection(new Selection(2, 12, 2, 12)); viewModel.type("\n", 'keyboard'); assert.strictEqual(model.getValue(), [ 'const array = [1, 2, 3, 4, 5];', - 'array.map(v =>', + 'array.map(_', ' ', ')' ].join('\n')); From 6bc3ed7222a854591cff541bd3a687ec7a5ec80f Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 21 Mar 2024 16:20:22 +0100 Subject: [PATCH 3/7] adding the skip statement once again --- .../editor/contrib/indentation/test/browser/indentation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts b/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts index 779827baece..7f8c30f73f6 100644 --- a/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts +++ b/src/vs/editor/contrib/indentation/test/browser/indentation.test.ts @@ -883,7 +883,7 @@ suite('`Full` Auto Indent On Type - TypeScript/JavaScript', () => { }); }); - test('issue #43244: indent when lambda arrow function is detected, outdent when end is reached', () => { + test.skip('issue #43244: indent when lambda arrow function is detected, outdent when end is reached', () => { // https://github.com/microsoft/vscode/issues/43244 From ea0ec9f54a129ce9b57a622dde21fbfba100dafa Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 21 Mar 2024 17:05:29 +0100 Subject: [PATCH 4/7] adding regexes in order to indent when inside of (), {} or [] --- .../language-configuration.json | 29 ++++++++++++++++++- .../codeEditor/test/node/autoindent.test.ts | 4 +-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/extensions/typescript-basics/language-configuration.json b/extensions/typescript-basics/language-configuration.json index 2d14b1cab19..d296e4824c0 100644 --- a/extensions/typescript-basics/language-configuration.json +++ b/extensions/typescript-basics/language-configuration.json @@ -215,6 +215,33 @@ "action": { "indent": "outdent" } - } + }, + // Indent when pressing enter from inside () + { + "beforeText": "^.*\\([^\\)]*$", + "afterText": "^[^\\(]*\\).*$", + "action": { + "indent": "indentOutdent", + "appendText": "\t", + } + }, + // Indent when pressing enter from inside {} + { + "beforeText": "^.*\\{[^\\}]*$", + "afterText": "^[^\\{]*\\}.*$", + "action": { + "indent": "indentOutdent", + "appendText": "\t", + } + }, + // Indent when pressing enter from inside [] + { + "beforeText": "^.*\\[[^\\]]*$", + "afterText": "^[^\\[]*\\].*$", + "action": { + "indent": "indentOutdent", + "appendText": "\t", + } + }, ] } diff --git a/src/vs/workbench/contrib/codeEditor/test/node/autoindent.test.ts b/src/vs/workbench/contrib/codeEditor/test/node/autoindent.test.ts index 05fae9e47ae..6d58f57ebba 100644 --- a/src/vs/workbench/contrib/codeEditor/test/node/autoindent.test.ts +++ b/src/vs/workbench/contrib/codeEditor/test/node/autoindent.test.ts @@ -190,7 +190,7 @@ suite('Auto-Reindentation - TypeScript/JavaScript', () => { // explanation: if (, [, {, is followed by a forward slash then assume we are in a regex pattern, and do not indent // increaseIndentPattern: /^((?!\/\/).)*(\{([^}"'`]*|(\t|[ ])*\/\/.*)|\([^)"'`]*|\[[^\]"'`]*)$/ -> /^((?!\/\/).)*(\{([^}"'`/]*|(\t|[ ])*\/\/.*)|\([^)"'`/]*|\[[^\]"'`/]*)$/ - // -> Final current increase indent pattern + // -> Final current increase indent pattern at of writing const fileContents = [ 'const r = /{/;', @@ -214,7 +214,7 @@ suite('Auto-Reindentation - TypeScript/JavaScript', () => { // fix: https://github.com/microsoft/vscode/commit/7910b3d7bab8a721aae98dc05af0b5e1ea9d9782 // decreaseIndentPattern: /^(.*\*\/)?\s*[\}\]\)].*$/ -> /^((?!.*?\/\*).*\*\/)?\s*[\}\]\)].*$/ - // -> Final current decrease indent pattern + // -> Final current decrease indent pattern at the time of writing // explanation: Positive lookahead: (?= «pattern») matches if pattern matches what comes after the current location in the input string. // Negative lookahead: (?! «pattern») matches if pattern does not match what comes after the current location in the input string From 820438f6c175dce8c359a5e79c3cb6b899298292 Mon Sep 17 00:00:00 2001 From: Aiday Marlen Kyzy Date: Thu, 21 Mar 2024 17:27:30 +0100 Subject: [PATCH 5/7] remove the onEnterRules that were added, this PR will be solely for testing purposes --- .../language-configuration.json | 29 +------------------ 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/extensions/typescript-basics/language-configuration.json b/extensions/typescript-basics/language-configuration.json index d296e4824c0..2d14b1cab19 100644 --- a/extensions/typescript-basics/language-configuration.json +++ b/extensions/typescript-basics/language-configuration.json @@ -215,33 +215,6 @@ "action": { "indent": "outdent" } - }, - // Indent when pressing enter from inside () - { - "beforeText": "^.*\\([^\\)]*$", - "afterText": "^[^\\(]*\\).*$", - "action": { - "indent": "indentOutdent", - "appendText": "\t", - } - }, - // Indent when pressing enter from inside {} - { - "beforeText": "^.*\\{[^\\}]*$", - "afterText": "^[^\\{]*\\}.*$", - "action": { - "indent": "indentOutdent", - "appendText": "\t", - } - }, - // Indent when pressing enter from inside [] - { - "beforeText": "^.*\\[[^\\]]*$", - "afterText": "^[^\\[]*\\].*$", - "action": { - "indent": "indentOutdent", - "appendText": "\t", - } - }, + } ] } From ecb2aa818ca690e4e7b7417004e0ca559cadca87 Mon Sep 17 00:00:00 2001 From: Ulugbek Abdullaev Date: Thu, 21 Mar 2024 12:56:56 +0100 Subject: [PATCH 6/7] rename: complete renaming RenameInputField to RenameWidget --- .../editor/contrib/rename/browser/rename.ts | 18 ++++++------ ...{renameInputField.css => renameWidget.css} | 0 .../{renameInputField.ts => renameWidget.ts} | 28 +++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) rename src/vs/editor/contrib/rename/browser/{renameInputField.css => renameWidget.css} (100%) rename src/vs/editor/contrib/rename/browser/{renameInputField.ts => renameWidget.ts} (96%) diff --git a/src/vs/editor/contrib/rename/browser/rename.ts b/src/vs/editor/contrib/rename/browser/rename.ts index dba920953ba..93ce518854e 100644 --- a/src/vs/editor/contrib/rename/browser/rename.ts +++ b/src/vs/editor/contrib/rename/browser/rename.ts @@ -38,7 +38,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { Registry } from 'vs/platform/registry/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { CONTEXT_RENAME_INPUT_VISIBLE, NewNameSource, RenameInputFieldResult, RenameWidget } from './renameInputField'; +import { CONTEXT_RENAME_INPUT_VISIBLE, NewNameSource, RenameWidget, RenameWidgetResult } from './renameWidget'; class RenameSkeleton { @@ -138,7 +138,7 @@ class RenameController implements IEditorContribution { return editor.getContribution(RenameController.ID); } - private readonly _renameInputField: RenameWidget; + private readonly _renameWidget: RenameWidget; private readonly _disposableStore = new DisposableStore(); private _cts: CancellationTokenSource = new CancellationTokenSource(); @@ -153,7 +153,7 @@ class RenameController implements IEditorContribution { @ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService, @ITelemetryService private readonly _telemetryService: ITelemetryService, ) { - this._renameInputField = this._disposableStore.add(this._instaService.createInstance(RenameWidget, this.editor, ['acceptRenameInput', 'acceptRenameInputWithPreview'])); + this._renameWidget = this._disposableStore.add(this._instaService.createInstance(RenameWidget, this.editor, ['acceptRenameInput', 'acceptRenameInputWithPreview'])); } dispose(): void { @@ -235,7 +235,7 @@ class RenameController implements IEditorContribution { trace('creating rename input field and awaiting its result'); const supportPreview = this._bulkEditService.hasPreviewHandler() && this._configService.getValue(this.editor.getModel().uri, 'editor.rename.enablePreview'); - const inputFieldResult = await this._renameInputField.getInput( + const inputFieldResult = await this._renameWidget.getInput( loc.range, loc.text, supportPreview, @@ -321,22 +321,22 @@ class RenameController implements IEditorContribution { } acceptRenameInput(wantsPreview: boolean): void { - this._renameInputField.acceptInput(wantsPreview); + this._renameWidget.acceptInput(wantsPreview); } cancelRenameInput(): void { - this._renameInputField.cancelInput(true, 'cancelRenameInput command'); + this._renameWidget.cancelInput(true, 'cancelRenameInput command'); } focusNextRenameSuggestion(): void { - this._renameInputField.focusNextRenameSuggestion(); + this._renameWidget.focusNextRenameSuggestion(); } focusPreviousRenameSuggestion(): void { - this._renameInputField.focusPreviousRenameSuggestion(); + this._renameWidget.focusPreviousRenameSuggestion(); } - private _reportTelemetry(nRenameSuggestionProviders: number, languageId: string, inputFieldResult: boolean | RenameInputFieldResult, inDebugMode?: 'inDebugMode') { + private _reportTelemetry(nRenameSuggestionProviders: number, languageId: string, inputFieldResult: boolean | RenameWidgetResult, inDebugMode?: 'inDebugMode') { type RenameInvokedEvent = { kind: 'accepted' | 'cancelled'; diff --git a/src/vs/editor/contrib/rename/browser/renameInputField.css b/src/vs/editor/contrib/rename/browser/renameWidget.css similarity index 100% rename from src/vs/editor/contrib/rename/browser/renameInputField.css rename to src/vs/editor/contrib/rename/browser/renameWidget.css diff --git a/src/vs/editor/contrib/rename/browser/renameInputField.ts b/src/vs/editor/contrib/rename/browser/renameWidget.ts similarity index 96% rename from src/vs/editor/contrib/rename/browser/renameInputField.ts rename to src/vs/editor/contrib/rename/browser/renameWidget.ts index eb6bfde534b..ce051f73bb7 100644 --- a/src/vs/editor/contrib/rename/browser/renameInputField.ts +++ b/src/vs/editor/contrib/rename/browser/renameWidget.ts @@ -16,7 +16,7 @@ import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { StopWatch } from 'vs/base/common/stopwatch'; import { assertType, isDefined } from 'vs/base/common/types'; -import 'vs/css!./renameInputField'; +import 'vs/css!./renameWidget'; import { applyFontInfo } from 'vs/editor/browser/config/domFontInfo'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; @@ -66,24 +66,24 @@ export type NewNameSource = /** * Various statistics regarding rename input field */ -export type RenameInputFieldStats = { +export type RenameWidgetStats = { nRenameSuggestions: number; source: NewNameSource; timeBeforeFirstInputFieldEdit: number | undefined; }; -export type RenameInputFieldResult = { +export type RenameWidgetResult = { /** * The new name to be used */ newName: string; wantsPreview?: boolean; - stats: RenameInputFieldStats; + stats: RenameWidgetStats; }; -interface IRenameInputField { +interface IRenameWidget { /** - * @returns a `boolean` standing for `shouldFocusEditor`, if user didn't pick a new name, or a {@link RenameInputFieldResult} + * @returns a `boolean` standing for `shouldFocusEditor`, if user didn't pick a new name, or a {@link RenameWidgetResult} */ getInput( where: IRange, @@ -91,7 +91,7 @@ interface IRenameInputField { supportPreview: boolean, requestRenameSuggestions: (cts: CancellationToken) => ProviderResult[], cts: CancellationTokenSource - ): Promise; + ): Promise; acceptInput(wantsPreview: boolean): void; cancelInput(focusEditor: boolean, caller: string): void; @@ -100,7 +100,7 @@ interface IRenameInputField { focusPreviousRenameSuggestion(): void; } -export class RenameWidget implements IRenameInputField, IContentWidget, IDisposable { +export class RenameWidget implements IRenameWidget, IContentWidget, IDisposable { // implement IContentWidget readonly allowEditorOverflow: boolean = true; @@ -243,7 +243,7 @@ export class RenameWidget implements IRenameInputField, IContentWidget, IDisposa if (this._domNode === undefined) { return; } - assertType(this._label !== undefined, 'RenameInputField#_updateFont: _label must not be undefined given _domNode is defined'); + assertType(this._label !== undefined, 'RenameWidget#_updateFont: _label must not be undefined given _domNode is defined'); this._editor.applyFontInfo(this._input.domNode); @@ -361,14 +361,14 @@ export class RenameWidget implements IRenameInputField, IContentWidget, IDisposa where: IRange, currentName: string, supportPreview: boolean, - requestRenameSuggestions: (cts: CancellationToken) => ProviderResult[], + requestRenameCandidates: (cts: CancellationToken) => ProviderResult[], cts: CancellationTokenSource - ): Promise { + ): Promise { const { start: selectionStart, end: selectionEnd } = this._getSelection(where, currentName); this._renameCandidateProvidersCts = new CancellationTokenSource(); - const candidates = requestRenameSuggestions(this._renameCandidateProvidersCts.token); + const candidates = requestRenameCandidates(this._renameCandidateProvidersCts.token); this._updateRenameCandidates(candidates, currentName, cts.token); this._isEditingRenameCandidate = false; @@ -395,7 +395,7 @@ export class RenameWidget implements IRenameInputField, IContentWidget, IDisposa } })); - const inputResult = new DeferredPromise(); + const inputResult = new DeferredPromise(); inputResult.p.finally(() => { disposeOnDone.dispose(); @@ -547,7 +547,7 @@ export class RenameWidget implements IRenameInputField, IContentWidget, IDisposa if (visibleRanges.length > 0) { firstLineInViewport = visibleRanges[0].startLineNumber; } else { - this._logService.warn('RenameInputField#_getTopForPosition: this should not happen - visibleRanges is empty'); + this._logService.warn('RenameWidget#_getTopForPosition: this should not happen - visibleRanges is empty'); firstLineInViewport = Math.max(1, this._position!.lineNumber - 5); // @ulugbekna: fallback to current line minus 5 } return this._editor.getTopForLineNumber(this._position!.lineNumber) - this._editor.getTopForLineNumber(firstLineInViewport); From e675692acc4e5cc9d0ce71d2ba0c4b73820db7fa Mon Sep 17 00:00:00 2001 From: Ulugbek Abdullaev Date: Thu, 21 Mar 2024 16:33:21 +0100 Subject: [PATCH 7/7] rename suggestions: formatting --- .../editor/contrib/rename/browser/rename.ts | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/contrib/rename/browser/rename.ts b/src/vs/editor/contrib/rename/browser/rename.ts index 93ce518854e..10786e237ec 100644 --- a/src/vs/editor/contrib/rename/browser/rename.ts +++ b/src/vs/editor/contrib/rename/browser/rename.ts @@ -367,22 +367,23 @@ class RenameController implements IEditorContribution { wantsPreview?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'If user wanted preview.'; isMeasurement: true }; }; - const value: RenameInvokedEvent = typeof inputFieldResult === 'boolean' - ? { - kind: 'cancelled', - languageId, - nRenameSuggestionProviders, - } - : { - kind: 'accepted', - languageId, - nRenameSuggestionProviders, + const value: RenameInvokedEvent = + typeof inputFieldResult === 'boolean' + ? { + kind: 'cancelled', + languageId, + nRenameSuggestionProviders, + } + : { + kind: 'accepted', + languageId, + nRenameSuggestionProviders, - source: inputFieldResult.stats.source.k, - nRenameSuggestions: inputFieldResult.stats.nRenameSuggestions, - timeBeforeFirstInputFieldEdit: inputFieldResult.stats.timeBeforeFirstInputFieldEdit, - wantsPreview: inputFieldResult.wantsPreview, - }; + source: inputFieldResult.stats.source.k, + nRenameSuggestions: inputFieldResult.stats.nRenameSuggestions, + timeBeforeFirstInputFieldEdit: inputFieldResult.stats.timeBeforeFirstInputFieldEdit, + wantsPreview: inputFieldResult.wantsPreview, + }; if (inDebugMode) { this._telemetryService.publicLog2('renameInvokedEventDebug', value);