emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: savehist and multiple Emacs sessions


From: Stefan Monnier
Subject: Re: savehist and multiple Emacs sessions
Date: Wed, 21 Dec 2005 12:01:14 -0500
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux)

>> So I think it's worth it to make savehist.el handle such
>> situations better.
> I agree.  I don't have time to thoroughly review the patch right now,
> but I trust that you got it right.

> The only thing I disagree with is the resurrection of `savehist-load'.

Well, the code is long enough to warrant a function of its own, and it
seemed like the most natural name for it.  But if you prefer to keep it
separate, I can call it something else, e.g. savehist-reload.

> BTW with the new semantics of savehist-loaded, you might want to
> rename it to savehist-load-time or something like that.

In that case I'd name it savehist-file-sync-time, since it can also be the
time it was last saved.

>> It's only be lightly tested.  It also includes the changes to the
>> minor mode definition that make it handle Custom setting slightly
>> better and which make it run the minor mode hook in the same way as
>> all other minor modes defined by define-minor-mode.

> This breaks savehist under XEmacs and Emacs 21.4, which I use.

Oh yes, now I remember.  Sorry 'bout that.  This new patch should fix all
the above.


        Stefan


--- orig/lisp/savehist.el
+++ mod/lisp/savehist.el
@@ -168,10 +168,8 @@
 as possible, ideally simply exposing the internal representation of
 buffer text.")
 
-(defvar savehist-loaded nil
-  "Whether the history has already been loaded.
-This prevents toggling savehist-mode from destroying existing
-minibuffer history.")
+(defvar savehist-file-sync-modtime nil
+  "Modtime of the `savehist-file' when we last sync'd up with it.")
 
 (when (featurep 'xemacs)
   ;; Must declare this under XEmacs, which doesn't have built-in
@@ -198,34 +196,21 @@
          (> (prefix-numeric-value arg) 0)))
   (if (not savehist-mode)
       (savehist-uninstall)
-    (when (and (not savehist-loaded)
-              (file-exists-p savehist-file))
-      (condition-case errvar
-         (progn
-           ;; Don't set coding-system-for-read -- we rely on the
-           ;; coding cookie to convey that information.  That way, if
-           ;; the user changes the value of savehist-coding-system,
-           ;; we can still correctly load the old file.
-           (load savehist-file nil (not (interactive-p)))
-           (setq savehist-loaded t))
-       (error
-        ;; Don't install the mode if reading failed.  Doing so would
-        ;; effectively destroy the user's data at the next save.
-        (setq savehist-mode nil)
-        (savehist-uninstall)
-        (signal (car errvar) (cdr errvar)))))
-    (savehist-install)
-    (run-hooks 'savehist-mode-hook))
+    (savehist-reload)
+    (savehist-install))
+  (if (and (fboundp 'customize-mark-as-set) (interactive-p))
+      (customize-mark-as-set 'savehist-mode))
+  (run-hooks 'savehist-mode-hook)
   ;; Return the new setting.
   savehist-mode)
-(add-minor-mode 'savehist-mode "")
+(add-minor-mode 'savehist-mode nil)
 
 (defun savehist-load ()
   "Obsolete function provided for transition from old versions of savehist.
 Don't call this from new code, use (savehist-mode 1) instead.
 
 This function loads the variables stored in `savehist-file' and turns on
-savehist-mode.  If savehist-file is in the old format that doesn't record
+`savehist-mode'.  If `savehist-file' is in the old format that doesn't record
 the value of `savehist-minibuffer-history-variables', that value is
 deducted from the contents of the file."
   (savehist-mode 1)
@@ -238,14 +223,52 @@
            (ignore-errors
              (insert-file-contents savehist-file))
             (let ((vars ()) form)
-              (while (setq form (condition-case nil
-                                   (read (current-buffer)) (error nil)))
+              (while (setq form (ignore-errors (read (current-buffer))))
                ;; Each form read is of the form (setq VAR VALUE).
                ;; Collect VAR, i.e. (nth form 1).
                 (push (nth 1 form) vars))
               vars)))))
 (make-obsolete 'savehist-load 'savehist-mode)
 
+(defun savehist-reload ()
+  "Load the history data from `savehist-file' while preserving the current 
history data."
+  (let ((savehist-old-minibuffer-history-variables
+         (mapcar (lambda (s) (and (boundp s) (cons s (symbol-value s))))
+                 (cons 'savehist-minibuffer-history-variables
+                       savehist-minibuffer-history-variables))))
+    (when (and (file-exists-p savehist-file)
+               (not (equal savehist-file-sync-modtime
+                           (nth 5 (file-attributes savehist-file)))))
+      (condition-case errvar
+          (progn
+            ;; Don't set coding-system-for-read -- we rely on the
+            ;; coding cookie to convey that information.  That way, if
+            ;; the user changes the value of savehist-coding-system,
+            ;; we can still correctly load the old file.
+            (load savehist-file nil (not (interactive-p)))
+            (setq savehist-file-sync-modtime
+                  (nth 5 (file-attributes savehist-file))))
+        (error
+         ;; Don't install the mode if reading failed.  Doing so would
+         ;; effectively destroy the user's data at the next save.
+         (setq savehist-mode nil)
+         (savehist-uninstall)
+         (signal (car errvar) (cdr errvar)))))
+
+    ;; In case we're loading the file late, there was info in the history
+    ;; variables that may have been overwritten by the info extracted from
+    ;; the file, so put it back in.
+    (dolist (sv savehist-old-minibuffer-history-variables)
+      ;; For each histvar that we knew about, make sure all the entries that
+      ;; were there before are still here now and in the same order.
+      (ignore-errors            ; Maybe some var is not a list or something.
+        (let* ((s (car sv))
+               (v (cdr sv))
+               (newv (symbol-value s)))
+          (unless (equal newv v)       ;Simple optimization.
+            (dolist (x v) (setq newv (delete x newv)))
+            (set s (append v newv))))))))
+
 (defun savehist-install ()
   "Hook savehist into Emacs.
 Normally invoked by calling `savehist-mode' to set the minor mode.
@@ -283,6 +306,13 @@
 If AUTO-SAVE is non-nil, compare the saved contents to the one last saved,
  and don't save the buffer if they are the same."
   (interactive)
+  (unless (equal savehist-file-sync-modtime
+                 (nth 5 (file-attributes savehist-file)))
+    ;; The file has been changed since last time we touched it.
+    ;; Probably some other Emacs session.  Load the corresponding info so we
+    ;; don't end up throwing it away by blindly overwriting it.  There's
+    ;; still a race-condition, but I don't think it's that important.
+    (savehist-reload))
   (with-temp-buffer
     (insert
      (format ";; -*- mode: emacs-lisp; coding: %s -*-\n" 
savehist-coding-system)
@@ -328,6 +358,8 @@
                        (unless (interactive-p) 'quiet)))
        (when savehist-file-modes
          (set-file-modes savehist-file savehist-file-modes))
+        (setq savehist-file-sync-modtime
+              (nth 5 (file-attributes savehist-file)))
        (setq savehist-last-checksum checksum)))))
 
 (defun savehist-autosave ()




reply via email to

[Prev in Thread] Current Thread [Next in Thread]