-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
GH-73: Implemented editor navigation history. #1649
Conversation
/** | ||
* Checks whether the service can go [`forward`](#forward). | ||
*/ | ||
canGoFroward(): boolean { |
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.
Small typo! Froward
-> Forward
} | ||
|
||
async onStart(): Promise<void> { | ||
this.restoreState(); |
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.
await
?
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 can do that; I left it out intentionally.
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.
ok, i mostly was wondering whether it should have the same lifecycle as a layout. For example, in Atom there are hooks to store and restore data, we have it only for the layout. And Atom decides when it is a good time to store and restore. In our case it seems to be a responsibility of the extension developer. It could be bad in the long run for example if we change when the data should be stored on the shutdown then each extension should be updated. I will open an issue to discuss it separately.
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.
In this case, would it make sense to store the state only onStop
similar how we store the layout data?
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.
Great idea, thanks! I was also wondering if we could do something like this in the FrontendApplication#startContributions
:
await Promise.all(this.contributions.getContributions().filter(c => !!c.onStart).map(c => c.onStart!(this)));
Instead of starting each contribution one by one and wait for them (if it is a Promise). We just need to handle errors properly, and not fail fast.
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.
Alright, let's leave as is.
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.
In this case, would it make sense to store the state only onStop similar how we store the layout data?
It raises a question; FrontendApplicationContribution#onStop
says: Note that this is implemented using `window.unload` which doesn't allow any asynchronous code anymore.
. Still, we call async code from onStop
, for instance: WorkspaceService
. Do we still want to go with this approach? It does not seem to be safe.
In a nutshell: this.storageService.setData
is async and we should not call it from window.unload
.
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 could have a sync API on the StorageService
.
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.
In a nutshell: this.storageService.setData is async and we should not call it from window.unload.
It is fine, it is implemented with LocalStorage
which is synchronous. Maybe we should make StorageService
synchronous as well. Let's keep the discussion in #1671. It is not in the scope of this PR.
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.
OK.
We have a change event on a resource already. We can refine it to provide a change kind so clients can react on it, like mark an editor as deleted and remove a history location. Let's tackle it separately. |
import { NavigationLocationService } from './navigation/navigation-location-service'; | ||
|
||
@injectable() | ||
export class EditorNavigationContribution implements Disposable, MenuContribution, CommandContribution, KeybindingContribution, FrontendApplicationContribution { |
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 EditorContribution
. Would it make sense to merge this contribution into it? I think it is nice to have all constants for commands, menus provided by the extension in one place.
I don't mean to merge completely EditorContribution
only registration of commands, menus and so on. Implementation can still live in something like EditorNavigationService
and be called from EditorContribution
.
What do you think?
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 am OK with both ways. If you prefer moving the editor navigation contribution there, we can do it.
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 up to you. My main concern is to avoid spreading extension constants.
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.
👍 Sure, as I said, I am OK with both, if you feel it is better, we can do it. It's a minor work.
I've tested it, not extensively, only for my cases. It works nicely for them. Code looks great as well. |
TODOs before merge:
|
I have made a few changes based on your feedback, the review is obsolete. Could someone please approve it again? Thanks! |
* Returns with the number of navigation locations that the application can handle and manage. | ||
* When the number of locations exceeds this number, old locations will be erased. | ||
*/ | ||
maxStackItems(): number { |
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.
Just looked through the code again; this should be protected
.
@simark, you have requested another review, shall we wait for that or are we good with this state? |
It was just because @MarkZ3 was actively waiting for this feature (if it is really what I think it is), so i thought he might want to give it a try. But if others are happy, go ahead, it's not like everything is set in stone after that. |
OK. I have pushed a small change so the review became stale. I have reduced the implicit You should be able to navigate back with Ctrl+- and forward with Ctrl+Shift+-, just like in VSCode. We ignore navigation location changes if those happen within +- 10 lines to the previous location. (Just like in VSCode). |
@kittaakos Sure, I'll give this a try in the next couple of hours. |
The keyboard binding for "back" doesn't seem to work in Electron: when I do Ctrl+-, it zooms out (as it should??). I also don't see the command in the command palette. I typed "previous" and "back". I ended up noticing it in the main menu, under "Go", there I see that there is no keyboard mapping for back but there is for forward. Indeed, "forward" seems to work with the keyboard, but "back" only works through the menu. This is on Ubuntu BTW. In the browser version, the menu items gray out properly and both shortcut are displayed in the menu. But similarly, the back keyboard binding zooms out. Very excited to be able to use this BTW! |
I will verify this and will get rid of the keybinding collision on Ubuntu. Perhaps, the same problem present on Windows.
That is on purpose, but I can add it if you think it could be useful. Please do not take the current zoom in/out problem into account for now.
That should be an electron bug; I will open a follow-up for that.
Thanks for the review! |
I think it makes sense. I see back/forward at the same level of other navigation commands like "go to definition". That's how I tried to find them at first. They are in the command palette in VS code too. BTW, I would think only the "keybinding collision" is really blocking, the rest can be addressed in different patches/issues. |
Roger that. I will add it.
I agree. |
The command label should be qualified:
just like in VSCode. |
We will go with Alt+← (to |
Closes #73. Signed-off-by: Akos Kitta <[email protected]>
I have verified on OS X (both on electron and browser) and on Windows too: @MarkZ3, could you please try it out on Linux? Thanks! |
@kittaakos I just tested it and it seems to work well! I'm personally not a big fan of how it works in VSCode because I think the history is a bit too detailed, and it seems to be similar here. But I would very much like to see this current proposal merged because it is very useful and later I can propose some tweaks or some preference. |
We could make it configurable from the preferences. The implementation should be straightforward.
Then please approve it, and I push the button ;) |
I'm not 100% sure about the shortcut on macOS. Safari is option-leftarrow, VSCode is ctrl-cmd-leftarrow, and Xcode also. We can change later though. |
I'll haven't checked the code yet but it shouldn't take long. |
The code was reviewed and approved already twice. I have tested on OS X and Windows too. But it is your call. |
Ah ok. Sounds good! |
Furthermore, the browser's back/forward is bound to the |
Woops, my bad. It is for me too. Got the keys mixed up :) |
Notes:
@theia/filesystem
in@theia/editor
.Closes #73.
Signed-off-by: Akos Kitta [email protected]