emacs-diffs
[Top][All Lists]
Advanced

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

scratch/so-long 3a109aa 08/10: Support 'preserved' variables and minor m


From: Phil Sainty
Subject: scratch/so-long 3a109aa 08/10: Support 'preserved' variables and minor modes in `so-long-mode'
Date: Thu, 29 Jul 2021 23:59:39 -0400 (EDT)

branch: scratch/so-long
commit 3a109aaa2972026d245444ddc4c86cbea2fd4c30
Author: Phil Sainty <psainty@orcon.net.nz>
Commit: Phil Sainty <psainty@orcon.net.nz>

    Support 'preserved' variables and minor modes in `so-long-mode'
    
    The default values support preserving the state of `view-mode' when
    switching to (and reverting from) `so-long-mode' (bug#45084).
    
    * lisp/so-long.el (so-long-mode-preserved-variables)
    (so-long-mode-preserved-minor-modes): New user options.
    (so-long-mode-maintain-preserved-variables)
    (so-long-mode-maintain-preserved-minor-modes): New functions.
    (so-long-remember-all, so-long-after-change-major-mode)
    (so-long-mode-revert): Use them.
    
    * etc/NEWS: Describe changes.
    
    * test/lisp/so-long-tests/so-long-tests-helpers.el:
    * test/lisp/so-long-tests/so-long-tests.el: Update tests.
---
 etc/NEWS                                         |  6 ++
 lisp/so-long.el                                  | 99 +++++++++++++++++++++++-
 test/lisp/so-long-tests/so-long-tests-helpers.el | 25 +++++-
 test/lisp/so-long-tests/so-long-tests.el         | 52 +++++++++++++
 4 files changed, 179 insertions(+), 3 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 103d91b..d4c8d06 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2834,6 +2834,12 @@ not recognised.  (This only has an effect if 
'set-auto-mode' chooses
 'fundamental-mode'; buffers which are simply in 'fundamental-mode' by
 default are unaffected.)
 
+---
+*** New user options 'so-long-mode-preserved-minor-modes' and
+'so-long-mode-preserved-variables' allow specified mode and variable
+states to be maintained if 'so-long-mode' replaces the original major
+mode.  By default, these new options support 'view-mode'.
+
 
 * New Modes and Packages in Emacs 28.1
 
diff --git a/lisp/so-long.el b/lisp/so-long.el
index 07f8370..69e0e1d 100644
--- a/lisp/so-long.el
+++ b/lisp/so-long.el
@@ -214,6 +214,24 @@
 ;; performance or otherwise avoid undesirable behaviours.  If `so-long-revert'
 ;; is called, then the original values are restored.
 
+;; * Retaining minor modes and settings when switching to `so-long-mode'
+;; ---------------------------------------------------------------------
+;; A consequence of switching to a new major mode is that many buffer-local
+;; minor modes and variables from the original major mode will be disabled.
+;; For performance purposes this is a desirable trait of `so-long-mode', but
+;; specified modes and variables can also be preserved across the major mode
+;; transition by customizing the `so-long-mode-preserved-minor-modes' and
+;; `so-long-mode-preserved-variables' user options.
+;;
+;; When `so-long-mode' is called, the states of any modes and variables
+;; configured by these options are remembered in the original major mode, and
+;; reinstated after switching to `so-long-mode'.  Likewise, if `so-long-revert'
+;; is used to switch back to the original major mode, these modes and variables
+;; are again set to the same states.
+;;
+;; The default values for these options ensure that if `view-mode' was active
+;; in the original mode, then it will also be active in `so-long-mode'.
+
 ;; * Hooks
 ;; -------
 ;; `so-long-hook' runs at the end of the `so-long' command, after the 
configured
@@ -394,6 +412,8 @@
 ;; 1.1   - Increase `so-long-threshold' from 250 to 10,000.
 ;;       - Increase `so-long-max-lines' from 5 to 500.
 ;;       - Include `fundamental-mode' in `so-long-target-modes'.
+;;       - New user option `so-long-mode-preserved-minor-modes'.
+;;       - New user option `so-long-mode-preserved-variables'.
 ;; 1.0   - Included in Emacs 27.1, and in GNU ELPA for prior versions of Emacs.
 ;;       - New global mode `global-so-long-mode' to enable/disable the library.
 ;;       - New user option `so-long-action'.
@@ -856,6 +876,44 @@ intended to be edited manually."
              (which-func-mode boolean))
   :package-version '(so-long . "1.0"))
 
+(defcustom so-long-mode-preserved-minor-modes
+  '(view-mode)
+  "List of buffer-local minor modes to preserve in `so-long-mode'.
+
+These will be enabled or disabled after switching to `so-long-mode' (by calling
+them with the numeric argument 1 or 0) in accordance with their state in the
+buffer's original major mode.  Unknown modes, and modes which are already in 
the
+desired state, are ignored.
+
+This happens before `so-long-variable-overrides' and `so-long-minor-modes'
+have been processed.
+
+By default this happens only if `so-long-action' is set to `so-long-mode'.
+If `so-long-revert' is subsequently invoked, then the modes are again set
+to their original state after the original major mode has been called.
+
+See also `so-long-mode-preserved-variables' (processed after this)."
+  :type '(repeat symbol) ;; not function, as may be unknown => mismatch.
+  :package-version '(so-long . "1.1"))
+
+(defcustom so-long-mode-preserved-variables
+  '(view-old-buffer-read-only)
+  "List of buffer-local variables to preserve in `so-long-mode'.
+
+The original value of each variable will be maintained after switching to
+`so-long-mode'.  Unknown variables are ignored.
+
+This happens before `so-long-variable-overrides' and `so-long-minor-modes'
+have been processed.
+
+By default this happens only if `so-long-action' is set to `so-long-mode'.
+If `so-long-revert' is subsequently invoked, then the variables are again
+set to their original values after the original major mode has been called.
+
+See also `so-long-mode-preserved-minor-modes' (processed before this)."
+  :type '(repeat variable)
+  :package-version '(so-long . "1.1"))
+
 (defcustom so-long-hook nil
   "List of functions to call after `so-long' is called.
 
@@ -942,10 +1000,17 @@ If RESET is non-nil, remove any existing values before 
storing the new ones."
     (setq so-long-original-values nil))
   (so-long-remember 'so-long-variable-overrides)
   (so-long-remember 'so-long-minor-modes)
+  (so-long-remember 'so-long-mode-preserved-variables)
+  (so-long-remember 'so-long-mode-preserved-minor-modes)
   (dolist (ovar so-long-variable-overrides)
     (so-long-remember (car ovar)))
   (dolist (mode so-long-minor-modes)
     (when (and (boundp mode) mode)
+      (so-long-remember mode)))
+  (dolist (var so-long-mode-preserved-variables)
+    (so-long-remember var))
+  (dolist (mode so-long-mode-preserved-minor-modes)
+    (when (and (boundp mode) mode)
       (so-long-remember mode))))
 
 (defun so-long-menu ()
@@ -1330,6 +1395,16 @@ This advice acts before `so-long-mode', with the 
previous mode still active."
   "Run by `so-long-mode' in `after-change-major-mode-hook'.
 
 Calls `so-long-disable-minor-modes' and `so-long-override-variables'."
+  ;; Check/set the state of 'preserved' variables and minor modes.
+  ;; (See also `so-long-mode-revert'.)
+  ;; The "modes before variables" sequence is important for the default
+  ;; preserved mode `view-mode' which remembers the `buffer-read-only' state
+  ;; (which is also permanent-local).  That causes problems unless we restore
+  ;; the original value of `view-old-buffer-read-only' after; otherwise the
+  ;; sequence `view-mode' -> `so-long' -> `so-long-revert' -> `view-mode'
+  ;; results in `view-mode' being disabled but the buffer still read-only.
+  (so-long-mode-maintain-preserved-minor-modes)
+  (so-long-mode-maintain-preserved-variables)
   ;; Disable minor modes.
   (so-long-disable-minor-modes)
   ;; Override variables (again).  We already did this in `so-long-mode' in
@@ -1374,7 +1449,7 @@ The variables are set in accordance with what was 
remembered in `so-long'."
   ;; In the instance where `so-long-mode-revert' has just reverted the major
   ;; mode, note that `kill-all-local-variables' was already called by the
   ;; original mode function, and so these 'overridden' variables may now have
-  ;; global rather than buffer-local values.
+  ;; global rather than buffer-local values (if they are not permanent-local).
   (let* ((remembered (so-long-original variable :exists))
          (originally-local (nth 2 remembered)))
     (if originally-local
@@ -1390,6 +1465,24 @@ The variables are set in accordance with what was 
remembered in `so-long'."
       ;; the old value as a buffer-local value, so we keep it simple.
       (kill-local-variable variable))))
 
+(defun so-long-mode-maintain-preserved-variables ()
+  "Set any 'preserved' variables.
+
+The variables are set in accordance with what was remembered in `so-long'."
+  (dolist (var (so-long-original 'so-long-mode-preserved-variables))
+    (so-long-restore-variable var)))
+
+(defun so-long-mode-maintain-preserved-minor-modes ()
+  "Enable or disable 'preserved' minor modes.
+
+The modes are set in accordance with what was remembered in `so-long'."
+  (dolist (mode (so-long-original 'so-long-mode-preserved-minor-modes))
+    (when (boundp mode)
+      (let ((original (so-long-original mode))
+            (current (symbol-value mode)))
+        (unless (equal current original)
+          (funcall mode (if original 1 0)))))))
+
 (defun so-long-mode-revert ()
   "Call the `major-mode' which was selected before `so-long-mode' replaced it.
 
@@ -1417,6 +1510,10 @@ This is the `so-long-revert-function' for 
`so-long-mode'."
     ;; `kill-all-local-variables' was already called by the original mode
     ;; function, so we may be seeing global values.
     (so-long-restore-variables)
+    ;; Check/set the state of 'preserved' variables and minor modes.
+    ;; (Refer to `so-long-after-change-major-mode' regarding the sequence.)
+    (so-long-mode-maintain-preserved-minor-modes)
+    (so-long-mode-maintain-preserved-variables)
     ;; Restore the mode line construct.
     (unless (derived-mode-p 'so-long-mode)
       (setq so-long-mode-line-info (so-long-mode-line-info)))))
diff --git a/test/lisp/so-long-tests/so-long-tests-helpers.el 
b/test/lisp/so-long-tests/so-long-tests-helpers.el
index ab4d9c6..822b2ce 100644
--- a/test/lisp/so-long-tests/so-long-tests-helpers.el
+++ b/test/lisp/so-long-tests/so-long-tests-helpers.el
@@ -43,7 +43,8 @@
     (cl-case action
       ('so-long-mode
        (should (eq major-mode 'so-long-mode))
-       (so-long-tests-assert-overrides))
+       (so-long-tests-assert-overrides)
+       (so-long-tests-assert-preserved))
       ('so-long-minor-mode
        (should (eq so-long-minor-mode t))
        (so-long-tests-assert-overrides))
@@ -62,7 +63,8 @@
     (cl-case action
       ('so-long-mode
        (should-not (eq major-mode 'so-long-mode))
-       (so-long-tests-assert-overrides-reverted))
+       (so-long-tests-assert-overrides-reverted)
+       (so-long-tests-assert-preserved))
       ('so-long-minor-mode
        (should-not (eq so-long-minor-mode t))
        (so-long-tests-assert-overrides-reverted))
@@ -90,6 +92,17 @@
     (when (boundp (car ovar))
       (should (equal (symbol-value (car ovar)) (cdr ovar))))))
 
+(defun so-long-tests-assert-preserved ()
+  "Assert that preserved modes and variables have their expected values."
+  (dolist (var so-long-mode-preserved-variables)
+    (when (boundp var)
+      (should (equal (symbol-value var)
+                     (alist-get var so-long-tests-memory)))))
+  (dolist (mode so-long-mode-preserved-minor-modes)
+    (when (boundp mode)
+      (should (equal (symbol-value mode)
+                     (alist-get mode so-long-tests-memory))))))
+
 (defun so-long-tests-remember ()
   "Remember the original states of modes and variables.
 
@@ -107,6 +120,14 @@ state against this remembered state."
   (dolist (mode so-long-minor-modes)
     (when (boundp mode)
       (push (cons mode (symbol-value mode))
+            so-long-tests-memory)))
+  (dolist (var so-long-mode-preserved-variables)
+    (when (boundp var)
+      (push (cons var (symbol-value var))
+            so-long-tests-memory)))
+  (dolist (mode so-long-mode-preserved-minor-modes)
+    (when (boundp mode)
+      (push (cons mode (symbol-value mode))
             so-long-tests-memory))))
 
 (provide 'so-long-tests-helpers)
diff --git a/test/lisp/so-long-tests/so-long-tests.el 
b/test/lisp/so-long-tests/so-long-tests.el
index 80f1c47..291ec9a 100644
--- a/test/lisp/so-long-tests/so-long-tests.el
+++ b/test/lisp/so-long-tests/so-long-tests.el
@@ -327,6 +327,58 @@
       (normal-mode)
       (should (eq major-mode 'so-long-mode)))))
 
+(ert-deftest so-long-tests-preserved-variables-and-modes ()
+  "Preserved variables and minor modes when using `so-long-mode'."
+  ;; Test the user options `so-long-mode-preserved-variables' and
+  ;; `so-long-mode-preserved-minor-modes'.  The minor mode `view-mode'
+  ;; is 'preserved' by default (using both options).
+  (with-temp-buffer
+    (display-buffer (current-buffer))
+    (insert "#!emacs\n")
+    (normal-mode)
+    ;; We enable `view-mode' before triggering `so-long'.
+    (insert (make-string (1+ so-long-threshold) ?x))
+    (view-mode 1)
+    (should (eq view-mode t))
+    (should (eq buffer-read-only t))
+    (so-long-tests-remember)
+    (let ((so-long-action 'so-long-mode)
+          (menu (so-long-menu)))
+      (so-long)
+      (so-long-tests-assert-active 'so-long-mode)
+      (should (eq view-mode t))
+      (should (eq buffer-read-only t))
+      ;; Revert.
+      (funcall (lookup-key menu [so-long-revert]))
+      (so-long-tests-assert-reverted 'so-long-mode)
+      (should (eq view-mode t))
+      (should (eq buffer-read-only t))
+      ;; Disable `view-mode'.  Note that without the preserved
+      ;; variables, the conflict between how `view-mode' and `so-long'
+      ;; each deal with the buffer's original `buffer-read-only' value
+      ;; would lead to a situation whereby the buffer would still be
+      ;; read-only after `view-mode' had been disabled.
+      (view-mode 0)
+      (should (eq view-mode nil))
+      (should (eq buffer-read-only nil))))
+  ;; Without `view-mode'.
+  (with-temp-buffer
+    (display-buffer (current-buffer))
+    (insert "#!emacs\n")
+    (normal-mode)
+    (insert (make-string (1+ so-long-threshold) ?x))
+    (should (eq view-mode nil))
+    (so-long-tests-remember)
+    (let ((so-long-action 'so-long-mode)
+          (menu (so-long-menu)))
+      (so-long)
+      (so-long-tests-assert-active 'so-long-mode)
+      (should (eq view-mode nil))
+      ;; Revert.
+      (funcall (lookup-key menu [so-long-revert]))
+      (so-long-tests-assert-reverted 'so-long-mode)
+      (should (eq view-mode nil)))))
+
 (ert-deftest so-long-tests-predicate ()
   "Custom predicate function."
   ;; Test the `so-long-predicate' user option.



reply via email to

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