helix-editor / helix

A post-modern modal text editor.
https://helix-editor.com
Mozilla Public License 2.0
33.09k stars 2.46k forks source link

Persistent State (session) #401

Open kirawi opened 3 years ago

kirawi commented 3 years ago

This feature will allow you to share the same file history between sessions, and could help in situations where the editor crashes. #290 #294

bestouff commented 2 years ago

Now the question is: what file format ? In the ideal case, like for vim, a script which can be edited.

cole-h commented 2 years ago

This should probably be implemented as a plugin (whenever that functionality is available).


That said, it would probably be prudent to use something easy to serialize. TOML is already used for the basic config, so why not stick with that? An example, totally fictional file might store information about the documents themselves like:

[[documents]]
path = "/canonical/file/path"
cursor = { line = 90, column = 1 }
alt_document = "/canonical/file/path2" # this is "last_accessed_doc"
# no focused here; would be deserialized as false
[[documents.selections]]
start = { line = 70, column = 10 }
end = { line = 100, column = 1 }
[[documents.selections]]
start = { line = 1, column = 1 }
end = { line = 2, column = 23 }

[[documents]]
path = "/canonical/file/path2"
cursor = { line = 1, column = 1 }
# no alt_document here because it doesn't have one; would be deserialized as None
focused = true # means this document is currently visible
[[documents.selections]]
start = { line = 1, column = 10 }
end = { line = 5, column = 1 }
[[documents.selections]]
start = { line = 10, column = 1 }
end = { line = 10, column = 3 }

I don't currently have any ideas on how we would serialize the current layout of views to TOML, though.

eugenesvk commented 2 years ago

Sublime Text has this awesome "hot exit" feature that allows you to exit without any "Save unsaved files?" confirmation and reopen to exactly the same state, it's very useful for regular use, not just crashes. Am I correct that you feature request is exactly the same?

(quote from ST regarding this feature)

Exiting the application with hot_exit enabled will cause it to close immediately without prompting. Unsaved modifications and open files will be preserved and restored when next starting. Closing a window with an associated project will also close the window without prompting, preserving unsaved changes in the workspace file alongside the project.

lytedev commented 2 years ago

For what it's worth, I'd like to propose that this not be a plugin. I know Helix calls itself a text editor, but it definitely seeks to have "MVP IDE" features, and this is something VS Code and other editors do out of the box to various degrees. Additionally, this sort of persistence is really nice to have for a number of reasons, especially if you regularly switch between projects wanting to sort of pick up where you left off. Happy to argue and be wrong, but I think this should be considered core functionality!

There are a couple of fairly simple ways I think we could achieve this without too much effort and with 99% of the benefit.

I think if you open helix "bare" (that is, without specifying a file argument) in a given directory, it could simply save the state it exits with to a file (either TOML or SQLite I imagine) as it exits. When you open helix "bare" again in that same directory, it loads up that same state.

Alternatively, instead of the "bare" logic, it could be a command (which in turn might be triggered with a flag like --load-session "$(pwd)" or a key mapping) such as save-session and load-session which by default would save/load the state to/from ~/.local/cache/helix/sessions/$DIR.toml (or ~/.local/share/helix, I dunno) where dir is the current directory with the directory separators (/ and \) replaced with %. This is similar to what my neovim session manager plugin does.

Likely the terminology here would need to change since Helix would need to know if it's "managing" a session so that when it comes exit time, it knows to write the session to the file. Additionally, maybe the session is written to very often (but certainly not for every state change?) and nothing special needs to happen specifically on exit. It would be worth investigating how other editors (or their plugins) handle this.

At a minimum to be useful (at least to me given my current neovim setup), I would expect the following to be stored:

Other things that would be nice:

Other considerations to take into account:

Anyways, this is something I'd like to work on if it's "blessed".

aikomastboom commented 2 years ago

I am a Jetbrains user myself and currently switch back and forth between hx and CLion to see how usable it is becoming for day-to-day development.

Adding persistent state (perhaps even extended to a project level) would really be great. On the other hand, I find myself also frequently turning to vi (now hx) because of its startup speed to just get a quick file changed (eg in /etc folder) where I do not want a complete state resurrected before I can do anything.

Having a means in the (core) code to be able to dump/restore state I find a big plus to any software. It might even help development as a means to easily create/record test fixtures or to provide/record reproducible bug-reports.

kirawi commented 2 years ago

This was brought up in Matrix, but it might be useful to have some form of manual session management, e.g. :session-write session_name. It would be simpler than having it be automatic and thinking about multiple editors writing to the same state file.

lytedev commented 2 years ago

Yeah the more I've thought about this the more I think that Helix should just provide the primitive capabilities and the user should be able to get Helix to do what it wants either by configuration, environment variables, or command-line flags which could be then be aliased.

I think a command line flag that lets you specify commands to run upon starting up would be a good first step, then you could do something like alias helix-session="helix --command \":load-session $(pwd | tr '/' '%')\"". As for how to ensure the session is saved (at least on a clean exit), we would need a similar mechanism for running a command just before quitting. This wouldn't be very unlike Vim's autocommands. This probably leads into a larger conversation about a plugin system and hooks, but for now, I'm thinking another command line argument like so would suffice: helix --before-quit-command ":save-session $(pwd | tr '/' '%')".

This would at least get us something for power users without too much effort.

The next question is the actual implementation of writing the state. I dove into the code to tinker a bit, and it looks like we could theoretically derive Serialize for Editor and all it's "child structs" (is there a proper term for this? field values?) and simply serialize the entire Editor struct as TOML and call it a day. I'm sure that's going to run into issues, though, so I'm thinking that we would want some way to serialize only the particular fields we care about

So we would define some other struct which contains the bits we actually care about for session storing/saving and would then need a From/Into implementation between the editor struct and this "sub-editor for sessions" struct which then would implement serializable. Then the commands (:session-write and :session-read) would simply convert the Editor state to the session-friendly form and serialize that to the file for the write command and swap in whatever Editor state we end up with as a result from loading a session for the read command.

I'm pretty new to Rust and VERY new to Helix's codebase, so please let me know if this sounds like a poor solution! Thank you in advance!

mike-lloyd03 commented 2 years ago

@lytedev That approach sounds reasonable but I'm not a helix maintainer. I'd really like to see session support get added since this is the biggest thing keeping me from fully embracing helix. If the maintainers agree that serializing the Editor object is a good approach, I wouldn't mind working together on this to get it going.

kirawi commented 2 years ago

I don't think these fields should be serialized: count, selected_register, diagnostics, debugger, clipboard_provider, syn_loader, theme_loader, last_theme, theme, status_msg, autoinfo, auto_pairs, idle_timer, and exit_code.

kirawi commented 2 years ago

I took a quick look at what changes might be needed:

txtyash commented 2 years ago

If a user hasn't set a theme then reloading the previously set theme on startup would be nice.

kirawi commented 1 year ago

@archseer I would like to try to tackle basic document history and command persistence. Do you have any guidance or requirements?

archseer commented 1 year ago

It probably needs to work similarly to SHARE_HISTORY/INC_APPEND_HISTORY in zsh:

APPEND_HISTORY If this is set, zsh sessions will append their history list to the history file, rather than replace it. Thus, multiple parallel zsh sessions will all have the new entries from their history lists added to the history file, in the order that they exit. The file will still be periodically re-written to trim it when the number of lines grows 20% beyond the value specified by $SAVEHIST (see also the HIST SAVE BY COPY option).

Neovim has it's own ShaDa format for this (shared data): https://neovim.io/doc/user/starting.html#shada

We can start small (prompt history), but we also need to figure out how this stores other data like document undo history and last document position: is it one file or a bunch of files etc. It's probably some custom format and isn't as easy as adding derive(Serialize) + dumping via serde.

mike-lloyd03 commented 1 year ago

For starting small, would it make sense just to be able to restore open buffers and document position? Command and undo history could be a follow on PR. When I think of "persistent state" I'm thinking mostly in terms of my workspace. If I close helix and open it again, I would expect to be able to pick right back up where I left off.

gibbz00 commented 1 year ago

Any reason why we don't want to avoid re-writing a database? Why not use SQLite for this? Could also be used to cache snippets similar to how coq_nvim does it.

kirawi commented 1 year ago

I've posted a draft PR. I have some local changes to transactions in a separate branch that would need to be pushed first. Overall, it'll probably be implemented to a working state sometime this week.

kirawi commented 1 year ago

The manual commands have been implemented in the linked PR. Feel free to test!

Randalix commented 1 year ago

What is the state of this? (When) will this be merged?

archseer commented 1 year ago

Have you tried looking through the associated issues and PRs? It's going to be merged when the implementation is finished.

naufraghi commented 1 year ago

The last linked PR https://github.com/helix-editor/helix/pull/5608 seems to have been closed and replaced by a new (but not yet linked) PR. Other PRs seem to be closed, many issues are linked. The Github UI is not helpful here :crying_cat_face: in understanding the overall status of a feature if you are not involved in the development of Helix.

That said, I understand that the question might be asking for a status update without much kindness, but on the other hand, the answer doesn't help much in understanding what's going on.

The feature is quite large and interrelated with many other features, and so the work is also complicated by the fact that many volunteer developers need to find the energy not only to write the first draft (which is usually fun), but also to refactor and adapt their work to the others (which is less of a Saturday afternoon task).

So I guess it's just complicated. Kudos for your work and thanks for hx!

kirawi commented 1 year ago

I have the main changes pushed to a branch, but I've just had a lot going on.

Riverside96 commented 1 year ago

Any updates? I can't find any related branch.

13r0ck commented 9 months ago

I am willing to put a $100 bounty on this feature

kirawi commented 9 months ago

ref https://github.com/helix-editor/helix/pull/9143

fastfading commented 5 months ago

it has been 3 years. still no improvement on this feature . how can we love this editor

intarga commented 5 months ago

The features are already implemented in #9143 so you can build that branch and use it if you’re desperate, but it’s not getting merged until buffer switching behaviour is fixed (#7568), and tests, config, and documentation are written because we care about quality more than rushing.

If you’re not even willing to put the effort in to check what’s done on the branch, and build it yourself, I don’t think you get to complain that volunteers aren’t implementing fast enough. After all, you could have implemented this yourself anytime in the last 3 years, but you didn’t 🤷‍♀️.

fastfading commented 5 months ago

I tried Helix two years ago, but I forgot why I gave up on it. Recently, I gave it another try, only to give up again due to the absence of this critical feature. It reminded me that I had abandoned it for the same reason last time. Undo after closing file is incredibly important; even Vim implemented the undofile feature early on because of this necessity.

Consider this scenario: you edit a file, save it, then close it or get disconnected via SSH. Later, you realize something is wrong, but you can't remember how the original file looked. You want to recover it, but there's no way to do so. Imagine the frustration you feel at that moment.

I apologize for not being a Rust engineer and unable to contribute in that regard. I just want to emphasize how crucial this feature is.

I simply want Helix to be better and better. I apologize if my previous comments sounded rude.

quentin-bettoum commented 5 months ago

Consider this scenario: you edit a file, save it, then close it or get disconnected via SSH. Later, you realize something is wrong, but you can't remember how the original file looked. You want to recover it, but there's no way to do so. Imagine the frustration you feel at that moment.

While persistent state would be a nice feature, the problem you're describing would probably be better solved by versioning these files with Git or by using snapshots for example.

I would not rely on any editor saved state if keeping the previous versions of files I'm working on is important.

naufraghi commented 5 months ago

I agree that persistent undo is something I hope to find there many times after an erroneous quit. But I think it's a different feature maybe?

Kudos to all the developers, Helix is very usable even without all these features, but the long tail of quality of live improvements will be faster and easier to implement once the foundation is solid and kept solid by a good process!

intarga commented 5 months ago

I agree that persistent undo is something I hope to find there many times after an erroneous quit. But I think it's a different feature maybe?

Kirawi and I decided to split the work, so they are working on persistent undo separately from me. You can find their work at #9154. I believe it's in a similar state to mine: The bulk of the work is done, and it's in a usable state, it just needs some polish before it's ready to merge

wraiford commented 5 months ago

I agree that persistent undo is something I hope to find there many times after an erroneous quit. But I think it's a different feature maybe?

Kudos to all the developers, Helix is very usable even without all these features, but the long tail of quality of live improvements will be faster and easier to implement once the foundation is solid and kept solid by a good process!

I strongly agree with bit about persistent undo being separate. I wouldn't want to sound rude or anything and since I'm just about on the street for devotion to open source, I can understand the limited time of volunteers. But for me personally, this is the one and only reason I haven't switched over to Helix. My experience with other vim editors with swap files was a nightmare. And I have an old laptop that freezes more than I'd like, due to it being the first (and unfortunately) poorly supported Ryzen 5 + AMD. So to have the possibility of losing state due to a freeze is simply unacceptable. Because even though I write to file extremely often, there are occasions where I am working across multiple files and have made multiple decent-sized changes. And it's the worst to have to reimplement at these times (because when it rains it pours effect).

So I still tolerate vscode + vscodevim. Fingers crossed that you prioritize this for others like me without the resources to have better hardware! I love the editor though!

kirawi commented 5 months ago

The issue of losing the content of a file on crash during a write was addressed on master via temporary files. It still won't preserve edits though.

fastfading commented 5 months ago

You can find their work at #9154. I believe it's in a similar state to mine: The bulk of the work is done, and it's in a usable state, it just needs some polish before it's ready to merge

https://github.com/kirawi/helix/tree/undo

@kirawi I tried to rebuild this branch , however it did not work. how to make it work ? I tried command :history-reload . not working

intarga commented 5 months ago

Did you enable it in your config?

fastfading commented 5 months ago

Did you enable it in your config?

no, how ?

fastfading commented 5 months ago
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index 72c859aa..8dd1b782 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -914,7 +914,7 @@ fn default() -> Self {
             popup_border: PopupBorderConfig::None,
             indent_heuristic: IndentationHeuristic::default(),
             jump_label_alphabet: ('a'..='z').collect(),
-            undofile: false,
+            undofile: true,
         }
     }
 }

I set it default , and it works now

kirawi commented 5 months ago

Config is handled in config.toml See https://docs.helix-editor.com/configuration.html for how that works

fastfading commented 5 months ago

https://github.com/helix-editor/helix/pull/9154 looks like this is buggy , the first time to open a file , it can be undofile after close . however , the next time it won't work until you call :deleteundofile . @kirawi

archseer commented 5 months ago

Yes, the PRs are still in development

sgon00 commented 3 months ago

Hi, I don't need some fancy undo session feature. Can helix remember cursor position after quit now? Thanks a lot.

intarga commented 2 months ago

@sgon00 If you build #9143 and add this line to the editor section in your config, yes, it works:

persist-old-files = true
sgon00 commented 1 month ago

@sgon00 If you build #9143 and add this line to the editor section in your config, yes, it works:

persist-old-files = true

Thanks a lot for the info. I just use the release binary. Is this included in the latest release? I am not sure how to check this and can NOT find this config option in the doc either.

intarga commented 1 month ago

It is not, the PR hasn’t been merged. I fixed the issue that was blocking it, but I still need to rebase, polish it a bit, write documentation, and get it reviewed before it can be merged. Then it will be included in the next release after the merge. Given all that, I expect it won’t be in a release for at least another few months (likely a year or so).

If the feature is a priority for you though (as it is for me) that branch is stable; I daily drive it with no issues.

intarga commented 3 weeks ago

Heads up for those using a build of #9143: I changed the format of the config options, so you will need to change your config when you update. The new format is like so:

[editor.persistence]
old-files = true
commands = true
search = true
clipboard = true