From bcaeba6e1a874ffc432291b11e1b762c3ff14b3d Mon Sep 17 00:00:00 2001 From: Aiden Scandella Date: Fri, 26 Aug 2016 11:12:26 -0700 Subject: [PATCH 1/5] Allow regex in / search --- src/actions/actions.ts | 2 +- src/mode/modeHandler.ts | 12 +++++++++--- test/mode/modeNormal.test.ts | 7 +++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/actions/actions.ts b/src/actions/actions.ts index f302790dda4..4cc9c8375c2 100644 --- a/src/actions/actions.ts +++ b/src/actions/actions.ts @@ -782,7 +782,7 @@ export class CommandSearchForwards extends BaseCommand { isMotion = true; public async exec(position: Position, vimState: VimState): Promise { - vimState.searchState = new SearchState(SearchDirection.Forward, vimState.cursorPosition); + vimState.searchState = new SearchState(SearchDirection.Forward, vimState.cursorPosition, "", true); vimState.currentMode = ModeName.SearchInProgressMode; return vimState; diff --git a/src/mode/modeHandler.ts b/src/mode/modeHandler.ts index 2aa89dd069c..476abea8c8d 100644 --- a/src/mode/modeHandler.ts +++ b/src/mode/modeHandler.ts @@ -179,6 +179,7 @@ export class SearchState { private _matchesDocVersion: number; private _searchDirection: SearchDirection = SearchDirection.Forward; + private isRegex: boolean; private _searchString = ""; public get searchString(): string { @@ -213,7 +214,11 @@ export class SearchState { ignorecase = false; } - const regex = new RegExp(search.replace(SearchState.specialCharactersRegex, "\\$&"), ignorecase ? 'gi' : 'g'); + let searchRE = search; + if (!this.isRegex) { + searchRE = search.replace(SearchState.specialCharactersRegex, "\\$&"); + } + const regex = new RegExp(searchRE, ignorecase ? 'gi' : 'g'); outer: for (let lineIdx = 0; lineIdx < TextEditor.getLineCount(); lineIdx++) { @@ -227,7 +232,7 @@ export class SearchState { this.matchRanges.push(new vscode.Range( new Position(lineIdx, result.index), - new Position(lineIdx, result.index + search.length) + new Position(lineIdx, result.index + result[0].length) )); if (result.index === regex.lastIndex) { @@ -280,10 +285,11 @@ export class SearchState { } } - constructor(direction: SearchDirection, startPosition: Position, searchString = "") { + constructor(direction: SearchDirection, startPosition: Position, searchString = "", isRegex = false) { this._searchDirection = direction; this._searchCursorStartPosition = startPosition; this.searchString = searchString; + this.isRegex = isRegex; } } diff --git a/test/mode/modeNormal.test.ts b/test/mode/modeNormal.test.ts index 25a73818967..ba70f64611a 100644 --- a/test/mode/modeNormal.test.ts +++ b/test/mode/modeNormal.test.ts @@ -1191,6 +1191,13 @@ suite("Mode Normal", () => { end: ["|one", "twooo", "thurr"] }); + newTest({ + title: "/ can search with regex", + start: ["|", "one two"], + keysPressed: "/o.*o", + end: ["", "|one two"] + }); + newTest({ title: "Can do C", start: ["export const options = {", "|", "};"], From 4caac227f9222f9a46b45d5352a56bd67fab9632 Mon Sep 17 00:00:00 2001 From: Aiden Scandella Date: Fri, 26 Aug 2016 13:39:05 -0700 Subject: [PATCH 2/5] Handle invalid regexen --- src/mode/modeHandler.ts | 12 +++++++++++- test/mode/modeNormal.test.ts | 6 +++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mode/modeHandler.ts b/src/mode/modeHandler.ts index 476abea8c8d..5912abe5bd0 100644 --- a/src/mode/modeHandler.ts +++ b/src/mode/modeHandler.ts @@ -218,7 +218,17 @@ export class SearchState { if (!this.isRegex) { searchRE = search.replace(SearchState.specialCharactersRegex, "\\$&"); } - const regex = new RegExp(searchRE, ignorecase ? 'gi' : 'g'); + + const regexFlags = ignorecase ? 'gi' : 'g'; + + let regex: RegExp; + try { + regex = new RegExp(searchRE, regexFlags); + } catch (err) { + // Couldn't compile the regexp, try again with special characters escaped + searchRE = search.replace(SearchState.specialCharactersRegex, "\\$&"); + regex = new RegExp(searchRE, regexFlags); + } outer: for (let lineIdx = 0; lineIdx < TextEditor.getLineCount(); lineIdx++) { diff --git a/test/mode/modeNormal.test.ts b/test/mode/modeNormal.test.ts index ba70f64611a..b0f07527326 100644 --- a/test/mode/modeNormal.test.ts +++ b/test/mode/modeNormal.test.ts @@ -1193,9 +1193,9 @@ suite("Mode Normal", () => { newTest({ title: "/ can search with regex", - start: ["|", "one two"], - keysPressed: "/o.*o", - end: ["", "|one two"] + start: ["|", "one two2o"], + keysPressed: "/o\do", + end: ["", "one tw|o2o"] }); newTest({ From 273c64ac9103587bd5ca07a5e8756d903605054b Mon Sep 17 00:00:00 2001 From: Aiden Scandella Date: Fri, 26 Aug 2016 13:44:29 -0700 Subject: [PATCH 3/5] Update constructor --- src/actions/actions.ts | 2 +- src/mode/modeHandler.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/actions/actions.ts b/src/actions/actions.ts index 4cc9c8375c2..155572ee339 100644 --- a/src/actions/actions.ts +++ b/src/actions/actions.ts @@ -782,7 +782,7 @@ export class CommandSearchForwards extends BaseCommand { isMotion = true; public async exec(position: Position, vimState: VimState): Promise { - vimState.searchState = new SearchState(SearchDirection.Forward, vimState.cursorPosition, "", true); + vimState.searchState = new SearchState(SearchDirection.Forward, vimState.cursorPosition, "", { isRegex: true }); vimState.currentMode = ModeName.SearchInProgressMode; return vimState; diff --git a/src/mode/modeHandler.ts b/src/mode/modeHandler.ts index 5912abe5bd0..0a8a12b9d79 100644 --- a/src/mode/modeHandler.ts +++ b/src/mode/modeHandler.ts @@ -295,7 +295,7 @@ export class SearchState { } } - constructor(direction: SearchDirection, startPosition: Position, searchString = "", isRegex = false) { + constructor(direction: SearchDirection, startPosition: Position, searchString = "", { isRegex = false } = {}) { this._searchDirection = direction; this._searchCursorStartPosition = startPosition; this.searchString = searchString; From 8f7a868bc064781f60430234f5faefbbdce7e172 Mon Sep 17 00:00:00 2001 From: Aiden Scandella Date: Fri, 26 Aug 2016 16:29:16 -0700 Subject: [PATCH 4/5] Escape backslash --- test/mode/modeNormal.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mode/modeNormal.test.ts b/test/mode/modeNormal.test.ts index b0f07527326..c0cc26c582c 100644 --- a/test/mode/modeNormal.test.ts +++ b/test/mode/modeNormal.test.ts @@ -1194,7 +1194,7 @@ suite("Mode Normal", () => { newTest({ title: "/ can search with regex", start: ["|", "one two2o"], - keysPressed: "/o\do", + keysPressed: "/o\\do", end: ["", "one tw|o2o"] }); From 3c581decb8022c9702ae5abb6d0951b0c1393b7c Mon Sep 17 00:00:00 2001 From: Aiden Scandella Date: Fri, 26 Aug 2016 19:50:10 -0700 Subject: [PATCH 5/5] Also support backwards search --- src/actions/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/actions.ts b/src/actions/actions.ts index 155572ee339..683dd5dc552 100644 --- a/src/actions/actions.ts +++ b/src/actions/actions.ts @@ -796,7 +796,7 @@ export class CommandSearchBackwards extends BaseCommand { isMotion = true; public async exec(position: Position, vimState: VimState): Promise { - vimState.searchState = new SearchState(SearchDirection.Backward, vimState.cursorPosition); + vimState.searchState = new SearchState(SearchDirection.Backward, vimState.cursorPosition, "", { isRegex: true }); vimState.currentMode = ModeName.SearchInProgressMode; return vimState;