unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* linum.el: problem (bug ?) fix and improvement
@ 2011-05-07 14:50 Toru TSUNEYOSHI
  2011-05-12 13:58 ` Stefan Monnier
  0 siblings, 1 reply; 9+ messages in thread
From: Toru TSUNEYOSHI @ 2011-05-07 14:50 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2049 bytes --]

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)

[-- Attachment #2: linum.el.1.diff --]
[-- Type: text/x-patch, Size: 2768 bytes --]

--- 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))

[-- Attachment #3: linum.el.2.diff --]
[-- Type: text/x-patch, Size: 10826 bytes --]

--- 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)

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2011-05-14  1:53 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-07 14:50 linum.el: problem (bug ?) fix and improvement Toru TSUNEYOSHI
2011-05-12 13:58 ` Stefan Monnier
2011-05-12 17:21   ` Eli Zaretskii
2011-05-12 19:43     ` Stefan Monnier
2011-05-13 12:14   ` Toru TSUNEYOSHI
2011-05-13 14:15     ` Stefan Monnier
2011-05-13 15:55       ` Toru TSUNEYOSHI
2011-05-13 16:26         ` Stefan Monnier
2011-05-14  1:53           ` Toru TSUNEYOSHI

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).