destroy history to get the thing pushed
This commit is contained in:
commit
50e4b47d01
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/nlinum-pkg.el
|
||||
/nlinum-autoloads.el
|
||||
*.elc
|
394
nlinum.el
Normal file
394
nlinum.el
Normal 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
|
Loading…
Reference in New Issue
Block a user