Skip to content

Commit

Permalink
Fix #438 - Limit the number of matches,
Browse files Browse the repository at this point in the history
and try to only recalculate when the searchString changes, or the document changes
  • Loading branch information
roblourens committed Jul 26, 2016
1 parent 93a1f44 commit 47367f1
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 40 deletions.
10 changes: 5 additions & 5 deletions src/actions/actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { VimSpecialCommands, VimState, SearchState } from './../mode/modeHandler';
import { VimSpecialCommands, VimState, SearchState, SearchDirection } from './../mode/modeHandler';
import { ModeName } from './../mode/mode';
import { TextEditor } from './../textEditor';
import { Register, RegisterMode } from './../register/register';
Expand Down Expand Up @@ -490,7 +490,7 @@ class CommandStar extends BaseCommand {
public async exec(position: Position, vimState: VimState): Promise<VimState> {
const currentWord = CommandStar.GetWordAtPosition(position);

vimState.searchState = new SearchState(+1, vimState.cursorPosition, currentWord);
vimState.searchState = new SearchState(SearchDirection.Forward, vimState.cursorPosition, currentWord);

do {
vimState.cursorPosition = vimState.searchState.getNextSearchMatchPosition(vimState.cursorPosition).pos;
Expand All @@ -517,7 +517,7 @@ class CommandHash extends BaseCommand {
public async exec(position: Position, vimState: VimState): Promise<VimState> {
const currentWord = CommandStar.GetWordAtPosition(position);

vimState.searchState = new SearchState(-1, vimState.cursorPosition, currentWord);
vimState.searchState = new SearchState(SearchDirection.Backward, vimState.cursorPosition, currentWord);

do {
// use getWordLeft() on position to start at the beginning of the word.
Expand Down Expand Up @@ -606,7 +606,7 @@ export class CommandSearchForwards extends BaseCommand {
isMotion = true;

public async exec(position: Position, vimState: VimState): Promise<VimState> {
vimState.searchState = new SearchState(+1, vimState.cursorPosition);
vimState.searchState = new SearchState(SearchDirection.Forward, vimState.cursorPosition);
vimState.currentMode = ModeName.SearchInProgressMode;

return vimState;
Expand All @@ -620,7 +620,7 @@ export class CommandSearchBackwards extends BaseCommand {
isMotion = true;

public async exec(position: Position, vimState: VimState): Promise<VimState> {
vimState.searchState = new SearchState(-1, vimState.cursorPosition);
vimState.searchState = new SearchState(SearchDirection.Backward, vimState.cursorPosition);
vimState.currentMode = ModeName.SearchInProgressMode;

return vimState;
Expand Down
82 changes: 47 additions & 35 deletions src/mode/modeHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,50 +128,63 @@ export class VimSettings {
useCtrlKeys = false;
}

export enum SearchDirection {
Forward = 1,
Backward = -1
}

export class SearchState {
private static readonly MAX_SEARCH_RANGES = 1000;

/**
* Every range in the document that matches the search string.
*/
public matchRanges: vscode.Range[] = [];
private _matchRanges: vscode.Range[] = [];
public get matchRanges(): vscode.Range[] {
return this._matchRanges;
}

private _searchCursorStartPosition: Position;
public get searchCursorStartPosition(): Position {
return this._searchCursorStartPosition;
}

private _matchesDocVersion: number;
private _searchDirection: SearchDirection = SearchDirection.Forward;

private _searchString = "";
public get searchString(): string {
return this._searchString;
}

public searchCursorStartPosition: Position;

/**
* 1 === forward
* -1 === backward
*/
public searchDirection = 1;


public set searchString(search: string){
this._searchString = search;

this._recalculateSearchRanges();
if (this._searchString !== search) {
this._searchString = search;
this._recalculateSearchRanges(/*forceRecalc=*/true);
}
}

private _recalculateSearchRanges(): void {
private _recalculateSearchRanges(forceRecalc?: boolean): void {
const search = this.searchString;

if (search === "") { return; }

// Calculate and store all matching ranges
this.matchRanges = [];
if (this._matchesDocVersion !== TextEditor.getDocumentVersion() || forceRecalc) {
// Calculate and store all matching ranges
this._matchesDocVersion = TextEditor.getDocumentVersion();
this._matchRanges = [];

for (let lineIdx = 0; lineIdx < TextEditor.getLineCount(); lineIdx++) {
const line = TextEditor.getLineAt(new Position(lineIdx, 0)).text;
for (let lineIdx = 0; lineIdx < TextEditor.getLineCount() && this._matchRanges.length < SearchState.MAX_SEARCH_RANGES; lineIdx++) {
const line = TextEditor.getLineAt(new Position(lineIdx, 0)).text;

let i = line.indexOf(search);
let i = line.indexOf(search);

for (; i !== -1; i = line.indexOf(search, i + search.length)) {
this.matchRanges.push(new vscode.Range(
new Position(lineIdx, i),
new Position(lineIdx, i + search.length)
));
for (; i !== -1 && this._matchRanges.length < SearchState.MAX_SEARCH_RANGES; i = line.indexOf(search, i + search.length)) {
this._matchRanges.push(new vscode.Range(
new Position(lineIdx, i),
new Position(lineIdx, i + search.length)
));
}
}
}
}
Expand All @@ -184,41 +197,41 @@ export class SearchState {
public getNextSearchMatchPosition(startPosition: Position, direction = 1): { pos: Position, match: boolean} {
this._recalculateSearchRanges();

if (this.matchRanges.length === 0) {
if (this._matchRanges.length === 0) {
// TODO(bell)
return { pos: startPosition, match: false };
}

const effectiveDirection = direction * this.searchDirection;
const effectiveDirection = direction * this._searchDirection;

if (effectiveDirection === 1) {
for (let matchRange of this.matchRanges) {
if (effectiveDirection === SearchDirection.Forward) {
for (let matchRange of this._matchRanges) {
if (matchRange.start.compareTo(startPosition) > 0) {
return { pos: Position.FromVSCodePosition(matchRange.start), match: true };
}
}

// Wrap around
// TODO(bell)
return { pos: Position.FromVSCodePosition(this.matchRanges[0].start), match: true };
return { pos: Position.FromVSCodePosition(this._matchRanges[0].start), match: true };
} else {
for (let matchRange of this.matchRanges.slice(0).reverse()) {
for (let matchRange of this._matchRanges.slice(0).reverse()) {
if (matchRange.start.compareTo(startPosition) < 0) {
return { pos: Position.FromVSCodePosition(matchRange.start), match: true };
}
}

// TODO(bell)
return {
pos: Position.FromVSCodePosition(this.matchRanges[this.matchRanges.length - 1].start),
pos: Position.FromVSCodePosition(this._matchRanges[this._matchRanges.length - 1].start),
match: true
};
}
}

constructor(direction: number, startPosition: Position, searchString = "") {
this.searchDirection = direction;
this.searchCursorStartPosition = startPosition;
constructor(direction: SearchDirection, startPosition: Position, searchString = "") {
this._searchDirection = direction;
this._searchCursorStartPosition = startPosition;
this.searchString = searchString;
}
}
Expand Down Expand Up @@ -576,7 +589,6 @@ export class ModeHandler implements vscode.Disposable {
}

// Update view

await this.updateView(vimState);

return vimState;
Expand Down
4 changes: 4 additions & 0 deletions src/textEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export class TextEditor {
});
}

static getDocumentVersion(): number {
return vscode.window.activeTextEditor.document.version;
}

/**
* Removes all text in the entire document.
*/
Expand Down

0 comments on commit 47367f1

Please sign in to comment.