Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1575: Adds support for searching for strings with newlines #1603

Merged
merged 9 commits into from
Apr 30, 2017

Conversation

Chillee
Copy link
Member

@Chillee Chillee commented Apr 29, 2017

Basically, the general approach is that we count how many newlines there are in their search string, and expand our search beyond line by line accordingly.

Thus, if their string contains two newline characters, then we check two lines at a time, and so on.

Accordingly, if there are no newline characters, this shouldn't affect performance at all, and performance should then degrade linearly with the amount of newlines (which makes sense).

One thing that it's missing is that Vscode doesn't seem to support highlighting the "newline" character. That makes newlines pretty invisible.

I've also added a test.

PS: You'll notice the commit that made the command line persistent, PR #1601. I accidentally checked it out and don't know how to delete a commit in the past, so I simply reverted it and then squashed the commit. I hope that's not an issue if both PR's are merged...

Copy link
Member

@johnfn johnfn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of small changes. My biggest concern is how this does perf-wise in really large files. e.g. how does a search for a\n\n\n work in actions.ts?

If that's still nice and snappy, we should be good to go here.

// Start at the current line and wrap the document if we hit the end.
outer:
do {
const line = TextEditor.getLineAt(new Position(lineIdx, 0)).text;
let rangeStart = new Position(lineIdx, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor I know, but can we have a convention of using const when the variable doesn't change?

let rangeStart = new Position(lineIdx, 0);
let rangeEnd = rangeStart.getLineEnd();
let lineLengths = [];
for (var i = 0; i < numNewLines; i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

..and let when it does?

let result = regex.exec(line);

while (result) {
if (this._matchRanges.length >= SearchState.MAX_SEARCH_RANGES) {
break outer;
}
let resultToPosition = function(resultIdx: number, lineIdx: number, lineLengths: Array<number>, result: RegExpExecArray){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a further style suggestion, it's good to prefer => over function in the general case.

@@ -92,20 +92,38 @@ export class SearchState {

let lineIdx = lineToStartAt;

let numNewLines = (searchRE.match(/\\n/g) || []).length;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regex-ception

let result = regex.exec(line);

while (result) {
if (this._matchRanges.length >= SearchState.MAX_SEARCH_RANGES) {
break outer;
}
let resultToPosition = function(resultIdx: number, lineIdx: number, lineLengths: Array<number>, result: RegExpExecArray){
let cur = resultIdx;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we have a slightly better name than cur, like positionInAggregateLines or something?

@Chillee
Copy link
Member Author

Chillee commented Apr 29, 2017

So there is a definitely a noticeable delay. I'll try to work on the performance.

Just wondering, is it a bad idea to load the entire file into one string?

Also, would it be viable to find search results as needed? As in, only find the results on the screen, and find more as necessary?

Actually, looking around, I think it may be worth trying to utilize vscode's default find functionality. They seem to have already ran into this issue and fixed it.

microsoft/vscode#313

Their solution seems kind of similar to the one I was planning on implementing, but they have the benefit of having direct access to the text model.

@Chillee
Copy link
Member Author

Chillee commented Apr 29, 2017

Alright, so I implemented a different model that searches the whole text instead of line by line. This is way faster (there's pretty much no drop in speed so far as I can tell, with an arbitrarily high number of newlines).

@Chillee
Copy link
Member Author

Chillee commented Apr 29, 2017

Alright. I think the current PR is in a mergeable state. The performance is very good, and I've ironed out all the other miscellaneous bugs.

I think the failing test is just the test server screwing up. The previous commit passed all tests (only failed due to linting issue), and the final commit shouldn't have changed anything related to that.

@johnfn johnfn merged commit cf49603 into VSCodeVim:master Apr 30, 2017
@Chillee Chillee changed the title Fixes #1575 (and also adds general newline support for searches) Fixes #1575: Adds support for searching for strings with newlines May 2, 2017
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants