Improved Find/Replace UI#6175
Conversation
…ut not yet picking up any of the enhanced functionality from Find)
result highlighting, tickmarks, result count, etc. They are still separate commands for now, with Find having a simpler UI.
* Treat Enter as Find Next instead of closing the bar. Removes Enter key handling and "commit" event from ModalBar. * Move error message into popup & clean up how its shown/hidden. Make text field border red whenever error is shown. Same for FindInFiles, as well. * Remove redundant "Skip" button in Replace UI * Make next/prev and Replace/All button pairs flush * Move result-count label inside search field * Fix all existing unit tests (removing some that are no longer applicable with the new Enter key behavior).
…d of deciding based on heuristics. (NOT changed in Find in Files yet, though) * Change Find Next to use editor cursor pos rather than an invisible saved pos (part of future story "Correct Find Next behavior", but also simplifies code). With simple unit test. * Make all Find/Replace buttons non-tabbable for now, to match existing next/prev buttons * Move Find in Files "no results" message back into search bar (as opposed to drop-down error popup) * Hide regexp error popup when sliding out Find in Files bar, just as we do for Find/Replace * Fix existing bug in Find in Files where prepopulated regexp text was not checked for errors
* Persist regex/case toggle state as a pref (shared across Find, Replace & Find in Files) * Unit tests for new Sprint 35 find/replace features * Replace keyboard shortcut acts like clicking the Replace button while search bar is open * Show keyboard shortcuts in search bar tooltips * UI polish: make regex/case option snug with search field; make replace buttons snug with replace field; don't overlap borders of snug buttons (caused border to appear darker when disabled due to alpha)
There was a problem hiding this comment.
It might be a good time to join this template with the Find in Files ones and use Mustache to decide what to display or not, since both have several similar parts and will have more once we have more Find in Files features. At the moment it could be done like:
<div class="search-input-container">
<input type="text" id="find-what" value="{{value}}" placeholder="{{Strings.CMD_FIND}}" />
<div class="error"></div>
<span id="find-counter"></span>
</div>
<button id="find-case-sensitive" class="btn no-focus" tabindex="-1" title="{{Strings.BUTTON_CASESENSITIVE_HINT}}"><div class="button-icon"></div></button>
<button id="find-regexp" class="btn no-focus" tabindex="-1" title="{{Strings.BUTTON_REGEXP_HINT}}"><div class="button-icon"></div></button>
{{#hasPrevNext}}
<div class="navigator">
<button id="find-prev" class="btn no-focus" tabindex="-1" title="{{Strings.BUTTON_PREV_HINT}}">{{Strings.BUTTON_PREV}}</button>
<button id="find-next" class="btn no-focus" tabindex="-1" title="{{Strings.BUTTON_NEXT_HINT}}">{{Strings.BUTTON_NEXT}}</button>
</div>
{{/hasPrevNext}}
{{#hasReplace}}
<input type="text" id="replace-with" placeholder="{{Strings.REPLACE_PLACEHOLDER}}"/>
<button id="replace-yes" class="btn no-focus" tabindex="-1">{{Strings.BUTTON_REPLACE}}</button>
<button id="replace-all" class="btn no-focus" tabindex="-1">{{Strings.BUTTON_REPLACE_ALL}}</button>
{{/hasReplace}}
<div class="no-results-message">{{FIND_NO_RESULTS}}</div></div>
{{#label}}
<div class="message">
<span id="searchlabel">{{{label}}}</span>
</div>
{{/label}}
And then Create the template with:
Mustache.render(searchDialogTemplate, {
value : initialQuery || "",
label : "", // Will have a value in Find in Files
hasPrevNext : true, // False for Find in Files
hasReplace : false, // True for Replace
Strings : Strings
});
There was a problem hiding this comment.
2nd that. Much prefer to have HTML code in a template file
There was a problem hiding this comment.
I've combined the Find & Replace HTML fully, and I'll move it into an external file, but I'd like to keep this separate from the Find in Files UI for now because I expect they will diverge further over time (e.g. Find in Files will have additional options for choosing the set of files, etc.) and it's not clear yet how much would be shared.
There was a problem hiding this comment.
Unfortunately this template is pretty ugly because horizontal (inline/inline-block layouts are extremely sensitive to whitespace). So it either has to be minified, or have every line start/end with a comment...
There was a problem hiding this comment.
Sure. Makes sense to keep them separate. Maybe we could use partials to reuse the parts that dont change between both templates. Like the input and buttons.
|
Q: Is it's necessary to update the Copyright notes for FindReplace, FindInFiles ... to 2013? |
|
@couzteau For existing files we don't need to increment the copyright year. Only newly-created files need the latest year. |
There was a problem hiding this comment.
Will FindReplace and FindInFiles be merged later? wondering wether a e method such as updatePrefsFromSearchBar should live in a module such as FindUtils, I suppose there are more candidates for such refactoring, ie handleQueryChange
There was a problem hiding this comment.
See my note above. I don't expect they'll ever be fully combined because there are just too many differences. But they could certainly share more code in the future than they do today. I think that's probably out of scope for this story, though.
There was a problem hiding this comment.
It will still be nice to move this new functions to a new utils file and refactor more code on later PRs.
There was a problem hiding this comment.
There's so much churn coming in this code with the overall Find epic, that I'd like to to try to clean it up too heavily right away. Let's let the dust start settling a tiny bit more and then see what the common patterns are.
There was a problem hiding this comment.
Sure. I was thinking that we could later try to join the Find Modal Bars objects in one, with most of the regexp stuff there and then just extend them in Find in Files or Find when is required. I think that this is where most of the stuff is shared at the moment. New things might come up with the next features.
|
I love the side effect of being able to use find replace as interactive regex tester! |
There was a problem hiding this comment.
Has there been an API change in CodeMirror? Wondering because the new implementation does not return anything to cm.operation anymore
There was a problem hiding this comment.
On master this line is the same: we don't return a value to cm.operation(). Afaik operation() has never expected or used any return values.
You might be thinking of the return found; line that's removed below -- which is outside the operation() call, returning from findNext() overall. I removed that as a cleanup because this is now recorded in state.lastMatch.
There was a problem hiding this comment.
got it. The diff is difficult to read.
|
Done with initial review. |
* Move Find/Replace UI into a template (must use a hack to hide linebreaks from the browser though, since whitespace changes the spacing between neighboring inline elements). * Force Tab/Shift+Tab to cycle between the two fields in Replace bar, instead of closing it. Tab behavior unchanged (vs. master) in Find & Find in Files bars. * If Replace bar wraps due to very narrow window, break only at the gap between the Find UI & Replace UI.
|
@couzteau Changes pushed. The only thing I haven't addressed yet is Raymond's comment about switching directly between the Find/Replace & Find in Files bars with the keyboard. I have a fix for that but since it's a little hacky I'd like to test it locally a bit more first before pushing it up. |
There was a problem hiding this comment.
Instead of having to pad with an empty html comment, you can achieve the same layout by just moving down > from the prior end tag as in the following example.
<div class="search-input-container"><input type="text" id="find-what" value="{{value}}" /><div class="error"></div
><button id='find-case-sensitive' class='btn no-focus' tabindex='-1' title='{{BUTTON_CASESENSITIVE_HINT}}'><div class='button-icon'></div></button>
There was a problem hiding this comment.
That might be even harder to read than the comment hack though... anyone else have an opinion or idea for a good way to get around this?
There was a problem hiding this comment.
Idea is to remove the gaps between inline elements, correct? Have you tried using a flex box layout in the dialog? I think it can also be done if you put float:left or display:inline-block on everything.
There was a problem hiding this comment.
Felxbox will work great if we want the input fields take the whole left over space split in an equal way. The same way we used it for the Find in Files and Replace tiles in the bottom panel.
same time for an instant (one sliding in while the other sliding out). Since more of the UI uses overlapping names now, that causes more problems than in the past. Ideally, ModalBar would enforce that only one is open at a time, but the close() options are too tightly controlled by the clients right now (especially QuickOpen). So we use a side channel to ensure that the two modal bars that now conflict directly (FindReplace, FindInFiles) don't overlap. Also, small cleanups: use double quotes in HTML templates; use underscores for FindReplace APIs intended to be called only by FindInFiles.
|
@couzteau Changes pushed to address @RaymondLim's double-quotes comment and the bug he found on Fri related to switching between Find in Files and Find/Replace. |
|
Looks good now. Merging. |
Not done yet, but pushed in case anyone else (@larz0?) wants to play with it.
Finished so far:
Not implemented yet:
Things to test: