summaryrefslogtreecommitdiff
path: root/lisp/so-long.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/so-long.el')
-rw-r--r--lisp/so-long.el225
1 files changed, 186 insertions, 39 deletions
diff --git a/lisp/so-long.el b/lisp/so-long.el
index f44d41dc5eb..7bf15e85dad 100644
--- a/lisp/so-long.el
+++ b/lisp/so-long.el
@@ -8,7 +8,7 @@
;; Keywords: convenience
;; Created: 23 Dec 2015
;; Package-Requires: ((emacs "24.4"))
-;; Version: 1.0
+;; Version: 1.1.1
;; This file is part of GNU Emacs.
@@ -50,16 +50,17 @@
;; performance further, as well as making the so-long activity more obvious to
;; the user. These kinds of minified files are typically not intended to be
;; edited, so not providing the usual editing mode in such cases will rarely be
-;; an issue. However, you can reinstate the original state of the buffer by
-;; calling `so-long-revert' (the key binding of which is advertised when the major
-;; mode change occurs). If you prefer that the major mode not be changed, you
-;; can customize the `so-long-minor-mode' action.
+;; an issue; however you can restore the buffer to its original state by calling
+;; `so-long-revert' (the key binding of which is advertised when the major mode
+;; change occurs). If you prefer that the major mode not be changed in the
+;; first place, there is a `so-long-minor-mode' action available, which you can
+;; select by customizing the `so-long-action' user option.
;;
;; The user options `so-long-action' and `so-long-action-alist' determine what
-;; actions `so-long' and `so-long-revert' will take. This allows you to configure
-;; alternative actions (including custom actions). As well as
-;; the major and minor mode actions provided by this library, `longlines-mode'
-;; is also supported by default as an alternative action.
+;; `so-long' and `so-long-revert' will do, enabling you to configure alternative
+;; actions (including custom actions). As well as the major and minor mode
+;; actions provided by this library, `longlines-mode' is also supported by
+;; default as an alternative action.
;;
;; Note that while the measures taken can improve performance dramatically when
;; dealing with such files, this library does not have any effect on the
@@ -127,9 +128,9 @@
;; Use M-x customize-group RET so-long RET
;; (or M-x so-long-customize RET)
;;
-;; The user options `so-long-target-modes', `so-long-threshold', and
-;; `so-long-max-lines' determine whether action will be taken automatically when
-;; visiting a file, and `so-long-action' determines what will be done.
+;; The user options `so-long-target-modes' and `so-long-threshold' determine
+;; whether action will be taken automatically when visiting a file, and
+;; `so-long-action' determines what will be done.
;; * Actions and menus
;; -------------------
@@ -152,7 +153,7 @@
;; * Files with a file-local 'mode'
;; --------------------------------
;; A file-local major mode is likely to be safe even if long lines are detected
-;; (as the author of the file would otherwise be unlikely to have set that mode),
+;; (the author of the file would otherwise be unlikely to have set that mode),
;; and so these files are treated as special cases. When a file-local 'mode' is
;; present, the function defined by the `so-long-file-local-mode-function' user
;; option is called. The default value will cause the `so-long-minor-mode'
@@ -213,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
@@ -287,8 +306,9 @@
;; the criteria for calling `so-long' in any given mode (plus its derivatives)
;; by setting buffer-local values for the variables in question. This includes
;; `so-long-predicate' itself, as well as any variables used by the predicate
-;; when determining the result. By default this means `so-long-max-lines',
-;; `so-long-skip-leading-comments', and `so-long-threshold'. E.g.:
+;; when determining the result. By default this means `so-long-threshold' and
+;; possibly also `so-long-max-lines' and `so-long-skip-leading-comments' (these
+;; latter two are not used by default starting from Emacs 28.1). E.g.:
;;
;; (add-hook 'js-mode-hook 'my-js-mode-hook)
;;
@@ -390,6 +410,14 @@
;; * Change Log:
;;
+;; 1.1.1 - Identical to 1.1, but fixing an incorrect GNU ELPA release.
+;; 1.1 - Utilise `buffer-line-statistics' in Emacs 28+, with the new
+;; `so-long-predicate' function `so-long-statistics-excessive-p'.
+;; - 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'.
@@ -442,13 +470,19 @@
(require 'cl-lib)
+;; Map each :package-version to the associated Emacs version.
+;; (This eliminates the need for explicit :version keywords on the
+;; custom definitions.)
(add-to-list 'customize-package-emacs-version-alist
- '(so-long ("1.0" . "27.1")))
+ '(so-long ("1.0" . "27.1")
+ ("1.1" . "28.1")))
-(defconst so-long--latest-version "1.0")
+(defconst so-long--latest-version "1.1")
+(declare-function buffer-line-statistics "fns.c" t t) ;; Emacs 28+
(declare-function longlines-mode "longlines")
(defvar longlines-mode)
+
(defvar so-long-enabled nil
;; This was initially a renaming of the old `so-long-mode-enabled' and
;; documented as "Set to nil to prevent `so-long' from being triggered
@@ -488,16 +522,24 @@
:prefix "so-long"
:group 'convenience)
-(defcustom so-long-threshold 250
+(defcustom so-long-threshold 10000
"Maximum line length permitted before invoking `so-long-function'.
-See `so-long-detected-long-line-p' for details."
+Line length is counted in either bytes or characters, depending on
+`so-long-predicate'.
+
+This is the only variable used to determine the presence of long lines if
+the `so-long-predicate' function is `so-long-statistics-excessive-p'."
:type 'integer
- :package-version '(so-long . "1.0"))
+ :package-version '(so-long . "1.1"))
-(defcustom so-long-max-lines 5
+(defcustom so-long-max-lines 500
"Number of non-blank, non-comment lines to test for excessive length.
+This option normally has no effect in Emacs versions >= 28.1, as the default
+`so-long-predicate' sees the entire buffer. Older versions of Emacs still make
+use of this option.
+
If nil then all lines will be tested, until either a long line is detected,
or the end of the buffer is reached.
@@ -507,11 +549,15 @@ be counted.
See `so-long-detected-long-line-p' for details."
:type '(choice (integer :tag "Limit")
(const :tag "Unlimited" nil))
- :package-version '(so-long . "1.0"))
+ :package-version '(so-long . "1.1"))
(defcustom so-long-skip-leading-comments t
"Non-nil to ignore all leading comments and whitespace.
+This option normally has no effect in Emacs versions >= 28.1, as the default
+`so-long-predicate' sees the entire buffer. Older versions of Emacs still make
+use of this option.
+
If the file begins with a shebang (#!), this option also causes that line to be
ignored even if it doesn't match the buffer's comment syntax, to ensure that
comments following the shebang will be ignored.
@@ -521,7 +567,7 @@ See `so-long-detected-long-line-p' for details."
:package-version '(so-long . "1.0"))
(defcustom so-long-target-modes
- '(prog-mode css-mode sgml-mode nxml-mode)
+ '(prog-mode css-mode sgml-mode nxml-mode fundamental-mode)
"`so-long' affects only these modes and their derivatives.
Our primary use-case is minified programming code, so `prog-mode' covers
@@ -534,7 +580,7 @@ files would prevent Emacs from handling them correctly."
;; Use 'symbol', as 'function' may be unknown => mismatch.
:type '(choice (repeat :tag "Specified modes" symbol)
(const :tag "All modes" t))
- :package-version '(so-long . "1.0"))
+ :package-version '(so-long . "1.1"))
(defcustom so-long-invisible-buffer-function #'so-long-deferred
"Function called in place of `so-long' when the buffer is not displayed.
@@ -566,7 +612,9 @@ the mentioned options might interfere with some intended processing."
(function :tag "Custom function"))
:package-version '(so-long . "1.0"))
-(defcustom so-long-predicate 'so-long-detected-long-line-p
+(defcustom so-long-predicate (if (fboundp 'buffer-line-statistics)
+ 'so-long-statistics-excessive-p
+ 'so-long-detected-long-line-p)
"Function, called after `set-auto-mode' to decide whether action is needed.
Only called if the major mode is a member of `so-long-target-modes'.
@@ -574,10 +622,14 @@ Only called if the major mode is a member of `so-long-target-modes'.
The specified function will be called with no arguments. If it returns non-nil
then `so-long' will be invoked.
-Defaults to `so-long-detected-long-line-p'."
- :type '(radio (const so-long-detected-long-line-p)
+Defaults to `so-long-statistics-excessive-p' starting from Emacs 28.1, or
+`so-long-detected-long-line-p' in earlier versions.
+
+Note that `so-long-statistics-excessive-p' requires Emacs 28.1 or later."
+ :type '(radio (const so-long-statistics-excessive-p)
+ (const so-long-detected-long-line-p)
(function :tag "Custom function"))
- :package-version '(so-long . "1.0"))
+ :package-version '(so-long . "1.1"))
;; Silence byte-compiler warning. `so-long-action-alist' is defined below
;; as a user option; but the definition sequence required for its setter
@@ -757,6 +809,7 @@ was established."
display-line-numbers-mode
flymake-mode
flyspell-mode
+ glasses-mode
goto-address-mode
goto-address-prog-mode
hi-lock-mode
@@ -776,6 +829,8 @@ was established."
hl-sexp-mode
idle-highlight-mode
rainbow-delimiters-mode
+ smartparens-mode
+ smartparens-strict-mode
)
;; It's not clear to me whether all of these would be problematic, but they
;; seemed like reasonable targets. Some are certainly excessive in smaller
@@ -800,7 +855,7 @@ disabled modes are re-enabled by calling them with the numeric argument 1.
Please submit bug reports to recommend additional modes for this list, whether
they are in Emacs core, GNU ELPA, or elsewhere."
:type '(repeat symbol) ;; not function, as may be unknown => mismatch.
- :package-version '(so-long . "1.0"))
+ :package-version '(so-long . "1.1"))
(defcustom so-long-variable-overrides
'((bidi-inhibit-bpa . t)
@@ -848,6 +903,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.
@@ -934,10 +1027,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 ()
@@ -1077,12 +1177,23 @@ serves the same purpose.")
;; We change automatically to faster code
;; And then I won't feel so mad
+(defun so-long-statistics-excessive-p ()
+ "Non-nil if the buffer contains a line longer than `so-long-threshold' bytes.
+
+This uses `buffer-line-statistics' (available from Emacs 28.1) to establish the
+longest line in the buffer (counted in bytes rather than characters).
+
+This is the default value of `so-long-predicate' in Emacs versions >= 28.1.
+\(In earlier versions `so-long-detected-long-line-p' is used by default.)"
+ (> (cadr (buffer-line-statistics))
+ so-long-threshold))
+
(defun so-long-detected-long-line-p ()
"Determine whether the current buffer contains long lines.
Following any initial comments and blank lines, the next N lines of the buffer
-will be tested for excessive length (where \"excessive\" means above
-`so-long-threshold', and N is `so-long-max-lines').
+will be tested for excessive length (where \"excessive\" means greater than
+`so-long-threshold' characters, and N is `so-long-max-lines').
Returns non-nil if any such excessive-length line is detected.
@@ -1090,7 +1201,9 @@ If `so-long-skip-leading-comments' is nil then the N lines will be counted
starting from the first line of the buffer. In this instance you will likely
want to increase `so-long-max-lines' to allow for possible comments.
-This is the default value of `so-long-predicate'."
+This is the default `so-long-predicate' function in Emacs versions < 28.1.
+\(Starting from 28.1, the default and recommended predicate function is
+`so-long-statistics-excessive-p', which is faster and sees the entire buffer.)"
(let ((count 0) start)
(save-excursion
(goto-char (point-min))
@@ -1185,13 +1298,14 @@ current buffer, and buffer-local values are assigned to variables in accordance
with `so-long-variable-overrides'.
This minor mode is a standard `so-long-action' option."
- nil nil nil
+ :lighter nil
(if so-long-minor-mode ;; We are enabling the mode.
(progn
;; Housekeeping. `so-long-minor-mode' might be invoked directly rather
;; than via `so-long', so replicate the necessary behaviours. The minor
;; mode also cares about whether `so-long' was already active, as we do
- ;; not want to remember values which were potentially overridden already.
+ ;; not want to remember values which were (potentially) overridden
+ ;; already.
(unless (or so-long--calling so-long--active)
(so-long--ensure-enabled)
(setq so-long--active t
@@ -1321,6 +1435,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
@@ -1334,14 +1458,15 @@ Calls `so-long-disable-minor-modes' and `so-long-override-variables'."
(defun so-long-disable-minor-modes ()
"Disable any active minor modes listed in `so-long-minor-modes'."
(dolist (mode (so-long-original 'so-long-minor-modes))
- (when (and (boundp mode) mode)
+ (when (and (boundp mode)
+ (symbol-value mode))
(funcall mode 0))))
(defun so-long-restore-minor-modes ()
"Restore the minor modes which were disabled.
The modes are enabled in accordance with what was remembered in `so-long'."
- (dolist (mode so-long-minor-modes)
+ (dolist (mode (so-long-original 'so-long-minor-modes))
(when (and (so-long-original mode)
(boundp mode)
(not (symbol-value mode)))
@@ -1356,7 +1481,7 @@ The modes are enabled in accordance with what was remembered in `so-long'."
"Restore the remembered values for the overridden variables.
The variables are set in accordance with what was remembered in `so-long'."
- (dolist (ovar so-long-variable-overrides)
+ (dolist (ovar (so-long-original 'so-long-variable-overrides))
(so-long-restore-variable (car ovar))))
(defun so-long-restore-variable (variable)
@@ -1364,7 +1489,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
@@ -1380,6 +1505,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.
@@ -1407,6 +1550,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)))))
@@ -1892,7 +2039,7 @@ If it appears in `%s', you should remove it."
(unless global-so-long-mode
(global-so-long-mode 1)))
(makunbound 'so-long-mode-enabled))
- ;; Update to version 1.N:
+ ;; Update to version 1.N from earlier versions:
;; (when (version< so-long-version "1.N") ...)
;;
;; All updates completed.