summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Sainty <psainty@orcon.net.nz>2021-01-17 01:25:13 +1300
committerPhil Sainty <psainty@orcon.net.nz>2021-03-21 16:23:12 +1300
commit31843e5eaadb3aee3ee3cb2a13838973dd185203 (patch)
treeef7c95570dd7149934b5c246fcbf83ef7df06e6a
parent6edeae3b4b7dd5105c9cf0dc0560d4c2c96a85bd (diff)
downloademacs-31843e5eaadb3aee3ee3cb2a13838973dd185203.tar.gz
WIP: Use `buffer-line-statistics'
-rw-r--r--etc/NEWS10
-rw-r--r--lisp/so-long.el59
2 files changed, 53 insertions, 16 deletions
diff --git a/etc/NEWS b/etc/NEWS
index fb4e8a03c4f..3f390b97712 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2235,9 +2235,17 @@ defines an additional key to exit mode like 'isearch-exit' ('RET').
** So Long
---
+*** New 'so-long-predicate' function 'so-long-statistics-excessive-p'
+efficiently detects the presence of a long line anywhere in the buffer
+using 'buffer-line-statistics' (see above). This is now the default
+predicate (replacing 'so-long-detected-long-line-p').
+
+---
*** 'so-long-threshold' and 'so-long-max-lines' have been raised to
10000 characters and 500 lines respectively, to reduce the likelihood
-of false-positives when 'global-so-long-mode' is enabled.
+of false-positives when 'global-so-long-mode' is enabled. The latter
+value is now only used by the old predicate, as the new predicate
+knows the longest line in the entire buffer.
---
*** 'so-long-target-modes' now includes 'fundamental-mode' by default,
diff --git a/lisp/so-long.el b/lisp/so-long.el
index 79d0d347f80..833c4b45295 100644
--- a/lisp/so-long.el
+++ b/lisp/so-long.el
@@ -128,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
;; -------------------
@@ -306,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)
;;
@@ -409,7 +410,9 @@
;; * Change Log:
;;
-;; 1.1 - Increase `so-long-threshold' from 250 to 10,000.
+;; 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'.
@@ -472,8 +475,10 @@
(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
@@ -516,7 +521,8 @@
(defcustom so-long-threshold 10000
"Maximum line length permitted before invoking `so-long-function'.
-See `so-long-detected-long-line-p' for details."
+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.1"))
@@ -591,7 +597,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'.
@@ -599,10 +607,12 @@ 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, or
+`so-long-detected-long-line-p' in earlier versions."
+ :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
@@ -1149,12 +1159,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.
@@ -1162,7 +1183,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))
@@ -2000,7 +2023,13 @@ If it appears in `%s', you should remove it."
(makunbound 'so-long-mode-enabled))
;; Update to version 1.1 from earlier versions:
(when (version< so-long-version "1.1")
- (add-to-list 'so-long-target-modes 'fundamental-mode))
+ (add-to-list 'so-long-target-modes 'fundamental-mode)
+ (let ((saved (eval (car (get 'so-long-predicate 'saved-value))))
+ (standard (eval (car (get 'so-long-predicate 'standard-value)))))
+ (when (and (eq standard 'so-long-statistics-excessive-p)
+ (or (not saved)
+ (eq saved 'so-long-detected-long-line-p)))
+ (setq so-long-predicate standard))))
;; Update to version 1.N:
;; (when (version< so-long-version "1.N") ...)
;;