destroy history to get the thing pushed

This commit is contained in:
Miranda Marquez 2024-07-18 12:11:29 -08:00
commit 50e4b47d01
2 changed files with 397 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/nlinum-pkg.el
/nlinum-autoloads.el
*.elc

394
nlinum.el Normal file
View File

@ -0,0 +1,394 @@
;;; nlinum.el --- Show line numbers in the margin -*- lexical-binding: t -*-
;; Copyright (C) 2012, 2014-2019 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Keywords: convenience
;; Version: 1.9
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; This is like linum-mode, but uses jit-lock to be (hopefully)
;; more efficient.
;;;; News:
;; v1.9:
;; - Add `nlinu-widen'.
;; v1.8:
;; - Add `nlinum-use-right-margin'.
;; v1.7:
;; - Add ability to highlight current line number.
;; - New custom variable `nlinum-highlight-current-line' and
;; face `nlinum-current-line'.
;; - New `nlinum' group in Custom.
;; v1.3:
;; - New custom variable `nlinum-format'.
;; - Change in calling convention of `nlinum-format-function'.
;; v1.2:
;; - New global mode `global-nlinum-mode'.
;; - New config var `nlinum-format-function'.
;;;; Known bugs:
;; - When narrowed, there can be a "bogus" line number that appears at the
;; very end of the buffer.
;; - After widening, the current line's number may stay stale until the
;; next command.
;;; Code:
(defgroup nlinum nil
"Show line numbers in the margin, (hopefully) more efficiently."
:group 'convenience
:group 'linum
:prefix "nlinum")
(defcustom nlinum-highlight-current-line nil
;; FIXME: It would be good to enable it by default, but only once we make it
;; work right with multiple-windows.
"Whether the current line number should be highlighted.
When non-nil, the current line number is highlighted in `nlinum-current-line'
face."
:type 'boolean)
(defcustom nlinum-widen nil
"If nil, count lines within the current narrowing only."
:type 'boolean)
(defface nlinum-current-line
'((t :inherit (shadow default)))
"Face for displaying current line.")
(defvar nlinum--width 2)
(make-variable-buffer-local 'nlinum--width)
(defvar nlinum--current-line 0
"Store current line number.")
(make-variable-buffer-local 'nlinum--current-line)
(defcustom nlinum-use-right-margin nil
"If non-nil, put line numbers in the right margin instead of the left one."
:type 'boolean)
;; (defvar nlinum--desc "")
(defvar nlinum--using-right-margin nil)
(make-variable-buffer-local 'nlinum--using-right-margin)
;;;###autoload
(define-minor-mode nlinum-mode
"Toggle display of line numbers in the left margin (Linum mode).
With a prefix argument ARG, enable Linum mode if ARG is positive,
and disable it otherwise. If called from Lisp, enable the mode
if ARG is omitted or nil.
Linum mode is a buffer-local minor mode."
:lighter nil ;; (" NLinum" nlinum--desc)
(jit-lock-unregister #'nlinum--region)
(remove-hook 'window-configuration-change-hook #'nlinum--setup-window :local)
(remove-hook 'text-scale-mode-hook #'nlinum--setup-window :local)
(remove-hook 'after-change-functions #'nlinum--after-change :local)
(remove-hook 'post-command-hook #'nlinum--current-line-update :local)
(remove-hook 'pre-redisplay-functions #'nlinum--check-narrowing :local)
(kill-local-variable 'nlinum--line-number-cache)
(kill-local-variable 'nlinum--last-point-min)
(remove-overlays (point-min) (point-max) 'nlinum t)
;; (kill-local-variable 'nlinum--ol-counter)
(kill-local-variable 'nlinum--width)
(when (and (local-variable-p 'nlinum--using-right-margin)
(not (eq nlinum--using-right-margin nlinum-use-right-margin)))
;; Remove outdated margins as well as margin annotations.
(let ((nlinum-mode nil)) (nlinum--flush))
(kill-local-variable 'nlinum--using-right-margin))
(setq nlinum--using-right-margin nlinum-use-right-margin)
(when nlinum-mode
;; FIXME: Another approach would be to make the mode permanent-local,
;; which might indeed be preferable.
(add-hook 'change-major-mode-hook (lambda () (nlinum-mode -1)))
(add-hook 'text-scale-mode-hook #'nlinum--setup-window nil :local)
(add-hook 'window-configuration-change-hook #'nlinum--setup-window nil t)
(add-hook 'after-change-functions #'nlinum--after-change nil :local)
(add-hook 'pre-redisplay-functions #'nlinum--check-narrowing nil :local)
(if nlinum-highlight-current-line
(add-hook 'post-command-hook #'nlinum--current-line-update nil :local))
(jit-lock-register #'nlinum--region :contextual))
(nlinum--setup-windows))
(defun nlinum--face-height (face)
(aref (font-info (face-font face)) 3))
(defun nlinum--face-width (face) ;New info only in Emacs>=25.
(let ((fi (font-info (face-font face))))
(when (> (length fi) 11)
(let ((width (aref fi 11)))
(if (<= width 0)
(aref fi 10)
width)))))
(defun nlinum--setup-window ()
;; FIXME: The interaction between different uses of the margin is
;; problematic. We should have a way for different packages to indicate (and
;; change) their preference independently.
(let* ((width (if (display-graphic-p)
(ceiling
(let ((width (nlinum--face-width 'linum)))
(if width
(/ (* nlinum--width 1.0 width)
(frame-char-width))
(/ (* nlinum--width 1.0
(nlinum--face-height 'linum))
(frame-char-height)))))
nlinum--width))
(cur-margins (window-margins))
(cur-margin (if nlinum--using-right-margin
(cdr cur-margins) (car cur-margins)))
;; (EXT . OURS) keeps track of the size of the margin, where EXT is the
;; size chosen by external code and OURS is the size we last set.
;; OURS is used to detect when someone else modifies the margin.
(margin-settings (window-parameter nil 'linum--margin)))
(if margin-settings
(unless (eq (cdr margin-settings) cur-margin)
;; Damn! The margin is not what it used to be! => Update EXT!
(setcar margin-settings cur-margin))
(set-window-parameter nil 'linum--margin
(setq margin-settings (list cur-margin))))
(and (car margin-settings) width
(setq width (max width (car margin-settings))))
(setcdr margin-settings width)
(apply #'set-window-margins nil
(let ((new-margin (if nlinum-mode width (car margin-settings))))
(if nlinum--using-right-margin
(list (car cur-margins) new-margin)
(list new-margin (cdr cur-margins)))))))
(defun nlinum--setup-windows ()
(dolist (win (get-buffer-window-list nil nil t))
(with-selected-window win (nlinum--setup-window))))
(defun nlinum--flush ()
(nlinum--setup-windows)
(save-excursion
(save-restriction
(widen)
;; (kill-local-variable 'nlinum--ol-counter)
(remove-overlays (point-min) (point-max) 'nlinum t)
(run-with-timer 0 nil
(lambda (buf)
(with-current-buffer buf
(with-silent-modifications
;; FIXME: only remove `fontified' on those parts of
;; the buffer that had an nlinum overlay!
(save-excursion
(save-restriction
(widen)
(remove-text-properties
(point-min) (point-max) '(fontified)))))))
(current-buffer)))))
(defun nlinum--current-line-update ()
"Update current line number."
(let ((last-line nlinum--current-line))
(setq nlinum--current-line (save-excursion
(forward-line 0)
(nlinum--line-number-at-pos)))
(let ((line-diff (- last-line nlinum--current-line))
beg end)
;; Remove the text properties only if the current line has changed.
(when (not (zerop line-diff))
(if (natnump line-diff)
;; Point is moving upward.
(progn
(setq beg (line-beginning-position))
(setq end (line-end-position (1+ line-diff))))
;; Point is moving downward.
(setq beg (line-beginning-position (1+ line-diff)))
(setq end (line-end-position)))
;; (message "curr-line:%d [beg/end:%d/%d] -- last-line:%d"
;; nlinum--current-line beg end last-line)
(with-silent-modifications
(remove-text-properties beg
;; Handle the case of blank lines too.
(min (point-max) (1+ end))
'(fontified)))))))
;; (defun nlinum--ol-count ()
;; (let ((i 0))
;; (dolist (ol (overlays-in (point-min) (point-max)))
;; (when (overlay-get ol 'nlinum) (incf i)))
;; i))
;; (defvar nlinum--ol-counter 100)
;; (make-variable-buffer-local 'nlinum--ol-counter)
;; (defun nlinum--flush-overlays (buffer)
;; (with-current-buffer buffer
;; (kill-local-variable 'nlinum--ol-counter)
;; ;; We've created many overlays in this buffer, which can slow
;; ;; down operations significantly. Let's flush them.
;; ;; An easy way to flush them is
;; ;; (remove-overlays min max 'nlinum t)
;; ;; (put-text-property min max 'fontified nil)
;; ;; but if the visible part of the buffer requires more than
;; ;; nlinum-overlay-threshold overlays, then we'll inf-loop.
;; ;; So let's be more careful about removing overlays.
;; (let ((windows (get-buffer-window-list nil nil t))
;; (start (point-min))
;; (debug-count (nlinum--ol-count)))
;; (with-silent-modifications
;; (while (< start (point-max))
;; (let ((end (point-max)))
;; (dolist (window windows)
;; (cond
;; ((< start (1- (window-start window)))
;; (setq end (min (1- (window-start window)) end)))
;; ((< start (1+ (window-end window)))
;; (setq start (1+ (window-end window))))))
;; (when (< start end)
;; (remove-overlays start end 'nlinum t)
;; ;; Warn jit-lock that this part of the buffer is not done any
;; ;; more. This has the downside that font-lock will be re-applied
;; ;; as well. But jit-lock doesn't know how to (and doesn't want
;; ;; to) keep track of the status of its various
;; ;; clients independently.
;; (put-text-property start end 'fontified nil)
;; (setq start (+ end 1))))))
;; (let ((debug-new-count (nlinum--ol-count)))
;; (message "Flushed %d overlays, %d remaining"
;; (- debug-count debug-new-count) debug-new-count)))))
(defvar nlinum--line-number-cache nil)
(make-variable-buffer-local 'nlinum--line-number-cache)
;; We could try and avoid flushing the cache at every change, e.g. with:
;; (defun nlinum--before-change (start _end)
;; (if (and nlinum--line-number-cache
;; (< start (car nlinum--line-number-cache)))
;; (save-excursion (goto-char start) (nlinum--line-number-at-pos))))
;; But it's far from clear that it's worth the trouble. The current simplistic
;; approach seems to be good enough in practice.
(defun nlinum--after-change (&rest _args)
(setq nlinum--line-number-cache nil))
(defvar nlinum--last-point-min nil)
(make-variable-buffer-local 'nlinum--last-point-min)
(defun nlinum--check-narrowing (&optional _win)
;; FIXME: We should also flush if nlinum-widen was changed.
;; Note: if nlinum-widen is t the flush is still needed when
;; point-min is/was in the middle of a line.
(unless (eql nlinum--last-point-min (point-min))
(unless nlinum-widen (setq nlinum--line-number-cache nil))
(nlinum--current-line-update)
(setq nlinum--last-point-min (point-min))
(nlinum--flush)))
(defun nlinum--line-number-at-pos ()
"Like `line-number-at-pos' but sped up with a cache.
Only works right if point is at BOL."
;; (cl-assert (bolp))
(if nlinum-widen
(save-excursion
(save-restriction
(widen)
(forward-line 0) ;In case (point-min) was not at BOL.
(let ((nlinum-widen nil))
(nlinum--line-number-at-pos))))
(let ((pos
(if (and nlinum--line-number-cache
(> (- (point) (point-min))
(abs (- (point) (car nlinum--line-number-cache)))))
(funcall (if (> (point) (car nlinum--line-number-cache))
#'+ #'-)
(cdr nlinum--line-number-cache)
(count-lines (point) (car nlinum--line-number-cache)))
(line-number-at-pos))))
;;(assert (= pos (line-number-at-pos)))
(setq nlinum--line-number-cache (cons (point) pos))
pos)))
(defcustom nlinum-format "%d"
"Format of the line numbers.
Used by the default `nlinum-format-function'."
:type 'string
:group 'linum)
(defvar nlinum-format-function
(lambda (line width)
(let* ((is-current-line (= line nlinum--current-line))
(str (format nlinum-format line)))
(when (< (length str) width)
;; Left pad to try and right-align the line-numbers.
(setq str (concat (make-string (- width (length str)) ?\ ) str)))
(put-text-property 0 width 'face
(if (and nlinum-highlight-current-line
is-current-line)
'nlinum-current-line
'linum)
str)
str))
"Function to build the string representing the line number.
Takes 2 arguments LINE and WIDTH, both of them numbers, and should return
a string. WIDTH is the ideal width of the result. If the result is larger,
it may cause the margin to be resized and line numbers to be recomputed.")
(defun nlinum--region (start limit)
(save-excursion
;; Text may contain those nasty intangible properties, but
;; that shouldn't prevent us from counting those lines.
(let ((inhibit-point-motion-hooks t))
(goto-char start)
(unless (bolp) (forward-line 1))
(remove-overlays (point) limit 'nlinum t)
(let ((line (nlinum--line-number-at-pos)))
(while
(and (not (eobp)) (< (point) limit)
(let* ((ol (make-overlay (point) (1+ (point))))
(str (funcall nlinum-format-function
line nlinum--width))
(width (string-width str))
(margin (if nlinum--using-right-margin
'right-margin 'left-margin)))
(when (< nlinum--width width)
(setq nlinum--width width)
(nlinum--flush))
(overlay-put ol 'nlinum t)
(overlay-put ol 'evaporate t)
(overlay-put ol 'before-string
(propertize " " 'display
`((margin ,margin) ,str)))
;; (setq nlinum--ol-counter (1- nlinum--ol-counter))
;; (when (= nlinum--ol-counter 0)
;; (run-with-idle-timer 0.5 nil #'nlinum--flush-overlays
;; (current-buffer)))
(setq line (1+ line))
(zerop (forward-line 1))))))))
;; (setq nlinum--desc (format "-%d" (nlinum--ol-count)))
nil)
;;;###autoload
(define-globalized-minor-mode global-nlinum-mode nlinum-mode
(lambda () (unless (minibufferp) (nlinum-mode))))
(provide 'nlinum)
;;; nlinum.el ends here