From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Madhu Newsgroups: gmane.emacs.devel Subject: ielm automatic saving of history -- bug 67000 Date: Sun, 13 Oct 2024 09:47:25 +0530 Message-ID: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="26843"; mail-complaints-to="usenet@ciao.gmane.io" To: emacs-devel@gnu.org Cancel-Lock: sha1:wiCU9IWkmjdJ6y8E2PuebVq+Y6A= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sun Oct 13 06:34:50 2024 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1szqJd-0006tv-GC for ged-emacs-devel@m.gmane-mx.org; Sun, 13 Oct 2024 06:34:49 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1szqIw-0000fm-Oz; Sun, 13 Oct 2024 00:34:06 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szq2n-0007p2-W5 for emacs-devel@gnu.org; Sun, 13 Oct 2024 00:17:26 -0400 Original-Received: from ciao.gmane.io ([116.202.254.214]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1szq2l-0005MQ-93 for emacs-devel@gnu.org; Sun, 13 Oct 2024 00:17:25 -0400 Original-Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from ) id 1szq2h-0002Nr-W0 for emacs-devel@gnu.org; Sun, 13 Oct 2024 06:17:19 +0200 X-Injected-Via-Gmane: http://gmane.org/ Received-SPF: pass client-ip=116.202.254.214; envelope-from=ged-emacs-devel@m.gmane-mx.org; helo=ciao.gmane.io X-Spam_score_int: -15 X-Spam_score: -1.6 X-Spam_bar: - X-Spam_report: (-1.6 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=0.249, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Sun, 13 Oct 2024 00:34:03 -0400 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:324529 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit * commit 60cff1ac9d216e5abcb350ea5e623ab0b377c131 |Author: Simen Heggestøyl |AuthorDate: Tue Jan 16 08:21:41 2024 +0100 |Commit: Simen Heggestøyl |CommitDate: Thu Feb 15 08:46:28 2024 +0100 | | Add support for reading/writing IELM input history (bug#67000) | | * lisp/ielm.el (inferior-emacs-lisp-mode): Add support for saving input | history to a file. | (ielm--history-file-name): New variable indicating IELM input history | file. | (ielm--exit): Holds a function to call when Emacs is killed to write | out the input history. | (ielm--input-history-writer): Helper function for writing the IELM | input history out to file. I see several problems with this implementation (based on opaque closures), the worst of which is that I am unable to quit emacs, because a closure (which tries to save the contents of a killed-buffer, is in kill-emacs-hook, and it cannot get the coding system right) The implementation roughly does: ``` (setq-local comint-input-ring-file-name ielm-history-file-name) (setq-local ielm--exit (ielm--input-history-writer (current-buffer))) (setq-local kill-buffer-hook (lambda () (funcall ielm--exit) (remove-hook 'kill-emacs-hook ielm--exit))) (unless noninteractive (add-hook 'kill-emacs-hook ielm--exit)) (comint-read-input-ring t) ``` 2. The way to opt out of this is to set ielm-history-file-name to nil in user customization. In that case this code path should be avoided altogether. ielm--exit is a buffer local variable which gets set to ``` (lambda () (with-current-buffer buf (comint-write-input-ring))) ``` and pushed onto kill-emacs-hook. Another closure gets pushed onto kill-buffer-hook, which removes the elt in kill-emacs-hook when it runs. The "worst" problem happens when ielm buffer exits without running kill-buffer-hook ( -- historically I've used this pattern to avoid saving history for a particular buffer, this is the way to opt out of saving the history) but in this case it runs from the kill-emacs-hook, and that forces me to choose a coding system to save the buffer. There is no option to opt out. I don't have any suggestions on how to solve this with this design. 3. The default Comint functions for storing eliisp history is less than acceptable. it stores lines, while ielm and elisp permit multi-line sexp forms. personally I've used code (derived from sly so not probably fsf license) in ielm-mode-hook to set up merge and save multiline forms using comint, I'm attaching this file here, for reference. However the currenlty installed implementation in (inferior-emacs-lisp-mode) does not play well with the this: It unconditionally touches comint history variables, my code also has to set the comint variables to use the comint history mechanism, and these are picked up with exit hooks. Maybe others using the facility will have some opinions on this. My own takeaway is it is not desirable to 1) force history saving mechanisms 2) use opaque closures for implementing hook functions. --=-=-= Content-Type: text/plain Content-Disposition: attachment; filename=my-ielm-history.el ;;; my-ielm-history.el -- to save ielm history using a hook. (posted, ;;; madhu 20241013) ;; comint-input-ring-separator and ielm-write-input-wring taken from ;; sly (defun my-ielm-read-input-ring () (let ((comint-input-ring-separator "####\n")) (comint-read-input-ring))) (defun my-ielm-process-sentinel (proc msg) (let ((buffer (process-buffer (get-process proc)))) (when (buffer-live-p buffer) (with-current-buffer buffer (my-ielm-write-input-ring)))) (internal-default-process-sentinel proc msg)) (defun my-ielm-write-input-ring () ;; not enough to make it buffer-local. The binding has to exist when ;; the rings is being written to " *Temp Input History*" (let* ((comint-input-ring-separator "####\n") ;; To merge the file's history with the current buffer's ;; history, sntart by deep-copying `comint-input-ring' to a ;; separate variable. (current-ring (copy-tree comint-input-ring 'vectors-too)) (histcontrol 'erasedups) (index (ring-length current-ring)) ) ;; this sets `comint-input-ring' from the file (my-ielm-read-input-ring) ;; loop `current-ring', which potentially contains new entries and ;; re-add entries to `comint-input-ring', which is now synched ;; with the file and will be written to disk. (cl-loop for i from (1- index) downto 0 for item = (ring-ref current-ring i) for existing-index = (ring-member comint-input-ring item) do (cond ((and existing-index (eq histcontrol 'erasedups)) (ring-remove comint-input-ring existing-index) (ring-insert comint-input-ring item)) ((and existing-index (not histcontrol)) (ring-insert comint-input-ring item)) (t (ring-insert comint-input-ring item))) unless (ring-member comint-input-ring item) do (ring-insert comint-input-ring item)) ;; Now save `comint-input-ring' (let ((coding-system-for-write 'utf-8-unix)) (comint-write-input-ring)))) ;; madhu 060520 (add-hook 'ielm-mode-hook (defun my-ielm-mode-hook () (set-process-sentinel (get-buffer-process (current-buffer)) 'my-ielm-process-sentinel) ;;(make-variable-buffer-local 'comint-input-ring-separator) (setq comint-input-ignoredups t comint-input-ring-file-name ;;comint-input-ring-separator "####\n" ;madhu 200131 (expand-file-name "~/.ielm-history.el") comint-input-ring-size 1000) ;;(make-local-hook 'kill-buffer-hook) (add-hook 'kill-buffer-hook 'my-ielm-write-input-ring nil t))) (defun fix-ielm-buffer () "put #### markers between sexps in a ielm history buffer without those" (while (not (eobp)) (forward-sexp) (assert (eolp)) (cond((eolp) (insert "####") (forward-line 1)) (t (debug))))) --=-=-=--