diff --git a/src/matching/matcher.ts b/src/matching/matcher.ts index 228d23d1310..b7d2a6ade0d 100644 --- a/src/matching/matcher.ts +++ b/src/matching/matcher.ts @@ -32,6 +32,10 @@ export class PairMatcher { */ const toFind = this.pairings[charToMatch]; + if (toFind === undefined) { + return undefined; + } + let stackHeight = closed ? 0 : 1; let matchedPosition: Position | undefined = undefined; diff --git a/src/mode/modeHandler.ts b/src/mode/modeHandler.ts index 2aa89dd069c..c47ab695db2 100644 --- a/src/mode/modeHandler.ts +++ b/src/mode/modeHandler.ts @@ -24,6 +24,7 @@ import { Position } from './../motion/position'; import { RegisterMode } from './../register/register'; import { showCmdLine } from '../../src/cmd_line/main'; import { Configuration } from '../../src/configuration/configuration'; +import { PairMatcher } from './../matching/matcher'; export enum VimSpecialCommands { Nothing, @@ -1086,35 +1087,32 @@ export class ModeHandler implements vscode.Disposable { ModeHandler._statusBarItem.show(); } - // Return true if a new undo point should be created based on the keypress + // Return true if a new undo point should be created based on brackets and parenthesis private createUndoPointForBrackets(vimState: VimState): boolean { // }])> keys all start a new undo state when directly next to an {[(< opening character const key = vimState.recordedState.actionKeys[vimState.recordedState.actionKeys.length - 1]; - if (vimState.currentMode === ModeName.Insert) { + if (key === undefined) { + return false; + } - if (TextEditor.getLineAt(vimState.cursorPosition).text.length <= 1) { - return false; + if (vimState.currentMode === ModeName.Insert) { + // Check if the keypress is a closing bracket to a corresponding opening bracket right next to it + let result = PairMatcher.nextPairedChar(vimState.cursorPosition, key, false); + if (result !== undefined) { + if (vimState.cursorPosition.compareTo(result) === 0) { + return true; + } } - const letterToTheLeft = TextEditor.getLineAt(vimState.cursorPosition).text[vimState.cursorPosition.character - 2]; - switch (key) { - case "}": - if (letterToTheLeft === "{") { return true; } - break; - case "]": - if (letterToTheLeft === "[") { return true; } - break; - case ")": - if (letterToTheLeft === "(") { return true; } - break; - case ">": - if (letterToTheLeft === "<") { return true; } - break; - default: - return false; + result = PairMatcher.nextPairedChar(vimState.cursorPosition.getLeft(), key, true); + if (result !== undefined) { + if (vimState.cursorPosition.getLeftByCount(2).compareTo(result) === 0) { + return true; + } } } + return false; } diff --git a/src/motion/position.ts b/src/motion/position.ts index f8ba2d1d0f9..f538b0caf5e 100644 --- a/src/motion/position.ts +++ b/src/motion/position.ts @@ -256,7 +256,7 @@ export class Position extends vscode.Position { } /** - * Get the position *count* lines up from this position, but not lower + * Get the position *count* lines up from this position, but not higher * than the end of the document. */ public getUpByCount(count = 0): Position { @@ -266,6 +266,22 @@ export class Position extends vscode.Position { ); } + /** + * Get the position *count* lines left from this position, but not farther + * than the beginning of the line + */ + public getLeftByCount(count = 0): Position { + return new Position(this.line, Math.max(0, this.character - count)); + } + + /** + * Get the position *count* lines right from this position, but not farther + * than the end of the line + */ + public getRightByCount(count = 0): Position { + return new Position(this.line, Math.min(TextEditor.getLineAt(this).text.length - 1, this.character + count)); + } + /** * Inclusive is true if we consider the current position a valid result, false otherwise. */