Fix bug with bracket matching and improve it with counts

This commit is contained in:
jasonwilliams 2024-02-01 23:01:27 +00:00
parent e17dcb808f
commit 4ec1caf239
3 changed files with 51 additions and 74 deletions

View File

@ -3,6 +3,7 @@ import { Action } from '../action_types';
import { enterInsertMode, setModeCursorStyle } from '../modes';
import { Mode } from '../modes_types';
import { parseKeysExact, parseKeysRegex } from '../parse_keys';
import { searchBackwardBracket, searchForwardBracket } from '../search_utils';
import { removeTypeSubscription } from '../type_subscription';
import { delete_ } from './operators';
@ -55,8 +56,20 @@ export const matchActions: Action[] = [
const [startCharNew, endCharNew] = getMatchPairs(replacement);
const num = helixState.resolveCount();
const forwardPosition = searchFowardForChar(endCharOrig, editor.selection.active, num);
const backwardPosition = searchBackwardForChar(startCharOrig, editor.selection.active, num);
const forwardPosition = searchForwardBracket(
editor.document,
startCharOrig,
endCharOrig,
editor.selection.active,
num,
);
const backwardPosition = searchBackwardBracket(
editor.document,
startCharOrig,
endCharOrig,
editor.selection.active,
num,
);
if (forwardPosition === undefined || backwardPosition === undefined) return;
@ -80,8 +93,8 @@ export const matchActions: Action[] = [
const [startChar, endChar] = getMatchPairs(char);
const num = helixState.resolveCount();
const forwardPosition = searchFowardForChar(endChar, editor.selection.active, num);
const backwardPosition = searchBackwardForChar(startChar, editor.selection.active, num);
const forwardPosition = searchForwardBracket(editor.document, startChar, endChar, editor.selection.active, num);
const backwardPosition = searchBackwardBracket(editor.document, startChar, endChar, editor.selection.active, num);
if (forwardPosition === undefined || backwardPosition === undefined) return;
@ -98,58 +111,6 @@ export const matchActions: Action[] = [
}),
];
const searchFowardForChar = (char: string, fromPosition: vscode.Position, num: number): vscode.Position | undefined => {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
const document = editor.document;
// num starts at 1 so we should drop down to 0, as 1 is the default
// even if count wasn't specified
let count = --num;
for (let i = fromPosition.line; i < document.lineCount; ++i) {
const lineText = document.lineAt(i).text;
const fromIndex = i === fromPosition.line ? fromPosition.character : 0;
for (let j = fromIndex; j < lineText.length; ++j) {
if (lineText[j] === char && count === 0) {
return new vscode.Position(i, j);
} else if (lineText[j] === char) {
--count;
}
}
}
return undefined;
};
const searchBackwardForChar = (
char: string,
fromPosition: vscode.Position,
num: number,
): vscode.Position | undefined => {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
const document = editor.document;
// num starts at 1 so we should drop down to 0, as 1 is the default
// even if count wasn't specified
let count = --num;
for (let i = fromPosition.line; i >= 0; --i) {
const lineText = document.lineAt(i).text;
const fromIndex = i === fromPosition.line ? fromPosition.character : lineText.length - 1;
for (let j = fromIndex; j >= 0; --j) {
if (lineText[j] === char && count === 0) {
return new vscode.Position(i, j);
} else if (lineText[j] === char) {
--count;
}
}
}
return undefined;
};
const getMatchPairs = (char: string) => {
let startChar: string;
let endChar: string;

View File

@ -304,8 +304,9 @@ function createInnerBracketHandler(
openingChar: string,
closingChar: string,
): (vimState: HelixState, document: vscode.TextDocument, position: vscode.Position) => vscode.Range | undefined {
return (vimState, document, position) => {
const bracketRange = getBracketRange(document, position, openingChar, closingChar);
return (helixState, document, position) => {
const count = helixState.resolveCount();
const bracketRange = getBracketRange(document, position, openingChar, closingChar, count);
if (bracketRange) {
return new vscode.Range(
@ -324,8 +325,9 @@ function createOuterBracketHandler(
openingChar: string,
closingChar: string,
): (vimState: HelixState, document: vscode.TextDocument, position: vscode.Position) => vscode.Range | undefined {
return (vimState, document, position) => {
const bracketRange = getBracketRange(document, position, openingChar, closingChar);
return (helixState, document, position) => {
const count = helixState.resolveCount();
const bracketRange = getBracketRange(document, position, openingChar, closingChar, count);
if (bracketRange) {
return new vscode.Range(bracketRange.start, bracketRange.end.with({ character: bracketRange.end.character + 1 }));
@ -340,6 +342,7 @@ function getBracketRange(
position: vscode.Position,
openingChar: string,
closingChar: string,
offset?: number,
): vscode.Range | undefined {
const lineText = document.lineAt(position.line).text;
const currentChar = lineText[position.character];
@ -348,13 +351,19 @@ function getBracketRange(
let end;
if (currentChar === openingChar) {
start = position;
end = searchForwardBracket(document, openingChar, closingChar, positionUtils.rightWrap(document, position));
end = searchForwardBracket(document, openingChar, closingChar, positionUtils.rightWrap(document, position), offset);
} else if (currentChar === closingChar) {
start = searchBackwardBracket(document, openingChar, closingChar, positionUtils.leftWrap(document, position));
start = searchBackwardBracket(
document,
openingChar,
closingChar,
positionUtils.leftWrap(document, position),
offset,
);
end = position;
} else {
start = searchBackwardBracket(document, openingChar, closingChar, position);
end = searchForwardBracket(document, openingChar, closingChar, position);
start = searchBackwardBracket(document, openingChar, closingChar, position, offset);
end = searchForwardBracket(document, openingChar, closingChar, position, offset);
}
if (start && end) {
@ -507,17 +516,18 @@ function createOuterWordHandler(
* This should ensure that we're fetching the nearest bracket pair.
**/
function createInnerMatchHandler(): (
vimState: HelixState,
helixState: HelixState,
document: vscode.TextDocument,
position: vscode.Position,
) => vscode.Range | undefined {
return (_, document, position) => {
return (helixState, document, position) => {
const count = helixState.resolveCount();
// Get all ranges from our position then reduce down to the shortest one
const bracketRange = [
getBracketRange(document, position, '(', ')'),
getBracketRange(document, position, '{', '}'),
getBracketRange(document, position, '<', '>'),
getBracketRange(document, position, '[', ']'),
getBracketRange(document, position, '(', ')', count),
getBracketRange(document, position, '{', '}', count),
getBracketRange(document, position, '<', '>', count),
getBracketRange(document, position, '[', ']', count),
].reduce((acc, range) => {
if (range) {
if (!acc) {

View File

@ -55,15 +55,18 @@ export function searchForwardBracket(
openingChar: string,
closingChar: string,
fromPosition: vscode.Position,
offset?: number,
): vscode.Position | undefined {
let n = 0;
let n = offset ? offset - 1 : 0;
for (let i = fromPosition.line; i < document.lineCount; ++i) {
const lineText = document.lineAt(i).text;
const fromIndex = i === fromPosition.line ? fromPosition.character : 0;
for (let j = fromIndex; j < lineText.length; ++j) {
if (lineText[j] === openingChar) {
// If closing and opening are the same, don't bother deducting n
// However if they are different, we need to deduct n when we see an opening char
if (lineText[j] === openingChar && openingChar !== closingChar) {
++n;
} else if (lineText[j] === closingChar) {
if (n === 0) {
@ -83,15 +86,18 @@ export function searchBackwardBracket(
openingChar: string,
closingChar: string,
fromPosition: vscode.Position,
offset?: number,
): vscode.Position | undefined {
let n = 0;
let n = offset ? offset - 1 : 0;
for (let i = fromPosition.line; i >= 0; --i) {
const lineText = document.lineAt(i).text;
const fromIndex = i === fromPosition.line ? fromPosition.character : lineText.length - 1;
for (let j = fromIndex; j >= 0; --j) {
if (lineText[j] === closingChar) {
// If closing and opening are the same, don't bother deducting n
// However if they are different, we need to deduct n when we see an opening char
if (lineText[j] === closingChar && closingChar !== openingChar) {
++n;
} else if (lineText[j] === openingChar) {
if (n === 0) {