Skip to content

Commit

Permalink
Implement search offsets
Browse files Browse the repository at this point in the history
Line, beginning, and end offsets - no semicolon offsets (yet).
Fixes VSCodeVim#3917
  • Loading branch information
J-Fields authored and stevenguh committed Aug 27, 2019
1 parent 60e349b commit 5a19d6c
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 5 deletions.
16 changes: 16 additions & 0 deletions src/common/motion/position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,22 @@ export class Position extends vscode.Position {
return this.getRight();
}

public getOffsetThroughLineBreaks(offset: number): Position {
let pos = new Position(this.line, this.character);

if (offset < 0) {
for (let i = 0; i < -offset; i++) {
pos = pos.getLeftThroughLineBreaks();
}
} else {
for (let i = 0; i < offset; i++) {
pos = pos.getRightThroughLineBreaks();
}
}

return pos;
}

public getRight(count: number = 1): Position {
if (!this.isLineEnd()) {
return new Position(this.line, this.character + count);
Expand Down
68 changes: 63 additions & 5 deletions src/state/searchState.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as vscode from 'vscode';

import { configuration } from '../configuration/configuration';
import { Position } from './../common/motion/position';
import { Position, PositionDiff } from './../common/motion/position';
import { ModeName } from './../mode/mode';
import { TextEditor } from './../textEditor';
import { setFlagsFromString } from 'v8';

export enum SearchDirection {
Forward = 1,
Expand Down Expand Up @@ -42,6 +43,19 @@ export class SearchState {

private isRegex: boolean;

private needle = '';

// How to adjust the cursor's position after going to a match
// Some examples:
// /abc/3 will jump to the third character after finding abc
// /abc/b-2 will go 2 characters to the left after finding abc
// /abc/e2 will go 2 characters to the right from the end of abc after finding it
// TODO: support the ; offset (see http://vimdoc.sourceforge.net/htmldoc/pattern.html)
private offset?: {
type: 'line' | 'beginning' | 'end';
num: number;
};

private _searchString = '';
public get searchString(): string {
return this._searchString;
Expand All @@ -50,12 +64,44 @@ export class SearchState {
public set searchString(search: string) {
if (this._searchString !== search) {
this._searchString = search;
this._recalculateSearchRanges({ forceRecalc: true });

const oldNeedle = this.needle;
this.needle = search;
this.offset = undefined;

const needleSegments =
this.searchDirection === SearchDirection.Backward ? search.split('?') : search.split('/');
if (needleSegments.length > 1) {
this.needle = needleSegments[0];
const num = Number(needleSegments[1]);
if (isNaN(num)) {
if (/b(\+-)?[0-9]*/.test(needleSegments[1])) {
this.offset = {
type: 'beginning',
num: Number(needleSegments[1].slice(1)),
};
} else if (/e(\+-)?[0-9]*/.test(needleSegments[1])) {
this.offset = {
type: 'end',
num: Number(needleSegments[1].slice(1)),
};
}
} else {
this.offset = {
type: 'line',
num: num,
};
}
}

if (this.needle !== oldNeedle) {
this._recalculateSearchRanges({ forceRecalc: true });
}
}
}

private _recalculateSearchRanges({ forceRecalc }: { forceRecalc?: boolean } = {}): void {
const search = this.searchString;
const search = this.needle;
if (search === '') {
return;
}
Expand Down Expand Up @@ -203,8 +249,20 @@ export class SearchState {
startPosition: Position,
direction = 1
): { pos: Position; match: boolean; index: number } {
const { start, match, index } = this.getNextSearchMatchRange(startPosition, direction);
return { pos: start, match, index };
const { start, end, match, index } = this.getNextSearchMatchRange(startPosition, direction);

let pos = start;
if (this.offset) {
if (this.offset.type === 'line') {
pos = start.add(PositionDiff.NewBOLDiff(this.offset.num));
} else if (this.offset.type === 'beginning') {
pos = start.getOffsetThroughLineBreaks(this.offset.num);
} else if (this.offset.type === 'end') {
pos = end.getOffsetThroughLineBreaks(this.offset.num - 1);
}
}

return { pos, match, index };
}

/**
Expand Down
49 changes: 49 additions & 0 deletions test/mode/normalModeTests/motions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,55 @@ suite('Motions in Normal Mode', () => {
endMode: ModeName.Normal,
});

newTest({
title: 'Search offsets: b does nothing',
start: ['|hayneedlehay'],
keysPressed: '/needle/b\n',
end: ['hay|needlehay'],
});

newTest({
title: 'Search offsets: b2 goes 2 to the right',
start: ['|hayneedlehay'],
keysPressed: '/needle/b2\n',
end: ['hayne|edlehay'],
});

newTest({
title: 'Search offsets: b+3 goes 3 to the right',
start: ['|hayneedlehay'],
keysPressed: '/needle/b+3\n',
end: ['haynee|dlehay'],
});

newTest({
title: 'Search offsets: e goes to the end',
start: ['|hayneedlehay'],
keysPressed: '/needle/e\n',
end: ['hayneedl|ehay'],
});

newTest({
title: 'Search offsets: character offset goes across line boundaries',
start: ['|hayneedlehay', '123'],
keysPressed: '/needle/e+5\n',
end: ['hayneedlehay', '1|23'],
});

newTest({
title: 'Search offsets: 2 goes 2 down',
start: ['|hayneedlehay', 'abc', 'def'],
keysPressed: '/needle/2\n',
end: ['hayneedlehay', 'abc', '|def'],
});

newTest({
title: 'Search offsets: -2 goes 2 up',
start: ['abc', '|def', 'hayneedlehay', 'abc', 'def'],
keysPressed: '/needle/-2\n',
end: ['|abc', 'def', 'hayneedlehay', 'abc', 'def'],
});

newTest({
title: 'maintains column position correctly',
start: ['|one one one', 'two', 'three'],
Expand Down

0 comments on commit 5a19d6c

Please sign in to comment.