emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] scratch/so-long 1dee5b3 1/2: fixup! Add so-long library


From: Phil
Subject: [Emacs-diffs] scratch/so-long 1dee5b3 1/2: fixup! Add so-long library
Date: Fri, 14 Jun 2019 00:52:29 -0400 (EDT)

branch: scratch/so-long
commit 1dee5b3fe7f9e1fe8add8c60e04565287b89d4c6
Author: Phil Sainty <address@hidden>
Commit: Phil Sainty <address@hidden>

    fixup! Add so-long library
---
 lisp/so-long.el | 199 ++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 122 insertions(+), 77 deletions(-)

diff --git a/lisp/so-long.el b/lisp/so-long.el
index 0fb58dd..51fff68 100644
--- a/lisp/so-long.el
+++ b/lisp/so-long.el
@@ -62,12 +62,12 @@
 ;; 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 by this library can improve performance
-;; dramatically when dealing with such files, this library does not have any
-;; effect on the fundamental limitations of the Emacs redisplay code itself; 
and
-;; so if you do need to edit the file, performance may still degrade as you get
-;; deeper into the long lines.  In such circumstances you may find that
-;; `longlines-mode' is the most helpful facility.
+;; Note that while the measures taken can improve performance dramatically when
+;; dealing with such files, this library does not have any effect on the
+;; fundamental limitations of the Emacs redisplay code itself; and so if you do
+;; need to edit the file, performance may still degrade as you get deeper into
+;; the long lines.  In such circumstances you may find that `longlines-mode' is
+;; the most helpful facility.
 ;;
 ;; Note also that the mitigations are automatically triggered when visiting a
 ;; file.  The library does not automatically detect if long lines are inserted
@@ -220,7 +220,10 @@
 ;; If visiting a file is still taking a very long time with so-long enabled,
 ;; you should test the following command:
 ;;
-;; emacs -Q -l /path/to/so-long.el -f so-long-enable <file>
+;; emacs -Q -l so-long -f global-so-long-mode <file>
+;;
+;; For versions of Emacs < 27, use:
+;; emacs -Q -l /path/to/so-long.el -f global-so-long-mode <file>
 ;;
 ;; If the file loads quickly when that command is used, you'll know that
 ;; something in your personal configuration is causing problems.  If this
@@ -237,7 +240,7 @@
 ;;
 ;; If so-long itself is causing problems, it can be inhibited by setting the
 ;; `so-long-enabled' variable to nil, or by disabling the global mode with
-;; M-- M-x global-so-long-mode, or M-: (global-so-long-mode -1)
+;; M-- M-x global-so-long-mode, or M-: (global-so-long-mode 0)
 
 ;; * Example configuration
 ;; -----------------------
@@ -290,8 +293,11 @@
 ;; Another way to target individual files is to set a file-local `mode'
 ;; variable.  Refer to M-: (info "(emacs) Specifying File Variables") RET
 ;;
+;; `so-long-minor-mode' can also be called directly if desired.  e.g.:
+;; (add-hook 'FOO-mode-hook 'so-long-minor-mode)
+;;
 ;; In Emacs 26.1 or later (see "Caveats" below) you also have the option of
-;; using file-local and directory-local variables to determine how so-long
+;; using file-local and directory-local variables to determine how `so-long'
 ;; behaves.  e.g. -*- so-long-action: longlines-mode; -*-
 ;;
 ;; The buffer-local `so-long-function' and `so-long-revert-function' values may
@@ -388,6 +394,11 @@
 (declare-function longlines-mode "longlines")
 (defvar longlines-mode)
 
+(declare-function outline-next-visible-heading "outline")
+(declare-function outline-previous-visible-heading "outline")
+(declare-function outline-toggle-children "outline")
+(declare-function outline-toggle-children "outline")
+
 (defvar so-long-enabled nil
   "Set to nil to prevent `so-long' from being triggered automatically.
 
@@ -445,6 +456,10 @@ See `so-long-detected-long-line-p' for details."
 (defcustom so-long-skip-leading-comments t
   "Non-nil to ignore all leading comments and whitespace.
 
+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.
+
 See `so-long-detected-long-line-p' for details."
   :type 'boolean
   :package-version '(so-long . "1.0")
@@ -497,7 +512,7 @@ Defaults to `so-long-detected-long-line-p'."
           (const :tag "Do nothing" nil)))
 
 (defun so-long--action-alist-setter (option value)
-  "The :set function for `so-long-action-alist'."
+  "The customize :set function for `so-long-action-alist'."
   ;; Set the value as normal.
   (set-default option value)
   ;; Update the :type of `so-long-action' to present the updated values.
@@ -793,20 +808,25 @@ nil if no value was set, and a cons cell otherwise."
     (cadr (assq key so-long-original-values))))
 
 (defun so-long-remember (variable)
-  "Push the `symbol-value' for VARIABLE to `so-long-original-values'."
+  "Store the value of VARIABLE in `so-long-original-values'.
+
+We additionally store a boolean value which indicates whether that value was
+buffer-local."
   (when (boundp variable)
     (setq so-long-original-values
           (assq-delete-all variable so-long-original-values))
     (push (list variable
                 (symbol-value variable)
-                (consp (assq variable (buffer-local-variables))))
+                (local-variable-p variable))
           so-long-original-values)))
 
 (defun so-long-remember-all (&optional reset)
   "Remember the current variable and minor mode values.
 
-Stores the existing values for each entry in `so-long-variable-overrides' and
-`so-long-minor-modes'."
+Stores the existing value for each entry in `so-long-variable-overrides'.
+Stores the name of each enabled mode from the list `so-long-minor-modes'.
+
+If RESET is non-nil, remove any existing values before storing the new ones."
   (when reset
     (setq so-long-original-values nil))
   (dolist (ovar so-long-variable-overrides)
@@ -815,24 +835,6 @@ Stores the existing values for each entry in 
`so-long-variable-overrides' and
     (when (and (boundp mode) mode)
       (so-long-remember mode))))
 
-(defun so-long-change-major-mode ()
-  "Ensure that `so-long-mode' knows the original `major-mode'.
-
-If `so-long-mode' is called interactively, we additionally remember all the
-original variable and minor mode values (normally taken care of by `so-long'),
-so that these can still be restored by `so-long-revert'.
-
-Called during `change-major-mode-hook'."
-  (unless (or (minibufferp)
-              (derived-mode-p 'so-long-mode))
-    ;; Housekeeping.  `so-long-mode' might be invoked directly rather than
-    ;; via `so-long', so replicate the necessary behaviours.
-    (when (and (symbolp this-command)
-               (provided-mode-derived-p this-command 'so-long-mode))
-      (so-long-remember-all :reset))
-    ;; Remember the original major mode.
-    (so-long-remember 'major-mode)))
-
 (defun so-long-menu ()
   "Dynamically generate the \"So Long\" menu."
   ;; (info "(elisp) Menu Example")
@@ -851,9 +853,15 @@ Called during `change-major-mode-hook'."
           item
         (define-key-after map (vector key)
           `(menu-item
-            ,label (lambda ()
-                     (interactive)
-                     (so-long-menu-item-replace-action ',item))
+            ,label
+            ,(let ((sym (make-symbol "so-long-menu-item-replace-action")))
+               ;; Using a symbol here, so that `describe-key' on the menu item
+               ;; produces the `so-long-menu-item-replace-action' 
documentation.
+               (defalias sym
+                 (apply-partially #'so-long-menu-item-replace-action item)
+                 (documentation #'so-long-menu-item-replace-action))
+               (put sym 'interactive-form '(interactive))
+               sym)
             :enable (not (and so-long--active
                               (eq ',actionfunc so-long-function)
                               (eq ',revertfunc so-long-revert-function)))))))
@@ -912,9 +920,12 @@ REPLACEMENT is a `so-long-action-alist' item."
     (require 'finder)
     (cl-letf (((symbol-function 'finder-summary) #'ignore))
       (finder-commentary "so-long"))
-    (when (looking-at "^Commentary:\n\n")
-      (let ((inhibit-read-only t))
-        (replace-match "so-long.el\n\n")))
+    (let ((inhibit-read-only t))
+      (when (looking-at "^Commentary:\n\n")
+        (replace-match "so-long.el\n\n"))
+      (save-excursion
+        (while (re-search-forward "^-+$" nil :noerror)
+          (replace-match ""))))
     (rename-buffer buf)
     ;; Enable `outline-mode' and `view-mode' for user convenience.
     (outline-mode)
@@ -928,6 +939,7 @@ REPLACEMENT is a `so-long-action-alist' item."
       (set-keymap-parent map (current-local-map))
       (use-local-map map))
     ;; Display the So Long menu.
+    (so-long--ensure-enabled)
     (let ((so-long-action nil))
       (so-long))))
 
@@ -998,7 +1010,11 @@ This is the default value of `so-long-predicate'."
     (save-excursion
       (goto-char (point-min))
       (when so-long-skip-leading-comments
-        ;; Clears whitespace at minimum.
+        ;; Skip the shebang line, if any.  This is not necessarily comment
+        ;; syntax, so we need to treat it specially.
+        (when (looking-at "#!")
+          (forward-line 1))
+        ;; Move past any leading whitespace and/or comments.
         ;; We use narrowing to limit the amount of text being processed at any
         ;; given time, where possible, as this makes things more efficient.
         (setq start (point))
@@ -1021,8 +1037,11 @@ This is the default value of `so-long-predicate'."
                    ;; If there was whitespace, we moved past it.
                    (setq start (point)))))
         ;; We're at the first non-comment line, but we may have moved past
-        ;; indentation whitespace, so move back to the beginning of the line.
-        (forward-line 0))
+        ;; indentation whitespace, so move back to the beginning of the line
+        ;; unless we're at the end of the buffer (in which case there was no
+        ;; non-comment/whitespace content in the buffer at all).
+        (unless (eobp)
+          (forward-line 0)))
       ;; Start looking for long lines.
       ;; `while' will ultimately return nil if we do not `throw' a result.
       (catch 'excessive
@@ -1059,8 +1078,8 @@ This is the default value of `so-long-predicate'."
   (let ((state (so-long-original 'longlines-mode :exists)))
     (if state
         (unless (equal (cadr state) longlines-mode)
-          (longlines-mode (if (cadr state) 1 -1)))
-      (longlines-mode -1))))
+          (longlines-mode (if (cadr state) 1 0)))
+      (longlines-mode 0))))
 
 (defun turn-on-so-long-minor-mode ()
   "Enable minor mode `so-long-minor-mode'."
@@ -1068,7 +1087,7 @@ This is the default value of `so-long-predicate'."
 
 (defun turn-off-so-long-minor-mode ()
   "Disable minor mode `so-long-minor-mode'."
-  (so-long-minor-mode -1))
+  (so-long-minor-mode 0))
 
 ;;;###autoload
 (define-minor-mode so-long-minor-mode
@@ -1087,6 +1106,7 @@ This minor mode is a standard `so-long-action' option."
         ;; mode also cares about whether `so-long' was already active, as we do
         ;; 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
                 so-long-detected-p t
                 so-long-function 'turn-on-so-long-minor-mode
@@ -1133,9 +1153,8 @@ This minor mode is a standard `so-long-action' option."
 (define-derived-mode so-long-mode nil "So Long"
   "This major mode is the default `so-long-action' option.
 
-The normal reason for this mode being active is that `global-so-long-mode'
-is enabled, and `so-long-predicate' has detected that the file contains
-excessively-long lines.
+The normal reason for this mode being active is that `global-so-long-mode' is
+enabled, and `so-long-predicate' has detected that the file contains long 
lines.
 
 Many Emacs modes struggle with buffers which contain excessively long lines,
 and may consequently cause unacceptable performance issues.
@@ -1151,28 +1170,23 @@ for the current buffer, and buffer-local values are 
assigned to variables in
 accordance with `so-long-variable-overrides'.
 
 To restore the original major mode (along with the minor modes and variable
-values), despite potential performance issues, type \\[so-long-revert]."
+values), despite potential performance issues, type \\[so-long-revert].
+
+Use \\[so-long-commentary] for more information.
+
+Use \\[so-long-customize] to configure the behaviour."
   ;; Housekeeping.  `so-long-mode' might be invoked directly rather than via
   ;; `so-long', so replicate the necessary behaviours.  We could use this same
   ;; test in `so-long-after-change-major-mode' to run `so-long-hook', but 
that's
   ;; not so obviously the right thing to do, so I've omitted it for now.
   (unless so-long--calling
+    (so-long--ensure-enabled)
     (setq so-long--active t
           so-long-detected-p t
           so-long-function 'so-long-mode
-          so-long-revert-function 'so-long-mode-revert)
-    ;; Reset `so-long-original-values' with the exception of `major-mode' which
-    ;; has just been stored by `so-long-change-major-mode'.  If we are directly
-    ;; invoking `so-long-mode' interactively then that `change-major-mode-hook'
-    ;; function additionally stored all the original values, and we do not want
-    ;; to clobber any of them.
-    (unless (and (symbolp this-command)
-                 (provided-mode-derived-p this-command 'so-long-mode))
-      (let ((major (so-long-original 'major-mode :exists)))
-        (setq so-long-original-values
-              (if major (list major) nil)))))
+          so-long-revert-function 'so-long-mode-revert))
   ;; Use `after-change-major-mode-hook' to disable minor modes and override
-  ;; variables, so that we act after any globalized modes have acted.
+  ;; variables.  Append, to act after any globalized modes have acted.
   (add-hook 'after-change-major-mode-hook
             'so-long-after-change-major-mode :append :local)
   ;; Override variables.  This is the first of two instances where we do this
@@ -1195,6 +1209,27 @@ values), despite potential performance issues, type 
\\[so-long-revert]."
              (or (so-long-original 'major-mode) "<unknown>")
              (substitute-command-keys "\\[so-long-revert]"))))
 
+(defun so-long-change-major-mode ()
+  ;; Advice, enabled with:
+  ;; (advice-add 'so-long-mode :before #'so-long-change-major-mode)
+  ;;
+  ;; n.b. `major-mode-suspend' and `major-mode-restore' are new in Emacs 27, 
and
+  ;; related to what we're doing here; but it's not worth going to the effort 
of
+  ;; using those (conditionally, only for 27+) when we have our own framework
+  ;; for remembering and restoring this buffer state (amongst other things).
+  "Ensure that `so-long-mode' knows the original `major-mode'.
+
+This advice acts before `so-long-mode', with the previous mode still active."
+  (unless (derived-mode-p 'so-long-mode)
+    ;; Housekeeping.  `so-long-mode' might be invoked directly rather than
+    ;; via `so-long', so replicate the necessary behaviours.
+    (unless so-long--calling
+      (so-long-remember-all :reset))
+    ;; Remember the original major mode, regardless.
+    (so-long-remember 'major-mode)))
+
+(advice-add 'so-long-mode :before #'so-long-change-major-mode)
+
 (defun so-long-after-change-major-mode ()
   "Run by `so-long-mode' in `after-change-major-mode-hook'.
 
@@ -1477,6 +1512,7 @@ argument, select the action to use interactively."
                                 nil :require-match)))))
   (unless so-long--calling
     (let ((so-long--calling t))
+      (so-long--ensure-enabled)
       ;; ACTION takes precedence if supplied.
       (when action
         (setq so-long-function nil
@@ -1566,11 +1602,26 @@ Use \\[so-long-customize] to configure the behaviour."
   :global t
   :group 'so-long
   (if global-so-long-mode
-      (so-long--enable)
-    (so-long--disable)))
+      ;; Enable
+      (progn
+        (so-long--enable)
+        (advice-add 'hack-local-variables :around
+                    #'so-long--hack-local-variables)
+        (advice-add 'set-auto-mode :around
+                    #'so-long--set-auto-mode)
+        (when (< emacs-major-version 26)
+          (advice-add 'hack-one-local-variable :around
+                      #'so-long--hack-one-local-variable)))
+    ;; Disable
+    (so-long--disable)
+    (advice-remove 'hack-local-variables #'so-long--hack-local-variables)
+    (advice-remove 'set-auto-mode #'so-long--set-auto-mode)
+    (when (< emacs-major-version 26)
+      (advice-remove 'hack-one-local-variable
+                     #'so-long--hack-one-local-variable))))
 
 (put 'global-so-long-mode 'variable-documentation
-     "Non-nil if the so-long library's functionality is enabled.
+     "Non-nil if the so-long library's automated functionality is enabled.
 
 Use \\[so-long-commentary] for more information.
 
@@ -1578,14 +1629,13 @@ Setting this variable directly does not take effect;
 either customize it (see the info node `Easy Customization')
 or call the function `global-so-long-mode'.")
 
+(defun so-long--ensure-enabled ()
+  "Enable essential functionality, if not already enabled."
+  (unless so-long-enabled
+    (so-long--enable)))
+
 (defun so-long--enable ()
-  "Enable the so-long library's functionality."
-  (add-hook 'change-major-mode-hook 'so-long-change-major-mode)
-  (advice-add 'hack-local-variables :around #'so-long--hack-local-variables)
-  (advice-add 'set-auto-mode :around #'so-long--set-auto-mode)
-  (when (< emacs-major-version 26)
-    (advice-add 'hack-one-local-variable :around
-                #'so-long--hack-one-local-variable))
+  "Enable functionality other than `global-so-long-mode'."
   (add-to-list 'mode-line-misc-info '("" so-long-mode-line-info))
   (define-key-after (current-global-map) [menu-bar so-long]
     `(menu-item "So Long" nil
@@ -1597,19 +1647,14 @@ or call the function `global-so-long-mode'.")
   (setq so-long-enabled t))
 
 (defun so-long--disable ()
-  "Enable the so-long library's functionality."
-  (remove-hook 'change-major-mode-hook 'so-long-change-major-mode)
-  (advice-remove 'hack-local-variables #'so-long--hack-local-variables)
-  (advice-remove 'set-auto-mode #'so-long--set-auto-mode)
-  (when (< emacs-major-version 26)
-    (advice-remove 'hack-one-local-variable
-                   #'so-long--hack-one-local-variable))
+  "Disable functionality other than `global-so-long-mode'."
   (setq mode-line-misc-info
         (delete '("" so-long-mode-line-info) mode-line-misc-info))
   (define-key (current-global-map) [menu-bar so-long] nil)
   (setq so-long-enabled nil))
 
 (defun so-long-unload-function ()
+  "Handler for `unload-feature'."
   (global-so-long-mode 0)
   nil)
 



reply via email to

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