-
Notifications
You must be signed in to change notification settings - Fork 29.3k
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
Quick input reset scroll position #109969
Comments
Fixing this might be non-trivial because you set new objects and there is no way for the picker to tell if you intend this to be a new set of choices that require the scroll position to be reset or if this is a refinement of the existing choices that require the scroll position to stay the same. |
I could give you the same object again, e.g I would modify them them in-place and set the same array again |
Two simpler options:
If we were to add this to the API one day, I would prefer the second option. |
I don't think the
This would work, though I'm not sure how to control scroll... any pointers on that? With that being said, I almost feel like @jrieken wants a way to say "Hey I modified the objects in some way, please refresh them". This can be done by turning this code into (note the if/else would be factored out as it is used in another place): picker.onDidTriggerItemButton(ctx => {
const isEnabled = snippetService.isEnabled(ctx.item.snippet);
snippetService.updateEnablement(ctx.item.snippet, !isEnabled);
if (!isEnabled) {
ctx.item.description = undefined;
ctx.item.buttons = [{
iconClass: Codicon.eyeClosed.classNames,
tooltip: nls.localize('disableSnippet', 'Hide from IntelliSense')
}];
} else {
ctx.item.description = nls.localize('isDisabled', "(hidden from IntelliSense)");
ctx.item.buttons = [{
iconClass: Codicon.eye.classNames,
tooltip: nls.localize('enable.snippet', 'Show in IntelliSense')
}];
}
picker.itemActivation = 0;
picker.itemsUpdated = true;
picker.update();
}); The if/else just sets the buttons and description based on the new state. The real magic is the last 3 lines that basically force update how the items are rendered. This gives the desired effect of clicking on an ποΈ and having it change right in front of you. picker.itemActivation = 0;
picker.itemsUpdated = true;
picker.update(); None of these are public atm, but I could see a possible Thoughts? |
The assumption so far was that items would not change and that we need to read their properties only once when they are set on the picker object. That has kept the API simple. The If we wanted to support mutable items, we would need an extension-supplied event. That would in my view mix two distinct approaches in the same API.
|
@chrmarti and I talked about this... one of my fundamental misunderstandings was that a The assumption being that this API would not scroll to top as you are just replacing nodes in the list. If you want the 'scroll to top' behavior, you can set What do you think? Something like this: export interface QuickPick<T extends QuickPickItem> extends QuickInput {
// ...
splice(replacementMap: Map<T, T>): void;
// ...
} |
after talking to @jrieken, he suggested we use an What do you think @chrmarti ? |
@TylerLeonhardt Sounds good. I suggest to briefly look into the implementation before committing to it. We currently maintain object identity in the API, e.g., when the extension sets some items, it will get the same objects back as the active and selected item(s). When introducing ids, you would probably expect the new object to replace the old object with the same id in all of the API. Probably not a big task, but something to consider. |
This a good point... I guess the question is... how far should we go with this? If you have 2 items with the same id should it:
I think the "focus algorithm" could simply be... "verify the order of the ids hasn't changed at all" which means something along these lines: private shouldKeepFocus(items: Array<T | IQuickPickSeparator>): boolean {
// short circuit if their lengths are different
if (items.length !== this._items.length) {
return false;
} else {
return this._items.every((item, i) => {
const otherItem = items[i];
// verify separators are the same
if (otherItem.type === 'separator'
&& item.type === 'separator'
&& otherItem.label === item.label
) {
return true;
}
// verify items have the same id (and that that id is not undefined)
if (otherItem.type !== 'separator'
&& item.type !== 'separator'
&& otherItem.id === item.id
&& otherItem.id
) {
return true;
}
return false;
});
}
} |
Even without duplicate ids in the same items array, ids raise some questions, e.g.:
If |
do you think you can point me to where
Yes I would also expect the new object. Good point.
Yes I like this. |
This one picks up changes from the UI: https://github.com/microsoft/vscode/blob/main/src/vs/base/parts/quickinput/browser/quickInput.ts#L807 We trigger this initially by setting the focus items on the list: https://github.com/microsoft/vscode/blob/main/src/vs/base/parts/quickinput/browser/quickInput.ts#L956 |
Ah... so what I was doing is setting:
but what this does is makes it so that when you reset This is the easiest solution for this issue... however... it may not be ideal. If we want to keep activeItems to the last selection that gets trickier because when the items in the list widget get set, it appears to clear the focused state... we get around this by using To truly fix this, that would mean we need some way to say "yes, focus on the last item that was focused but reset the scroll position back to what it was before. I just sent a PR out that does this. |
We have a related use case in the Python extension where the scroll focus is lost when adding items dynamically to end of quickpick list #131457 |
related #76193 |
One way to avoid introducing ids would be to have separate functions for inserting, replacing and removing items:
|
I like these suggestions @chrmarti and I think they're the only way to give folks the flexibility they're looking for all around:
This also makes me feel a bit better since it won't be potentially breaking user that already use the property I shall take this to API sync next week. |
I have another suggestion similar to
...It's likely more natural that the consumers have the new list instead of the diff. So if we were to use Even if the consumers have the diff, it might be a different kind of diff than what the API expects. It probably easier for the user to simply prepare the new list using whatever diff they have and assign it directly. So I believe if this is just to avoid scrolling, |
@karrtikr Replacing the entire list and keeping the scroll position fixed only works well if what the user sees doesn't move. That's the case when appending items to the end or updating existing items (in a way that doesn't change their height). Other changes to the list could move the visible items and the extension has no way to find out which items are visible. The extension needs to be careful about changes to the list to preserve the scroll position, so maybe that already implies that the extension is either aware of the delta and can apply it step-by-step or it is not aware of the delta and doesn't know how to preserve the scroll position. Maybe |
@chrmarti that second signature sounds very similar to the splice up above. |
@chrmarti Good point, I agree extension has to have some idea about the delta already.
But I think this is true for both the API suggestions, and extension has to be careful about the scroll either way. What would be the advantage of editing the lists using delta rather than directly replacing it? One thing I could think of is that having a separate I like the second signature, but it seems having |
@TylerLeonhardt True and maybe a reason to avoid it initially. One difference is that the
@karrtikr Indeed, having a general solution is the goal.
@karrtikr Not when it comes to preserving the scroll position. |
@jrieken proposed something different... a
Property on quickpick. This is similar to |
I have a PR out that adds a |
verification: original issue has good steps. |
This is happening when reassigning the items (since the press changed the label) here:
vscode/src/vs/workbench/contrib/snippets/browser/insertSnippet.ts
Line 213 in 92314d6
The text was updated successfully, but these errors were encountered: