-
Notifications
You must be signed in to change notification settings - Fork 35.9k
Generalize Ctrl+DownArrow and Ctrl+UpArrow to most input-result widgets (Fix #179967) #187077
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
Conversation
b68e8ca to
5d64ccf
Compare
|
Hey @hsfzxjy thanks so much for working on this. Something to consider - not sure if you have already thought of this - is are there pre-existing applications of this keybinding for each of the contexts? IE in these views, does for example, I adopted such a change in the search view - but did not realize that I broke muscle memory a bit since ctrl/cmd+downArrow when in the search in put box with multiline text should jump to the bottom of that, but currently instead jumps to the next input box. |
|
@meganrogge Yes, I've investigated on this and ensure not breaking muscle memory. The hardest part is that those Lists/Tables/Trees in the "results panel" by default use Ctrl+Up for scrolling up, which could conflict with the newly added action of focusing "input widget". I harmonize these two into:
Here's a list of behavior that this PR affects: Extensions Extension List Keybinding Editor Keybinding Table MarkerView View Body CommentsView Tree CommentsView REPL Input |
|
Amazing 🙌 thank you. I'll review this next week. |
5664660 to
79caf94
Compare
|
@meganrogge I see you are reviewing this PR. Is there anything you would need from me? |
679b20b to
7f73b97
Compare
|
@sandy081 a look at your particular area(s) would be good. Thanks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commentsView.ts and commentsView.test.ts look good!
|
@roblourens could you pls make sure it looks good for your area? |
| function createScrollAtTopObserver(contextKeyService: IContextKeyService, widget: WorkbenchListWidget): IDisposable { | ||
| const listScrollAtTop = RawWorkbenchListScrollAtTopContextKey.bindTo(contextKeyService); | ||
| listScrollAtTop.set(widget.scrollTop === 0); | ||
| return widget.onDidScroll((e) => { | ||
| const shouldUpdate = (e.oldScrollTop === 0) !== (e.scrollTop === 0); | ||
| if (shouldUpdate) { | ||
| listScrollAtTop.set(e.scrollTop === 0); | ||
| } | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK there is no need to check for should update since that's taken care of further down the line.
| function createScrollAtTopObserver(contextKeyService: IContextKeyService, widget: WorkbenchListWidget): IDisposable { | |
| const listScrollAtTop = RawWorkbenchListScrollAtTopContextKey.bindTo(contextKeyService); | |
| listScrollAtTop.set(widget.scrollTop === 0); | |
| return widget.onDidScroll((e) => { | |
| const shouldUpdate = (e.oldScrollTop === 0) !== (e.scrollTop === 0); | |
| if (shouldUpdate) { | |
| listScrollAtTop.set(e.scrollTop === 0); | |
| } | |
| }); | |
| } | |
| function createScrollAtTopObserver(contextKeyService: IContextKeyService, widget: WorkbenchListWidget): IDisposable { | |
| const listScrollAtTop = RawWorkbenchListScrollAtTopContextKey.bindTo(contextKeyService); | |
| const update = () => listScrollAtTop.set(widget.scrollTop === 0); | |
| update(); | |
| return widget.onDidScroll(update); | |
| } |
| private readonly _onDidBlur = this._register(new EventMultiplexer<void>()); | ||
| readonly onDidBlur = this._onDidBlur.event; | ||
| private readonly _onDidFocus = this._register(new EventMultiplexer<void>()); | ||
| readonly onDidFocus = this._onDidFocus.event; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of allocating additional objects, these two events should just be the same instances as the focusTracker's events. One suggestion: createInput could return the focusTracker instance along with the ContextScopedHistoryInputBox instance, then the events could simply be assigned in the constructor.
| this._register(this._onDidFocusResults.add(focusTracker.onDidFocus)); | ||
| this._register(this._onDidBlurResults.add(focusTracker.onDidBlur)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is trickier to untangle, but should still be possible to do without any additional allocations. Let me know if you need pointers for that.
| this._register(this._onDidFocusResults.add(this.replInput.onDidFocusEditorWidget)); | ||
| this._register(this._onDidBlurResults.add(this.replInput.onDidBlurEditorWidget)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same allocation comment as above.
| register(view: IInputResultsView): IDisposable; | ||
| } | ||
|
|
||
| export class InputResultsService implements IInputResultsService { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is such a strange thing to become a service. First, I don't think we've ever defined such a concept as an input-result widget. But let's say we do... still, we don't have a class to encapsulate that widget's definition and behavior. We seem to be creating an abstract concept of a widget without creating the widget itself. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I made it as a service so that we can define a unified command to make the navigation keybinding consistent across several widgets. Do you find it necessary to define unified commands for these navigation? If so, what's the better way for this?
Also after reading other comments you left, I agree that the term input-results is poorly defined and too constrained. For example in repl, it's hard to say which one of the filter box and the input box is the "input". Thus I feel like to rewrite this PR and extend it to more general cases -- use Ctrl+Up/Down to navigate among widgets in a vertical-layout container like the search panel did. This should come with the following advantages:
- No more confusion of "input" vs "results"
- Can be applied to container with more than two child widgets, instead of simple "input" and "results".
I am wondering what's your attitude to this proposal? Many thanks to your kind instructions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you find it necessary to define unified commands for these navigation? If so, what's the better way for this?
We have what's called a MultiCommand - for example
vscode/src/vs/workbench/contrib/accessibility/browser/accessibilityContribution.ts
Lines 71 to 88 in c780d0d
| export const AccessibilityHelpAction = registerCommand(new MultiCommand({ | |
| id: 'editor.action.accessibilityHelp', | |
| precondition: undefined, | |
| kbOpts: { | |
| primary: KeyMod.Alt | KeyCode.F1, | |
| weight: KeybindingWeight.WorkbenchContrib, | |
| linux: { | |
| primary: KeyMod.Alt | KeyMod.Shift | KeyCode.F1, | |
| secondary: [KeyMod.Alt | KeyCode.F1] | |
| } | |
| }, | |
| menuOpts: [{ | |
| menuId: MenuId.CommandPalette, | |
| group: '', | |
| title: localize('editor.action.accessibilityHelp', "Open Accessibility Help"), | |
| order: 1 | |
| }], | |
| })); |
Your approach above sounds good to me, though I believe would still use the service concept?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have what's called a
MultiCommand
Thanks for pointing out, never know this before.
I am actually rewriting this PR to realize general widget navigation in a container using Ctrl+Up/Down. With MultiCommand I think the service concept can be eliminated. But the time complexity of executing action may increase since there could be many containers attached to the action. Is it acceptable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that sounds good. Thanks so much for working on this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@meganrogge I have another idea to eliminate service, which I'm not sure is appropriate or not. I've put the pseudo code at https://gist.github.com/hsfzxjy/5beae21297024f443c2d69faffc4cfe5 . Could you check it and see whether this pattern is OK or why it's not acceptable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That LGTM
| private readonly _onDidBlurResults = this._register(new EventMultiplexer<void>()); | ||
| private readonly _onDidFocusResults = this._register(new EventMultiplexer<void>()); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same allocation comment.
|
I've completed a full rewrite on this PR in respond to @roblourens 's constructive suggestions. The changes at present are:
@meganrogge I think we should start a new review? Sorry about the occupation of your precious time. Thanks! 🙏🏼 |
|
@hsfzxjy thank you so much for your continued work on this. based on my testing, things are working very well 🎉 I'm seeing this error though: EDIT: |
|
@meganrogge Saw this. I am troubleshooting it. |
|
The error is gone now. It was caused by an overly aggressive tree-shaking. |
|
@joaomoreno if you want to give this another pass, I plan to test and approve today if all works well |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏🏼
Fix #179967.
This adds Ctrl+UpArrow and Ctrl+DownArrow navigation to
The two keybindings are uniformly controlled by two new commands
inputResults.focusResultsandinputResults.focusInput.