Subject: 28.0.50; Alternative method to persist Comint history

From: Augusto Stoffel <[email-masked]>
Date: Sun, 26 Sep 2021 14:13:16 +0200

I was trying to make the Python shell persist its history and I couldn't
make it work well with the existing method (`comint-read-input-ring' and
`comint-write-input-ring'), for the following reasons:

- Some user commands (initialization, eval region, completion) send code
  to the inferior process behind the scenes, and this ends up recorded
  in the interpreter's history file.
- The Python interpreter is not as smart as bash when it comes to saving
  the history file.  It fails to do so if it's killed abruptly (e.g., by
  killing the comint buffer).  Somehow I couldn't make it work via a
  process sentinel either.
- The IPython interpreter, on the other hand, is overly smart and uses a
  database instead of a plain history file.

Now I found an alternative that works well for me.  It relies on the
savehist mechanism:

    (defvar-local comint-history-variable nil)

    (advice-add 'comint-add-to-input-history :after-while
                (lambda (cmd)
                  (when comint-history-variable
                    (add-to-history comint-history-variable
                                    (substring-no-properties cmd)))))

    (defun comint-history-setup ()
      (setq comint-history-variable (intern (concat (symbol-name major-mode)
                                                    "-history")))
      (unless (boundp comint-history-variable)
        (set comint-history-variable nil))
      (add-to-list 'savehist-minibuffer-history-variables comint-history-variable)
      (dolist (it (symbol-value comint-history-variable))
        (ring-insert-at-beginning comint-input-ring it)))

    (add-hook 'inferior-python-mode-hook 'comint-history-setup)

So the idea is to save each input to the comint twice: once in the
buffer-local `comint-input-ring' (for the purposes of `M-n', `M-p',
etc.), and once globally in the place pointed by
`comint-history-variable' (for the purposes of persistence).

This is a bit of a hack, but I think the only alternative would be to
make ring.el interact well with `savehist-mode', a much more drastic
change (but one that isearch might benefit from, for instance).

Note also that many Comints have their version of `M-!', and this funny
`comint-history-variable' could be used there as well---one more small
reason to say it's a desirable feature. :-)

Anyway, do you think this looks reasonable? Then I would format a patch
(without the various corner-cuts of the above, of course).  This
wouldn't change the regular shell, but would add this new feature to
comint.el and make the Python shell use it.