Skip to content

Commit

Permalink
Merge pull request #1267 from rufusroflpunch/master
Browse files Browse the repository at this point in the history
Delete matching bracket upon backspace
  • Loading branch information
johnfn authored Feb 7, 2017
2 parents 2d41501 + 8b62526 commit 3c957ba
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 2 deletions.
36 changes: 34 additions & 2 deletions src/matching/matcher.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Position } from './../motion/position';
import { Position, PositionDiff } from './../motion/position';
import * as vscode from 'vscode';

/**
* PairMatcher finds the position matching the given character, respecting nested
Expand All @@ -14,8 +15,13 @@ export class PairMatcher {
"]" : { match: "[", nextMatchIsForward: false, matchesWithPercentageMotion: true },
// These characters can't be used for "%"-based matching, but are still
// useful for text objects.
"<" : { match: ">", nextMatchIsForward: true },
"<" : { match: ">", nextMatchIsForward: true },
">" : { match: "<", nextMatchIsForward: false },
// These are useful for deleting closing and opening quotes, but don't seem to negatively
// affect how text objects such as `ci"` work, which was my worry.
'"' : { match: '"', nextMatchIsForward: true },
"'" : { match: "'", nextMatchIsForward: true },
"`" : { match: "`", nextMatchIsForward: true },
};

static nextPairedChar(position: Position, charToMatch: string, closed: boolean = true): Position | undefined {
Expand Down Expand Up @@ -62,4 +68,30 @@ export class PairMatcher {
// TODO(bell)
return undefined;
}

/**
* Given a current position, find an immediate following bracket and return the range. If
* no matching bracket is found immediately following the opening bracket, return undefined.
*/
static immediateMatchingBracket(currentPosition: Position): vscode.Range | undefined {
// Don't delete bracket unless autoClosingBrackets is set
if (!vscode.workspace.getConfiguration().get("editor.autoClosingBrackets")) { return undefined; }

const deleteRange = new vscode.Range(currentPosition, currentPosition.getLeftThroughLineBreaks());
const deleteText = vscode.window.activeTextEditor.document.getText(deleteRange);
let matchRange: vscode.Range | undefined;
let isNextMatch = false;

if ("{[(\"'`".indexOf(deleteText) > -1) {
const matchPosition = currentPosition.add(new PositionDiff(0, 1));
matchRange = new vscode.Range(matchPosition, matchPosition.getLeftThroughLineBreaks());
isNextMatch = vscode.window.activeTextEditor.document.getText(matchRange) === PairMatcher.pairings[deleteText].match;
}

if (isNextMatch && matchRange) {
return matchRange;
}

return undefined;
}
}
2 changes: 2 additions & 0 deletions src/mode/modeHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,8 @@ export class ModeHandler implements vscode.Disposable {
break;

case "deleteText":
let matchRange = PairMatcher.immediateMatchingBracket(command.position);
if (matchRange) { edit.delete(matchRange); }
edit.delete(new vscode.Range(command.position, command.position.getLeftThroughLineBreaks()));
break;

Expand Down
18 changes: 18 additions & 0 deletions test/mode/modeInsert.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,24 @@ suite("Mode Insert", () => {
assertEqualLines([" "]);
});

test("will remove closing bracket", async() => {
await modeHandler.handleMultipleKeyEvents([
'i',
'(',
'<Esc>'
]);

assertEqualLines(["()"]);

await modeHandler.handleMultipleKeyEvents([
'a',
'<BS>',
'<Esc>'
]);

assertEqualLines([""]);
});

newTest({
title: "Can perform <ctrl+o> to exit and perform one command in normal",
start: ['testtest|'],
Expand Down

0 comments on commit 3c957ba

Please sign in to comment.