From 6c3cac03aa56310d8a325155e3dc20372746cdcf Mon Sep 17 00:00:00 2001 From: Ilya Golovin Date: Tue, 30 Aug 2022 22:51:40 +0300 Subject: [PATCH 1/9] Feat: implement brackets removing --- .../browser/bracketMatching.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts index d43fb6f30db89..9c573ee0392eb 100644 --- a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts @@ -79,6 +79,25 @@ class SelectToBracketAction extends EditorAction { BracketMatchingController.get(editor)?.selectToBracket(selectBrackets); } } +class RemoveBracketsAction extends EditorAction { + constructor() { + super({ + id: 'editor.action.removeBrackets', + label: nls.localize('smartSelect.removeBrackets', "Remove Brackets"), + alias: 'Remove Brackets', + precondition: undefined, + kbOpts: { + kbExpr: EditorContextKeys.editorTextFocus, + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Backspace, + weight: KeybindingWeight.EditorContrib + } + }); + } + + public run(accessor: ServicesAccessor, editor: ICodeEditor): void { + BracketMatchingController.get(editor)?.removeBrackets(); + } +} type Brackets = [Range, Range]; @@ -252,6 +271,22 @@ export class BracketMatchingController extends Disposable implements IEditorCont this._editor.revealRange(newSelections[0]); } } + public removeBrackets(): void { + if (!this._editor.hasModel()) { + return; + } + + const model = this._editor.getModel(); + this._editor.getSelections().map((selection) => { + const position = selection.getPosition(); + + const brackets = model.bracketPairs.matchBracket(position); + if (brackets) { + this._editor.executeEdits(null, + [{ range: brackets[0], text: '', }, { range: brackets[1], text: '' }]); + } + }); + } private static readonly _DECORATION_OPTIONS_WITH_OVERVIEW_RULER = ModelDecorationOptions.register({ description: 'bracket-match-overview', @@ -360,6 +395,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont registerEditorContribution(BracketMatchingController.ID, BracketMatchingController); registerEditorAction(SelectToBracketAction); registerEditorAction(JumpToBracketAction); +registerEditorAction(RemoveBracketsAction); registerThemingParticipant((theme, collector) => { const bracketMatchBackground = theme.getColor(editorBracketMatchBackground); if (bracketMatchBackground) { From 5f642009005d79396bbc75242e82ea3fdc6381ee Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 27 Aug 2022 00:31:01 +0300 Subject: [PATCH 2/9] demo --- .../browser/bracketMatching.ts | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts index 9c573ee0392eb..8196094b13950 100644 --- a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts @@ -46,6 +46,26 @@ class JumpToBracketAction extends EditorAction { } } +class RemoveBracketsAction extends EditorAction { + constructor() { + super({ + id: 'editor.action.removeBrackets', + label: nls.localize('smartSelect.jumpBracke2t', "Remove brackets"), + alias: 'Remove brackets', + precondition: undefined, + // kbOpts: { + // kbExpr: EditorContextKeys.editorTextFocus, + // primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Backslash, + // weight: KeybindingWeight.EditorContrib + // } + }); + } + + public run(accessor: ServicesAccessor, editor: ICodeEditor): void { + BracketMatchingController.get(editor)?.removeBrackets(); + } +} + class SelectToBracketAction extends EditorAction { constructor() { super({ @@ -288,6 +308,55 @@ export class BracketMatchingController extends Disposable implements IEditorCont }); } + public removeBrackets(): void { + if (!this._editor.hasModel()) { + return; + } + + const model = this._editor.getModel(); + const removeBrackets: Array<[Position, Position]> = []; + + this._editor.getSelections().forEach(selection => { + const position = selection.getStartPosition(); + let brackets = model.bracketPairs.matchBracket(position); + + if (!brackets) { + brackets = model.bracketPairs.findEnclosingBrackets(position); + if (!brackets) { + const nextBracket = model.bracketPairs.findNextBracket(position); + if (nextBracket && nextBracket.range) { + brackets = model.bracketPairs.matchBracket(nextBracket.range.getStartPosition()); + } + } + } + + let firstBracket: Position | null = null; + let lastBracket: Position | null = null; + + if (brackets) { + brackets.sort(Range.compareRangesUsingStarts); + const [open, close] = brackets; + firstBracket = open.getStartPosition(); + lastBracket = close.getEndPosition(); + } + + if (firstBracket && lastBracket) { + removeBrackets.push([firstBracket, lastBracket]); + } + }); + + if (removeBrackets.length > 0) { + + this._editor.executeEdits('source', removeBrackets.map((brackets) => { + + return brackets.map((pos, i) => ({ + range: { startColumn: pos.column, endColumn: pos.column + (i === 0 ? 1 : -1), startLineNumber: pos.lineNumber, endLineNumber: pos.lineNumber }, + text: '' + })); + }).flat(1)); + } + } + private static readonly _DECORATION_OPTIONS_WITH_OVERVIEW_RULER = ModelDecorationOptions.register({ description: 'bracket-match-overview', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, From 96419a2dbcc80b4e3a980df6f2953ab54ca6f9b1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 7 Sep 2022 10:28:57 +0300 Subject: [PATCH 3/9] up impl --- .../browser/bracketMatching.ts | 72 +------------------ 1 file changed, 3 insertions(+), 69 deletions(-) diff --git a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts index 8196094b13950..e103b6b751809 100644 --- a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts @@ -46,26 +46,6 @@ class JumpToBracketAction extends EditorAction { } } -class RemoveBracketsAction extends EditorAction { - constructor() { - super({ - id: 'editor.action.removeBrackets', - label: nls.localize('smartSelect.jumpBracke2t', "Remove brackets"), - alias: 'Remove brackets', - precondition: undefined, - // kbOpts: { - // kbExpr: EditorContextKeys.editorTextFocus, - // primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Backslash, - // weight: KeybindingWeight.EditorContrib - // } - }); - } - - public run(accessor: ServicesAccessor, editor: ICodeEditor): void { - BracketMatchingController.get(editor)?.removeBrackets(); - } -} - class SelectToBracketAction extends EditorAction { constructor() { super({ @@ -297,64 +277,18 @@ export class BracketMatchingController extends Disposable implements IEditorCont } const model = this._editor.getModel(); - this._editor.getSelections().map((selection) => { + this._editor.getSelections().forEach((selection) => { const position = selection.getPosition(); - const brackets = model.bracketPairs.matchBracket(position); - if (brackets) { - this._editor.executeEdits(null, - [{ range: brackets[0], text: '', }, { range: brackets[1], text: '' }]); - } - }); - } - - public removeBrackets(): void { - if (!this._editor.hasModel()) { - return; - } - - const model = this._editor.getModel(); - const removeBrackets: Array<[Position, Position]> = []; - - this._editor.getSelections().forEach(selection => { - const position = selection.getStartPosition(); let brackets = model.bracketPairs.matchBracket(position); - if (!brackets) { brackets = model.bracketPairs.findEnclosingBrackets(position); - if (!brackets) { - const nextBracket = model.bracketPairs.findNextBracket(position); - if (nextBracket && nextBracket.range) { - brackets = model.bracketPairs.matchBracket(nextBracket.range.getStartPosition()); - } - } } - - let firstBracket: Position | null = null; - let lastBracket: Position | null = null; - if (brackets) { - brackets.sort(Range.compareRangesUsingStarts); - const [open, close] = brackets; - firstBracket = open.getStartPosition(); - lastBracket = close.getEndPosition(); - } - - if (firstBracket && lastBracket) { - removeBrackets.push([firstBracket, lastBracket]); + this._editor.executeEdits(null, + [{ range: brackets[0], text: '', }, { range: brackets[1], text: '' }]); } }); - - if (removeBrackets.length > 0) { - - this._editor.executeEdits('source', removeBrackets.map((brackets) => { - - return brackets.map((pos, i) => ({ - range: { startColumn: pos.column, endColumn: pos.column + (i === 0 ? 1 : -1), startLineNumber: pos.lineNumber, endLineNumber: pos.lineNumber }, - text: '' - })); - }).flat(1)); - } } private static readonly _DECORATION_OPTIONS_WITH_OVERVIEW_RULER = ModelDecorationOptions.register({ From a8bf3ead0ed582fde3c95812e634ae30201361a2 Mon Sep 17 00:00:00 2001 From: Vitaly Date: Wed, 7 Sep 2022 11:56:56 +0300 Subject: [PATCH 4/9] add test --- .../test/browser/bracketMatching.test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts b/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts index c2e738046d357..a763778420018 100644 --- a/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts +++ b/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts @@ -209,4 +209,24 @@ suite('bracket matching', () => { new Selection(1, 19, 1, 16) ]); }); + + test('Removes brackets', () => { + const editor = createCodeEditorWithBrackets('var x = (3 + (5-7)); y();'); + const bracketMatchingController = disposables.add(editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController)); + + // position before the bracket + editor.setPosition(new Position(1, 9)); + bracketMatchingController.removeBrackets(); + assert.deepStrictEqual(editor.getModel().getValue(), 'var x = 3 + (5-7); y();'); + editor.getModel().setValue('var x = (3 + (5-7)); y();'); + + // position between brackets + editor.setPosition(new Position(1, 16)); + bracketMatchingController.removeBrackets(); + assert.deepStrictEqual(editor.getModel().getValue(), 'var x = (3 + 5-7); y();'); + bracketMatchingController.removeBrackets(); + assert.deepStrictEqual(editor.getModel().getValue(), 'var x = 3 + 5-7; y();'); + bracketMatchingController.removeBrackets(); + assert.deepStrictEqual(editor.getModel().getValue(), 'var x = 3 + 5-7; y();'); + }); }); From b2bc6c55e121389824b12a46545c9ed7380d66cc Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 14 Sep 2022 09:11:28 +0300 Subject: [PATCH 5/9] refactor for future replace brackets command implementation will be much cleaner --- .../contrib/bracketMatching/browser/bracketMatching.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts index e103b6b751809..5cc443648da5e 100644 --- a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts @@ -95,7 +95,7 @@ class RemoveBracketsAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICodeEditor): void { - BracketMatchingController.get(editor)?.removeBrackets(); + BracketMatchingController.get(editor)?.replaceBrackets('', ''); } } @@ -271,7 +271,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont this._editor.revealRange(newSelections[0]); } } - public removeBrackets(): void { + public replaceBrackets(openingContent: string, closingContent: string,): void { if (!this._editor.hasModel()) { return; } @@ -286,7 +286,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont } if (brackets) { this._editor.executeEdits(null, - [{ range: brackets[0], text: '', }, { range: brackets[1], text: '' }]); + [{ range: brackets[0], text: openingContent, }, { range: brackets[1], text: closingContent }]); } }); } From 5600459b36a749b991e6ceea86bf0a62c12d183c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 14 Sep 2022 09:13:00 +0300 Subject: [PATCH 6/9] -`,` --- .../editor/contrib/bracketMatching/browser/bracketMatching.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts index 5cc443648da5e..18f52c57fc54d 100644 --- a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts @@ -271,7 +271,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont this._editor.revealRange(newSelections[0]); } } - public replaceBrackets(openingContent: string, closingContent: string,): void { + public replaceBrackets(openingContent: string, closingContent: string): void { if (!this._editor.hasModel()) { return; } From d1710fb9452b9d0c61ac4842d1ea8740aae32d27 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 14 Sep 2022 12:22:18 +0300 Subject: [PATCH 7/9] fix tests compile --- .../test/browser/bracketMatching.test.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts b/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts index a763778420018..6ba6a71078891 100644 --- a/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts +++ b/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts @@ -213,20 +213,23 @@ suite('bracket matching', () => { test('Removes brackets', () => { const editor = createCodeEditorWithBrackets('var x = (3 + (5-7)); y();'); const bracketMatchingController = disposables.add(editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController)); + function removeBrackets() { + bracketMatchingController.replaceBrackets('', ''); + } // position before the bracket editor.setPosition(new Position(1, 9)); - bracketMatchingController.removeBrackets(); + removeBrackets(); assert.deepStrictEqual(editor.getModel().getValue(), 'var x = 3 + (5-7); y();'); editor.getModel().setValue('var x = (3 + (5-7)); y();'); // position between brackets editor.setPosition(new Position(1, 16)); - bracketMatchingController.removeBrackets(); + removeBrackets(); assert.deepStrictEqual(editor.getModel().getValue(), 'var x = (3 + 5-7); y();'); - bracketMatchingController.removeBrackets(); + removeBrackets(); assert.deepStrictEqual(editor.getModel().getValue(), 'var x = 3 + 5-7; y();'); - bracketMatchingController.removeBrackets(); + removeBrackets(); assert.deepStrictEqual(editor.getModel().getValue(), 'var x = 3 + 5-7; y();'); }); }); From 041162720124701905526e9b022ad1816c3bcbab Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 1 Mar 2023 21:15:29 +0300 Subject: [PATCH 8/9] push undo stops and pass command source id --- .../bracketMatching/browser/bracketMatching.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts index 66694153e1887..b66bd520d90f2 100644 --- a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts @@ -94,7 +94,7 @@ class RemoveBracketsAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICodeEditor): void { - BracketMatchingController.get(editor)?.replaceBrackets('', ''); + BracketMatchingController.get(editor)?.replaceBrackets('', '', this.id); } } @@ -270,7 +270,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont this._editor.revealRange(newSelections[0]); } } - public replaceBrackets(openingContent: string, closingContent: string): void { + public replaceBrackets(openingContent: string, closingContent: string, editSource?: string): void { if (!this._editor.hasModel()) { return; } @@ -284,8 +284,15 @@ export class BracketMatchingController extends Disposable implements IEditorCont brackets = model.bracketPairs.findEnclosingBrackets(position); } if (brackets) { - this._editor.executeEdits(null, - [{ range: brackets[0], text: openingContent, }, { range: brackets[1], text: closingContent }]); + this._editor.pushUndoStop(); + this._editor.executeEdits( + editSource, + [ + { range: brackets[0], text: openingContent }, + { range: brackets[1], text: closingContent } + ] + ); + this._editor.pushUndoStop(); } }); } From 3965ebd5761df03634107944214d8fc2366df44d Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 2 Mar 2023 14:04:22 +0300 Subject: [PATCH 9/9] simplify. revert b2bc6c55e121389824b12a46545c9ed7380d66cc --- .../contrib/bracketMatching/browser/bracketMatching.ts | 8 ++++---- .../bracketMatching/test/browser/bracketMatching.test.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts index b66bd520d90f2..a3b15fd4ae607 100644 --- a/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts @@ -94,7 +94,7 @@ class RemoveBracketsAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICodeEditor): void { - BracketMatchingController.get(editor)?.replaceBrackets('', '', this.id); + BracketMatchingController.get(editor)?.removeBrackets(this.id); } } @@ -270,7 +270,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont this._editor.revealRange(newSelections[0]); } } - public replaceBrackets(openingContent: string, closingContent: string, editSource?: string): void { + public removeBrackets(editSource?: string): void { if (!this._editor.hasModel()) { return; } @@ -288,8 +288,8 @@ export class BracketMatchingController extends Disposable implements IEditorCont this._editor.executeEdits( editSource, [ - { range: brackets[0], text: openingContent }, - { range: brackets[1], text: closingContent } + { range: brackets[0], text: '' }, + { range: brackets[1], text: '' } ] ); this._editor.pushUndoStop(); diff --git a/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts b/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts index 6ba6a71078891..c16f4d7e9af45 100644 --- a/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts +++ b/src/vs/editor/contrib/bracketMatching/test/browser/bracketMatching.test.ts @@ -214,7 +214,7 @@ suite('bracket matching', () => { const editor = createCodeEditorWithBrackets('var x = (3 + (5-7)); y();'); const bracketMatchingController = disposables.add(editor.registerAndInstantiateContribution(BracketMatchingController.ID, BracketMatchingController)); function removeBrackets() { - bracketMatchingController.replaceBrackets('', ''); + bracketMatchingController.removeBrackets(); } // position before the bracket