-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
Eagerly preview files in quickopen widgets #13909
Conversation
Hi @wprater, I'm your friendly neighborhood Microsoft Pull Request Bot (You can call me MSBOT). Thanks for your contribution! TTYL, MSBOT; |
@wprater, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR. |
per my comment #8939 (comment) I would l prefer we closed a newly opened preview editor upon a cancellation request. please review and let me know what you think. |
e7ed1c6 adds support for openSymbolHandler. however, while the previews are occurring, the lines are not being selected. edit: fixed. was clobbering the |
1bf54e9
to
da200f3
Compare
@@ -267,4 +267,4 @@ export class AllEditorsPicker extends BaseEditorPicker { | |||
|
|||
return super.getAutoFocus(searchValue); | |||
} | |||
} |
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.
@bpasero sorry about the newlines. I can rebase them out. should we add "files.insertFinalNewline": false
to workspace settings or .editorconfig
?
@wprater the "active editor" is not enough to check, you need to check for any opened editor that is a preview editor inside a group. See https://github.com/Microsoft/vscode/blob/master/src/vs/workbench/common/editor.ts#L814 One thing I just realized is that we need to introduce a new editor option to force it to open as preview because if a user has preview disabled ( |
thanks for the tip ;) I'll look into this today. |
be7b5d9
to
0618752
Compare
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.
IEditorGroupService.getStacksModel() gives you complete access about what is going on in the editor stacks world (1 stack contains 3 groups side by side of N editor tabs). I think the best is to just store the current preview editor before doing the magic and then restore either the previous one on cancel or close the opened one if there was no preview editor before.
@bpasero per your comment above, I have some pseudo code to discover any previous preview editors so I can close any new ones. However, Im not certain the best way to get access to editorGroupService
from within quickopencontroller. Thoughts?
// Determine if there was a preview editor already open
this.previousPreviewEditorInput = null;
// how to get the activeGroup?
const activeGroup = this.historyService.editorGroupService.getStacksModel().activeGroup;
const visiblePreviewEditors = activeGroup.editors.filter((input: EditorInput) => {
return activeGroup.isPreview(input);
});
if (visiblePreviewEditors.length) {
this.previousPreviewEditorInput = visiblePreviewEditors[0].input;
}
the best I have so far is to add getStacksModel(): IEditorStacksModel
to the IEditorPart
IWorkbenchEditorService
interfaces, so I can get the stacks model from the editorService
.
} | ||
|
||
return false; | ||
return super.run(mode, context); |
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.
I moved all this out per 0618752
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.
having it in EditorQuickOpenEntry
allows us to keep this eager preview and open logic in one place for all the other quick open widgets (not sure of nomenclature here), with the exception of EditorPickerEntry
. It extends on QuickOpenEntryGroup
.
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.
@wprater EditorQuickOpenEntry
has some behaviour that we do not want in EditorPickerEntry
(e.g. opening to the side) but we do want the preview especially in the EditorPickerEntry
as well. I fear for now we have to duplicate this if it is not too much code...
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.
got it.
if (this.input instanceof EditorInput) { | ||
this.editorService.openEditor(this.input, { pinned }, sideBySide).done(null, errors.onUnexpectedError); | ||
} else { | ||
this.editorService.openEditor({ resource: (this.input as IResourceInput).resource, options: { pinned: true } }, sideBySide); |
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.
can you tell me why pinned
was forced to true
for a IResourceInput
here?
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.
@wprater thanks, a bad bug that I introduced and will push a fix to master. it should be { pinned }
as the other one.
const pinned = !this.previewEditors || (options && (options.pinned || typeof options.index === 'number')) || input.isDirty(); | ||
let pinned = !this.previewEditors || (options && (options.pinned || typeof options.index === 'number')) || input.isDirty(); | ||
if (this.previewEditors) { | ||
pinned = !this.configurationService.getConfiguration<IWorkbenchEditorConfiguration>().workbench.editor.enablePreviewFromQuickOpen; |
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.
using the config service here vs. EditorHistoryEntry
. I may have preferred to put the config service call in the getOptions
of EditorQuickOpenEntry
, but there is no configurationService directly available there.
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.
@wprater you can use most service from most classes by just adding it to the constructor as I was showing it for quickOpenController
. We use constructor service injection and you typically do not have to deal with it.
I am not yet sure how we can get this working without introducing a new editor option forcePreview
(or something like that) to open editors non-pinned when navigating in quick open.
I see your idea with using enablePreviewFromQuickOpen
setting but I think this is different: it controls if a file opened from quick open shows up pinned or as preview. In our case we always want preview no matter what this setting does.
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.
@wprater you can use most service from most classes by just adding it to the constructor as I was showing it for quickOpenController. We use constructor service injection and you typically do not have to deal with it.
good to know. in this case, I have to explicitly pass it down to the EditorQuickOpenEntry
during the super call for all the abstract classes that extend it. not really a good approach.
I would rather put all this stuff in the abstract classes getOptions
.
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.
I see your idea with using enablePreviewFromQuickOpen setting but I think this is different: it controls if a file opened from quick open shows up pinned or as preview. In our case we always want preview no matter what this setting does.
yeah, I did add a option for that, but called it eagerPreview
. I will rename it forcePreview
.
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.
It is fine to push down services like that but if you have a more elegant solution, also fine.
So you are talking about introducing a new global setting to control previewing from quick open? I honestly thing we do not need that because in other quick opens we already behave like that (e.g. quick outline, goto line, change theme). We can just have it on by default 👍
@wprater just add This service is being created before quick open so you can get it injected. |
0618752
to
6f94d8a
Compare
that worked perfect! |
aae016a
to
3a8af47
Compare
@bpasero added support for history blocking while tabs are being eagerly previewed! but need a better way to test it. |
4107685
to
bf01703
Compare
I need to fix the restoration of tabs and then we can re-review. |
Ok ping me then. |
@wprater since I just merged your other PR there are merge conflicts now. |
c243f5b
to
e68b30d
Compare
7ceadd3
to
98cf219
Compare
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.
start a new review? or should I pull out the editor restoring bit? I cleanup these commits when review is done.
Let's do that. I want to get this merged in and I like your idea of the freeze/restore. |
We are in end game currently and I will only have time next week again. I suggest you bring this into a good shape without the editor restoring thingy (I can add it later) and then I merge it next week. |
@@ -440,6 +440,7 @@ export class EditorOptions implements IEditorOptions { | |||
options.forceOpen = settings.forceOpen; | |||
options.revealIfVisible = settings.revealIfVisible; | |||
options.pinned = settings.pinned; | |||
options.forcePreview = settings.forcePreview; |
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.
@wprater can you quickly check where else in this file options are handled, I think you missed to add this new flag e.g. to TextDiffEditorOptions
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.
I did not add it because TextDiffEditorOptions would ever be used in a preview content, correct?
if (mode === Mode.OPEN_IN_BACKGROUND) { | ||
openInBackgroundOptions = { pinned: true, preserveFocus: true }; | ||
} | ||
sideBySide = !context.quickNavigateConfiguration && context.keymods.indexOf(KeyMod.CtrlCmd) >= 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.
@wprater any particular reason you added the extra !context.quickNavigateConfiguration
check here?
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.
What do you mean by "extra"?
When I removed the sideBySide and pinned options from https://github.com/Microsoft/vscode/pull/13909/files/87c4898204236054020596a89a459e77ebfefd04#diff-efeb3f5a180f00bd9db3f96c43f67f5cL1107 I wanted to keep the logic being used.
} else if (openInBackgroundOptions) { | ||
opts = EditorOptions.create(openInBackgroundOptions); | ||
} | ||
let pinned; |
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.
@wprater why do we need pinned here? first of all it does not seem to be used when the mode is Mode.OPEN
. And then I think the editor part itself is already dealing with the setting workbench.editor.enablePreviewFromQuickOpen
?
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.
Im a bit confused by your comment. Also, I don't see where the editorPart is handling this. It used to be in the controller, but was moved when I refactored that out here.
It's used in OPEN_IN_BACKGROUND
and OPEN
modes and gets it's value from the workbench.editor.enablePreviewFromQuickOpen
setting while in OPEN
mode. Some of this logic was taken when I removed this logic from the controller.
Did you look at this in context of the whole run
method here?
@@ -239,7 +239,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService | |||
// while the UI is not yet ready. Clients have to deal with this fact and we have to make sure that the | |||
// stacks model gets updated if any of the UI updating fails with an error. | |||
const group = this.ensureGroup(position, !options || !options.preserveFocus); | |||
const pinned = !this.previewEditors || (options && (options.pinned || typeof options.index === 'number')) || input.isDirty(); | |||
const pinned = (!this.previewEditors && !(options && options.forcePreview)) || (options && (options.pinned || typeof options.index === 'number')) || input.isDirty(); |
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 actually interesting: conceptually we cannot have a dirty file open as preview. So if you have many dirty files and you navigate over them in quick open they will open as pinned editors :-/
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.
When you say quick open, do you mean the control+tab or Open anywhere? Sorry, Im not up to speed on all the nomenclature.
Won't dirty files already be opened an not previewed, so when they get selected, the editor will just be opened (switched to foreground)?
@@ -30,11 +30,12 @@ import { IResourceInput, IEditorInput } from 'vs/platform/editor/common/editor'; | |||
import { IModeService } from 'vs/editor/common/services/modeService'; | |||
import { getIconClasses } from 'vs/workbench/browser/labels'; | |||
import { IModelService } from 'vs/editor/common/services/modelService'; | |||
import { EditorInput, getUntitledOrFileResource, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; | |||
// import { EditorInput, getUntitledOrFileResource, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; |
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.
@wprater why commented out?
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.
I was still working on this, sorry, I never intend to commit commented out code. It was meant to be removed.
@@ -184,7 +192,11 @@ export class GotoLineHandler extends QuickOpenHandler { | |||
this.lastKnownEditorViewState = (<IEditor>editor.getControl()).saveViewState(); | |||
} | |||
|
|||
return TPromise.as(new QuickOpenModel([new GotoLineEntry(searchValue, this.editorService, this)])); | |||
const entry = this.instantiationService.createInstance( |
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.
@wprater you do not need to pass in the services, just do: this.instantiationService.createInstance(GotoLineEntry, searchValue)
All services will be passed in automatically.
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.
The constructor's signature requires a handler as well as those services. Everything will get passed in while using the instantiationService?
constructor(line: string, editorService: IWorkbenchEditorService, historyService: IHistoryService, configurationService: IConfigurationService, handler: GotoLineHandler)
@wprater added more feedback. I did not look closely at Btw I noticed that dirty editors cannot open as preview editors (conceptually currently). That is a pretty bad limitation for this feature I fear :-( |
Commented on this, but I did not intend to commit the commented out code. It's ready to look at, the code in |
I don't see to understand why they would ever be attempted to open as a preview? They are always already open, correct? So those editors would become active during the select (preview). Was caught up on a ton of project work these last weeks. |
@wprater yeah good point on the fact that dirty files are always opened. however, you might have opened a dirty file in another group (there can be up to 3 groups) and so you might be in group 1 doing your quick open preview business when a dirty file is opened in group 2 or 3. This leads to opening the dirty file in to group 1 while you preview over, UNLESS we would actually reveal the file in the other group, which would make the whole preview business more complicated. I find it very interesting what sublime does and they do not have this problem because they seem to have a special preview editor that is not even opening a new tab in the tab well: This goes back to your original idea of having a custom editor for preview but goes beyond that: We do currently not have such a preview editor that does NOT open a new tab. Sublime also leverages this when you have no file open: |
Yeah, Im not sure that's the best experience? Think you've always been keen to keep the focus within the focused group. Especially if we follow up with this issue #14142 Did you want to chat offline (or in another ticket) about how we could create such a temporary (preview) editor? I think we have most of the mechanics done already. Just a matter of rendering an editor on top of the current editor's group and sending events for tabs revealing or what not. Otherwise, I need to figure out how deal with these dirty editors. |
The more I think about this problem the more I believe we need to introduce a new concept in the editor space which is a truly preview-editor that does not show up anywhere in the UI besides showing the contents of a file. This editor should (when open) not cause a change in the tab well, will be ignored by any editor listeners (such as the history - making the blocking of history obsolete) and should not cause any UI change anywhere else (e.g. opened editors view). Once any other editor opens (or even the same editor), this preview-editor is thrown away and replaced with the real editor that shows with a tab. If the same editor is opened that was previously previewed, it should keep the contents of the editor and just update the tab well on top. I fear this is not such a simple change because it drags through many layers and needs some more thinking. But I thought I send out this idea already. |
Yeah, I agree that we should go this route, after going through all these save/restore/preview states I was always thinking a simpler overlay/temp editor could help simplify things. Let me know how I can help. |
Unfortunately it needs to be a full new concept that goes beyond a temp editor. Appreciate your help, I need to think about this for a while. Some other P1 work is requiring my full attention right now. |
so is this PR dead? |
I think it is ongoing, but from my end I did not have enough time to check back. I think the critical piece missing is a way of opening an editor as preview without interfering with any tabs model or emitting events otherwise. This is a bit outside of the scope of this PR to be fair but I think the preview cannot be done properly without such functionality on the core workbench editor layer. |
Im still very keen to help get this landed. We were close, but as @bpasero said, there was a condition where an editor could open in a pane that was only meant to be a preview. A temporary view which would overlay on top of the current editor part, would be one solution. I dont know enough of the internal mechanics to take a good stab at this, however. More than happy to brainstorm.. or review code ideas. |
Poke / +1 as a drive to get this developed properly / merged as this would make a pretty big difference to UX in vscode |
Unfortunately this needs a lot more thinking to get right, closing until we revisit this. |
Is this still something planned? No more activity there too: #12892 Would love to see this happening! 👍 |
refs #8939
notes
#8939 (comment)
#8939 (comment)