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

Fix search addons: Fix problem of skipping some results and incorrect text selection after resize window #1866

Merged
merged 17 commits into from
Apr 10, 2019

Conversation

ntchjb
Copy link
Contributor

@ntchjb ntchjb commented Dec 29, 2018

When function _findInLine is run in reverse mode (find previous), it skipped the results that is wrapped, and also skipped the line that has isWrapped === true although there are other results in the line. When resizing the window and search again, it highlights incorrect position.

So, for skipping wrapped result problem, I added a condition to check whether start column index is in the range or not. If not, then lastIndexOf function should begin matching at the end of the string.

For skipping wrapped line, I think the part of code inside _findInLine that did a return when found properties isWrapped === true can be removed because we should also scan other results in wrapped line.

For resizing window, I saw that the value at this._terminal._core.buffer.lines.get(y).length didn't change when the window was resized, but for this._terminal.cols, the value is changed, so I decided to use this._terminal.cols to match with searching range.

ntchjb and others added 2 commits December 29, 2018 09:38
- Changed to use `this._terminal.cols` for buffer line length instead.
- Let `_findInLine` check on wrapped line
- Added conditions in `_findInLine`
  - For reverse search, if there is no  selection at given row, then start scan at the end of the string
@@ -187,9 +187,6 @@ export class SearchHelper implements ISearchHelper {
* @return The search result if it was found.
*/
protected _findInLine(term: string, row: number, col: number, searchOptions: ISearchOptions = {}, isReverseSearch: boolean = false): ISearchResult {
if (this._terminal._core.buffer.lines.get(row).isWrapped) {
Copy link
Member

Choose a reason for hiding this comment

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

Testing ti locally on master and your branch it doesn't seem to work on either? 😕

The idea behind this isWrapped check is to ignore all rows flagged as wrapped and only take the first row (which always has isWrapped = false

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh sorry, I misunderstand the idea. I will put back the return block and try to fix else where. The problem is that if the wrapped line has multiple matches, the search result will highlight only one result and skipped others then go to next line.

by managing column range that is needed to be scanned.
@ntchjb
Copy link
Contributor Author

ntchjb commented Dec 29, 2018

I fixed the problem by controlling index of col before passing to _findInLine. When the function scans on unwrapped line, it should have the value of col high enough so that the function can scan through all wrapped lines below the unwrapped line.

- Convert buffer index to string index before searching
- Convert string index to buffer index after searching
- Fix bug when search selection skipped some result
@ntchjb
Copy link
Contributor Author

ntchjb commented Jan 1, 2019

For the latest commit, I try to modify searching function to support wide characters and combined characters by mapping between buffer index and string index. I'm not sure if stringIndexToBufferIndex and bufferIndexToStringIndex method should be moved to Buffer.ts or not. For stringIndexToBufferIndex method, it is different from the original in Buffer.ts that the method also counts empty cells as whitespace. So that for the following test case:

term.core.write('Hello World\r\ntest\n123....hello');
const hello2 = term.searchHelper.findInLine('Hello', 2);

return the result as {col: 11, row: 2, term: 'Hello'}.

I'm not sure why \n in write function results in several empty cells before 123....hello string.

@ntchjb
Copy link
Contributor Author

ntchjb commented Jan 1, 2019

This PR might relate to #1686 and #1801

Edit: A PR may be created separately for wide characters support feature.

@Tyriar
Copy link
Member

Tyriar commented Jan 2, 2019

For the latest commit, I try to modify searching function to support wide characters and combined characters by mapping between buffer index and string index.

It might be better to revert the latest commit and do that in another one as this was so close. I'm happy to merge if we revert that, provided that "- Fix bug when search selection skipped some result" in the latest commit message is not something we need to worry about?

Also on the actual solution, that's way too much code to copy over to the addon as it will quickly get out of sync.

I'm not sure why \n in write function results in several empty cells before 123....hello string.

That's happening because you did \n which moves the cursor to the following line, but you missed the \r which moves the cursor to the start of the line.

@ntchjb
Copy link
Contributor Author

ntchjb commented Jan 3, 2019

OK, I reverted the latest commit to the previous commit. However, at the latest commit, there is a fix that relates to the previous commit, so I make an additional commit to complete the fix.

@Tyriar Tyriar added this to the 3.11.0 milestone Jan 8, 2019
for (let y = 0; y <= startRow; y++) {
result = this._findInLine(term, y, 0, searchOptions);
result = this._findInLine(term, findingRow, cumulativeCols, searchOptions);
Copy link
Member

Choose a reason for hiding this comment

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

It looks like this change is grabbing the cumulativeCols and calling _findInLine multiple times for a single wrapped row. This kind of goes against the design and _findInLines is meant to get the full unwrapped line and search it fully. I think the actual root cause is somewhere inside _findInLine and calling it multiple times on the same row is getting around it.

After this section searchStringLine is meant to contain the full wrapped line so we can search it in full:

if (this._terminal._core.buffer.lines.get(row).isWrapped) {
return;
}
let stringLine = this._linesCache ? this._linesCache[row] : void 0;
if (stringLine === void 0) {
stringLine = this.translateBufferLineToStringWithWrap(row, true);
if (this._linesCache) {
this._linesCache[row] = stringLine;
}
}
const searchTerm = searchOptions.caseSensitive ? term : term.toLowerCase();
const searchStringLine = searchOptions.caseSensitive ? stringLine : stringLine.toLowerCase();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, you were right. _findInLine should return the result at the first time, otherwise, go to the next unwrapped line.

@ntchjb
Copy link
Contributor Author

ntchjb commented Jan 9, 2019

I reverted fineNext mechanism to the old one, firstly, scan for the first unwrapped line and run _findInLine. If the result not found, then scan for the next unwrapped line and run _findInLine. If the result still not found, then try to scan from the first unwrapped row in the buffer.

@Tyriar Tyriar modified the milestones: 3.11.0, 3.12.0 Feb 1, 2019
@Tyriar Tyriar modified the milestones: 3.12.0, 3.13.0 Mar 8, 2019
Copy link
Member

@Tyriar Tyriar left a comment

Choose a reason for hiding this comment

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

I just tried testing this again and it still seems broken, to test I'm typing a bunch of characters and then trying to find previous a term on a wrapped line:

image

The circled "df" doesn't get found though.

@ntchjb
Copy link
Contributor Author

ntchjb commented Mar 15, 2019

I'm sorry, but I couldn't reproduce the problem. I tested in demo server using yarn start. The search results found df keywords in both forward and backward which covers all matching words. Here is my snapshot.
Screen Shot 2562-03-15 at 17 49 52

I used column with width cols 87 and rows 26. Here is the text results

bash-3.2$ echo '
> lkmasdjasdfknajlsdlnkafdslnkasdflnjalsdfnkjdasfnlkjadsfnljksdajklsadfllfsdakafdsfadsnlkadf
> '

lkmasdjasdfknajlsdlnkafdslnkasdflnjalsdfnkjdasfnlkjadsfnljksdajklsadfllfsdakafdsfadsnlkadf

bash-3.2$ 

df words has been found 10 times in total.

I run the demo server on macOS 10.14 with Google Chrome 72

@ntchjb
Copy link
Contributor Author

ntchjb commented Mar 15, 2019

If you mean that, after typed a bunch of the string and ran findPrevious search without any selection at the first time, and it didn't select matching string at the end of the first line, then, I changed the code in findPrevious to start scanning at the last row first if there is no text selection.

Copy link
Member

@Tyriar Tyriar left a comment

Choose a reason for hiding this comment

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

Thanks, seems to work great now! I fixed a minor issue which started findPrevious at the top of the buffer rather than where the viewport was.

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.

None yet

2 participants