[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
linum.el: problem (bug ?) fix and improvement
From: |
Toru TSUNEYOSHI |
Subject: |
linum.el: problem (bug ?) fix and improvement |
Date: |
Sat, 7 May 2011 23:50:28 +0900 |
Hello.
I sometimes use linum-mode, then I meet a problem.
It is displaying a wrong line number when there is an invisible line.
(I don't know the problem is a bug clearly, but it is trouble to me.)
Example:
====================================================================
In buffer (linum-mode is enabled).
1 abc
2 def
3 ghi
4 jkl
Make the 2nd line ("def\n") invisible (by `facemenu-set-invisible').
1 abc
2 ghi <= wrong
4 jkl
====================================================================
I fixed the problem.
the attached file: "linum-mode.el.1.diff"
(based on Emacs 23.3.)
(If the following additional improvement is unnecessary, please ignore.)
Additionally, I improved about invisible buffer string.
the attached file: "linum-mode.el.2.diff"
(including the above bug fix.)
(1) Indicating invisible line(s) by an underlined line number
when the following line(s) is/are invisible.
====================================================================
_1_ abc <= underline
3 ghi
4 jkl
====================================================================
(2) Indicating partial invisible string by a `strike-through' line
number when the line has partial invisible string.
====================================================================
_1_ abc
3 ghi
4 jkl
Make the 3rd line ("hi") invisible partially.
_1_ abc
-3- g <= strike-through
4 jkl
Make the 1st line ("ab") invisible partially.
-_1_- c <= underline and strike-through
-3- g
4 jkl
====================================================================
For the additional improvement,
check the new variable `linum-indicate-invis',
and eval the following, please.
(setq linum-indicate-invis t)
--- linum.el.orig 2011-01-09 02:45:14.000000000 +0900
+++ linum.el 2011-05-06 21:24:13.338622400 +0900
@@ -146,26 +146,38 @@
;; Create an overlay (or reuse an existing one) for each
;; line visible in this window, if necessary.
(while (and (not (eobp)) (<= (point) limit))
- (let* ((str (if fmt
- (propertize (format fmt line) 'face 'linum)
- (funcall linum-format line)))
- (visited (catch 'visited
- (dolist (o (overlays-in (point) (point)))
- (when (equal-including-properties
- (overlay-get o 'linum-str) str)
- (unless (memq o linum-overlays)
- (push o linum-overlays))
- (setq linum-available (delq o linum-available))
- (throw 'visited t))))))
- (setq width (max width (length str)))
- (unless visited
- (let ((ov (if (null linum-available)
- (make-overlay (point) (point))
- (move-overlay (pop linum-available) (point) (point)))))
- (push ov linum-overlays)
- (overlay-put ov 'before-string
- (propertize " " 'display `((margin left-margin)
,str)))
- (overlay-put ov 'linum-str str))))
+ (unless (and (invisible-p (point))
+ (catch 'invisible-p
+ (save-excursion
+ (let* ((inhibit-field-text-motion t)
+ (eol (line-end-position)))
+ (while (not (eolp))
+ (goto-char
+ (next-single-char-property-change
+ (point) 'invisible nil eol))
+ (unless (invisible-p (point))
+ (throw 'invisible-p nil)))
+ t)))) ; current line is invisible entirely ?
+ (let* ((str (if fmt
+ (propertize (format fmt line) 'face 'linum)
+ (funcall linum-format line)))
+ (visited (catch 'visited
+ (dolist (o (overlays-in (point) (point)))
+ (when (equal-including-properties
+ (overlay-get o 'linum-str) str)
+ (unless (memq o linum-overlays)
+ (push o linum-overlays))
+ (setq linum-available (delq o linum-available))
+ (throw 'visited t))))))
+ (setq width (max width (length str)))
+ (unless visited
+ (let ((ov (if (null linum-available)
+ (make-overlay (point) (point))
+ (move-overlay (pop linum-available) (point) (point)))))
+ (push ov linum-overlays)
+ (overlay-put ov 'before-string
+ (propertize " " 'display `((margin left-margin)
,str)))
+ (overlay-put ov 'linum-str str)))))
;; Text may contain those nasty intangible properties, but that
;; shouldn't prevent us from counting those lines.
(let ((inhibit-point-motion-hooks t))
--- linum.el.orig 2011-01-09 02:45:14.000000000 +0900
+++ linum.el 2011-05-07 23:06:51.062956400 +0900
@@ -58,6 +58,39 @@
"Face for displaying line numbers in the display margin."
:group 'linum)
+(defface linum-partial-text-invis
+ '((t (:inherit linum :strike-through t)))
+ "Face for displaying line numbers in the display margin.
+It is used only for a line which has the partial (not entire) invisible text."
+ :group 'linum)
+
+(defface linum-following-line-invis
+ '((t (:inherit linum :underline t)))
+ "Face for displaying line numbers in the display margin.
+It is used only for a line which has the following invisible line(s)."
+ :group 'linum)
+
+(defface linum-partial-text-and-following-line-invis
+ ;;'((t (:inherit (linum-partial-text-invis linum-following-line-invis)))) ;
NG
+ '((t (:inherit linum :strike-through t :underline t)))
+ "Face for displaying line numbers in the display margin.
+It is used only for a line which has the partial (not entire) invisible text
+and the following invisible line(s)."
+ :group 'linum)
+
+(defcustom linum-indicate-invis nil
+ "Whether to indicate invisibility by line number's face.
+
+A value of nil means don't indicate.
+A value of `partial-text' means do only for the partial text.
+A value of `following-line' means do only for the following line.
+A value of t means do both for the partial text and for the following line."
+ :type '(choice (const :tag "Don't indicate" nil)
+ (const :tag "Only for partial text" partial-text)
+ (const :tag "Only for the following line" following-line)
+ (const :tag "Both for partial text and for the following line"
t))
+ :group 'linum)
+
(defcustom linum-eager t
"Whether line numbers should be updated after each command.
The conservative setting `nil' might miss some buffer changes,
@@ -133,51 +166,200 @@
(defun linum-update-window (win)
"Update line numbers for the portion visible in window WIN."
- (goto-char (window-start win))
+ (goto-char (1- (window-end win t)))
+ (let ((inhibit-point-motion-hooks t))
+ (forward-line 0))
(let ((line (line-number-at-pos))
- (limit (window-end win t))
+ (limit (window-start win))
(fmt (cond ((stringp linum-format) linum-format)
((eq linum-format 'dynamic)
(let ((w (length (number-to-string
(count-lines (point-min) (point-max))))))
(concat "%" (number-to-string w) "d")))))
- (width 0))
+ (width 0)
+ (shortage 0)
+ bol-invis eol eol-invis invis orig-invis old-invis
+ (invis-list '((nil . 0)
+ (partial-text . 1)
+ (following-line . 2)
+ (partial-text-and-following-line . 3) ; (+ 1 2)
+ (whole-line . 6))) ; (+ 2 4), it may
hide `following-line'
+ (face-list `((nil . linum)
+ (partial-text
+ . ,(if (memq linum-indicate-invis '(t partial-text))
+ 'linum-partial-text-invis
+ 'linum))
+ (following-line
+ . ,(if (memq linum-indicate-invis '(t following-line))
+ 'linum-following-line-invis
+ 'linum))
+ (partial-text-and-following-line
+ . ,(or (cdr (assq linum-indicate-invis
+ '((nil . linum)
+ (t .
linum-partial-text-and-following-line-invis)
+ (partial-text .
linum-partial-text-invis)
+ (following-line .
linum-following-line-invis))))
+ 'linum))
+ ;;(whole-line . nil)
+ )))
(run-hooks 'linum-before-numbering-hook)
;; Create an overlay (or reuse an existing one) for each
;; line visible in this window, if necessary.
- (while (and (not (eobp)) (<= (point) limit))
- (let* ((str (if fmt
- (propertize (format fmt line) 'face 'linum)
- (funcall linum-format line)))
- (visited (catch 'visited
- (dolist (o (overlays-in (point) (point)))
- (when (equal-including-properties
- (overlay-get o 'linum-str) str)
- (unless (memq o linum-overlays)
- (push o linum-overlays))
- (setq linum-available (delq o linum-available))
- (throw 'visited t))))))
- (setq width (max width (length str)))
- (unless visited
- (let ((ov (if (null linum-available)
- (make-overlay (point) (point))
- (move-overlay (pop linum-available) (point) (point)))))
- (push ov linum-overlays)
- (overlay-put ov 'before-string
- (propertize " " 'display `((margin left-margin)
,str)))
- (overlay-put ov 'linum-str str))))
+ (while (and (zerop shortage) (<= limit (point)))
+ (let ((inhibit-point-motion-hooks t))
+ (setq bol-invis (invisible-p (point))
+ eol (line-end-position)
+ eol-invis (invisible-p eol)
+
+ ;; | bol-invis | (mol-invis) | eol-invis | -> | invis
|
+ ;;
|-----------+-------------+-----------+----+---------------------------------|
+ ;; | t | t | t | | whole-line
|
+ ;; | t | t | nil | | partial-text
|
+ ;; | t | nil | t | |
partial-text-and-following-line |
+ ;; | t | nil | nil | | partial-text
|
+ ;; | nil | t | t | |
partial-text-and-following-line |
+ ;; | nil | t | nil | | partial-text
|
+ ;; | nil | nil | t | | following-line
|
+ ;; | nil | nil | nil | | nil
|
+
+ invis (cond (bol-invis
+ ;; middle of line is invisible ?
+ (cond ((catch 'invisible-p
+ (while t
+ (goto-char
+ (next-single-char-property-change
+ (point) 'invisible nil eol))
+ (cond ((eolp)
+ (throw 'invisible-p t))
+ ((not (invisible-p (point)))
+ (throw 'invisible-p nil)))))
+ (cond (eol-invis
+ 'whole-line)
+ (t
+ 'partial-text)))
+ (t
+ (cond (eol-invis
+ 'partial-text-and-following-line)
+ (t
+ 'partial-text)))))
+ (t
+ ;; middle of line is invisible ?
+ (cond ((catch 'invisible-p
+ (while t
+ (goto-char
+ (next-single-char-property-change
+ (point) 'invisible nil eol))
+ (cond ((eolp)
+ (throw 'invisible-p nil))
+ ((invisible-p (point))
+ (throw 'invisible-p t)))))
+ (cond (eol-invis
+ 'partial-text-and-following-line)
+ (t
+ 'partial-text)))
+ (t
+ (cond (eol-invis
+ 'following-line)
+ (t
+ nil))))))
+ orig-invis invis
+ ;; consider the following line invisibility
+ invis (car (rassq (logior (cdr (assq invis invis-list))
+ (cdr (assq old-invis invis-list)))
+ invis-list)))
+ (forward-line 0))
+ (unless (eq invis 'whole-line)
+ (let* ((str (if fmt
+ (propertize (format fmt line)
+ 'face (cdr (assq invis face-list)))
+ (funcall linum-format line)))
+ (visited (catch 'visited
+ (dolist (o (overlays-in (point) (point)))
+ (when (equal-including-properties
+ (overlay-get o 'linum-str) str)
+ (unless (memq o linum-overlays)
+ (push o linum-overlays))
+ (setq linum-available (delq o linum-available))
+ (throw 'visited t))))))
+ (setq width (max width (length str)))
+ (unless visited
+ (let ((ov (if (null linum-available)
+ (make-overlay (point) (point))
+ (move-overlay (pop linum-available) (point) (point)))))
+ (push ov linum-overlays)
+ (overlay-put ov 'before-string
+ (propertize " " 'display `((margin left-margin)
,str)))
+ (overlay-put ov 'linum-str str)
+ (overlay-put ov 'linum-invis orig-invis)))))
+ (setq old-invis (if (eq invis 'whole-line) 'following-line nil))
;; Text may contain those nasty intangible properties, but that
;; shouldn't prevent us from counting those lines.
(let ((inhibit-point-motion-hooks t))
- (forward-line))
- (setq line (1+ line)))
+ (setq shortage (forward-line -1)))
+ (setq line (1- line)))
(set-window-margins win width (cdr (window-margins win)))))
(defun linum-after-change (beg end len)
;; update overlays on deletions, and after newlines are inserted
(when (or (= beg end)
(= end (point-max))
- (string-match-p "\n" (buffer-substring-no-properties beg end)))
+ (string-match-p "\n" (buffer-substring-no-properties beg end))
+ (if linum-indicate-invis
+ ;; overlay property `linum-invis' value and current `invis'
value are different ?
+ (save-excursion
+ (let ((inhibit-point-motion-hooks t)
+ bol-invis eol eol-invis invis orig-invis)
+ (goto-char beg)
+ (forward-line 0)
+ (setq orig-invis (catch 'linum-invis
+ (dolist (o (overlays-in (point) (point)))
+ (if (plist-member (overlay-properties
o) 'linum-invis)
+ (throw 'linum-invis (overlay-get o
'linum-invis))))
+ 'whole-line)
+ bol-invis (invisible-p (point))
+ eol (line-end-position)
+ eol-invis (invisible-p eol)
+ invis (cond (bol-invis
+ ;; middle of line is invisible ?
+ (cond ((catch 'invisible-p
+ (while t
+ (goto-char
+
(next-single-char-property-change
+ (point) 'invisible nil eol))
+ (cond ((eolp)
+ (throw 'invisible-p t))
+ ((not (invisible-p
(point)))
+ (throw 'invisible-p
nil)))))
+ (cond (eol-invis
+ 'whole-line)
+ (t
+ 'partial-text)))
+ (t
+ (cond (eol-invis
+
'partial-text-and-following-line)
+ (t
+ 'partial-text)))))
+ (t
+ ;; middle of line is invisible ?
+ (cond ((catch 'invisible-p
+ (while t
+ (goto-char
+
(next-single-char-property-change
+ (point) 'invisible nil eol))
+ (cond ((eolp)
+ (throw 'invisible-p
nil))
+ ((invisible-p (point))
+ (throw 'invisible-p
t)))))
+ (cond (eol-invis
+
'partial-text-and-following-line)
+ (t
+ 'partial-text)))
+ (t
+ (cond (eol-invis
+ 'following-line)
+ (t
+ nil)))))))
+ (not (eq orig-invis invis))))))
(linum-update-current)))
(defun linum-after-scroll (win start)
- linum.el: problem (bug ?) fix and improvement,
Toru TSUNEYOSHI <=