Skip to content
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

Persistent State (session) #401

Open
kirawi opened this issue Jul 3, 2021 · 39 comments
Open

Persistent State (session) #401

kirawi opened this issue Jul 3, 2021 · 39 comments
Assignees
Labels
A-helix-term Area: Helix term improvements C-enhancement Category: Improvements E-hard Call for participation: Experience needed to fix: Hard / a lot

Comments

@kirawi
Copy link
Member

kirawi commented Jul 3, 2021

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

@kirawi kirawi added the C-enhancement Category: Improvements label Jul 3, 2021
@pickfire pickfire added the A-helix-term Area: Helix term improvements label Jul 3, 2021
@kirawi kirawi added the E-hard Call for participation: Experience needed to fix: Hard / a lot label Aug 19, 2021
@kirawi kirawi changed the title Persistent State Persistent State (sessions) Nov 20, 2021
@kirawi kirawi changed the title Persistent State (sessions) Persistent State (session) Nov 20, 2021
@bestouff
Copy link

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

@cole-h
Copy link
Contributor

cole-h commented Nov 27, 2021

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
Copy link

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
Copy link
Contributor

lytedev commented Jul 20, 2022

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:

  • Open files (buffers?)
  • Splits (or windows or whatever they are) and they're ratios
  • The cursor locations for each of these splits

Other things that would be nice:

  • Undo history
  • Unsaved changes for any open buffers
  • Registers and macros

Other considerations to take into account:

  • If a session loads a buffer but a file has changed since the session was saved, how do we handle this?

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

@aikomastboom
Copy link
Contributor

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
Copy link
Member Author

kirawi commented Jul 21, 2022

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
Copy link
Contributor

lytedev commented Jul 22, 2022

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
Copy link

@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
Copy link
Member Author

kirawi commented Aug 12, 2022

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
Copy link
Member Author

kirawi commented Aug 23, 2022

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

  • We really only want to save three fields on Editor: tree, documents, and registers.
    • Documents should be cached.
  • The commands can be implemented in helix-term/src/commands/typed.rs. We can initialize a new Editor instance with the saved state and swap it by mutating cx.editor.
  • It might be necessary to reset Application::compositor, but I'm not sure.

@txtyash
Copy link
Contributor

txtyash commented Sep 28, 2022

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

@kirawi kirawi self-assigned this Dec 25, 2022
@kirawi
Copy link
Member Author

kirawi commented Jan 20, 2023

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
Copy link
Member Author

kirawi commented Jan 30, 2023

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

@Randalix
Copy link

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

@archseer
Copy link
Member

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

@naufraghi
Copy link

naufraghi commented Jul 24, 2023

The last linked PR #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 😿 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
Copy link
Member Author

kirawi commented Jul 24, 2023

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

@Riverside96

This comment was marked as spam.

@13r0ck
Copy link

13r0ck commented Dec 13, 2023

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

@kirawi
Copy link
Member Author

kirawi commented Jan 2, 2024

ref #9143

@intarga intarga mentioned this issue Jan 4, 2024
13 tasks
@fastfading
Copy link

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

@intarga
Copy link
Contributor

intarga commented Apr 17, 2024

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
Copy link

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
Copy link
Contributor

quentin-bettoum commented Apr 17, 2024

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
Copy link

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
Copy link
Contributor

intarga commented Apr 17, 2024

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
Copy link

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
Copy link
Member Author

kirawi commented Apr 19, 2024

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
Copy link

fastfading commented Apr 23, 2024

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
Copy link
Contributor

intarga commented Apr 23, 2024

Did you enable it in your config?

@fastfading
Copy link

Did you enable it in your config?

no, how ?

@fastfading
Copy link

fastfading commented Apr 23, 2024

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
Copy link
Member Author

kirawi commented Apr 23, 2024

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

@fastfading
Copy link

fastfading commented Apr 24, 2024

#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
Copy link
Member

Yes, the PRs are still in development

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-helix-term Area: Helix term improvements C-enhancement Category: Improvements E-hard Call for participation: Experience needed to fix: Hard / a lot
Projects
None yet
Development

No branches or pull requests