akermu / emacs-libvterm

Emacs libvterm integration
GNU General Public License v3.0
1.71k stars 136 forks source link

Integrate with desktop-save-mode #666

Open ksqsf opened 1 year ago

ksqsf commented 1 year ago

vterm currently does not integrate with desktop-save-mode, and thus all vterm buffers will be lost after restarting Emacs. And it seems nobody has raised this topic before (searching this github repo).

I'm currently using custom integration code (see below; it works for me but I'm sure it's incomplete), but I hope vterm can support it upstream. I believe the integration will be helpful to many others, and saves me a few lines of config. :)


  ;; Integration with desktop-save-mode
  (defvar vterm-persist-buffer-contents t
    "When t, desktop-save-mode also saves the buffer contents.")
  (defun vterm-save-desktop-buffer (desktop-dirname)
    (cons
     (desktop-file-name default-directory desktop-dirname)
     (if vterm-persist-buffer-contents (buffer-string) "")))
  (defun vterm-restore-desktop-buffer (filename buffer-name misc)
    "MISC is the saved return value of `desktop-save-vterm'."
    (let ((default-directory (car misc)))
      (require 'vterm)
      (with-current-buffer (get-buffer-create buffer-name)
        (when vterm-persist-buffer-contents
          (insert (cdr misc))
          (insert "\n\n"))
        (vterm-mode))))
  (add-to-list 'desktop-buffer-mode-handlers '(vterm-mode . vterm-restore-desktop-buffer))
  (add-hook 'vterm-mode-hook #'(lambda () (setq-local desktop-save-buffer 'vterm-save-desktop-buffer)))
Sbozzolo commented 1 year ago

Thanks, @ksqsf.

Do shell-mode / term-mode implement similar functions? I mostly asking because technically when you restore the buffer you'll be starting a new process (you won't be picking up from the old one). To me, this breaks a little bit the idea of saving/restoring, as what you are saving is only the text in the buffer.

PS: You don't need to sharp-quote a lambda

ksqsf commented 1 year ago

That's a good point. Indeed, shell (comint) and term do not do this.

Speaking of "only saving the text", I think just restarting the term is already useful even without saving buffer contents: I have long-running emacs sessions in multiple tabs with multiple terms carefully placed, so maybe that's why I need this.

But anyway, I'm not in the position to judge if this should be included. Feel free to close this issue. :)

pataquets commented 1 year ago

IMO, just opening the terminal windows in the previous directory might help for some users. Although it understandably won't save the screen buffer contents, that might be enough to enable some kind of context recovery with some smart shell trickery (eg. a different BASH_HISTORY file for each window comes to mind). Some tmux tools exist for saving sessions, for example. Even if it's not a priority, I won't dismiss the feature at all.

EDIT: I've opened #674 to find if setting different env vars as described in the example would be possible entirely from Emacs alone.

pataquets commented 10 months ago

Somewhat answering myself for the use case above, I've been able to launch vterm with a customized environment variable:

     (with-environment-variables
         (("HISTFILE" (expand-file-name "~/.test-history-file")))
       (vterm))
fakeGenuis commented 9 months ago

A persp-mode version here, for doom users, though doom can restore vterm with default-directory.

(after! persp-mode
  ;; vterm
  (persp-def-buffer-save/load
   :mode 'vterm-mode :tag-symbol 'def-vterm-buffer
   :save-vars '(default-directory)
   :save-function (lambda (buf tag vars)
                    (list tag (buffer-name buf) vars
                          (string-trim-right (buffer-substring-no-properties (point-min) (point-max)))))
   :load-function (lambda (savelist &rest _)
                    (cl-destructuring-bind (buf-name vars buf-string) (cdr savelist)
                      (let ((default-directory (alist-get 'default-directory vars)))
                        (require 'vterm)
                        (with-current-buffer (get-buffer-create buf-name)
                          (insert buf-string)
                          (vterm-mode)))))))

buffer-string stores text string with properties and makes reload stuck with Invalid read syntax "#" (don't know why), so buffer-substring-no-properties used here.