unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Kaushal Modi <kaushal.modi@gmail.com>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: code.falling@gmail.com, Emacs developers <emacs-devel@gnu.org>
Subject: Re: Patch to highlight current line number [nlinum.el]
Date: Mon, 18 Jul 2016 22:05:43 +0000	[thread overview]
Message-ID: <CAFyQvY0GeKh145SH1ep-9wbps4FsHEO3Sipw4Nhknd3wzs980A@mail.gmail.com> (raw)
In-Reply-To: <jwv60s23nj1.fsf-monnier+emacs@gnu.org>

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

Hi Stefan,

My comments are inline below, with a formatted patch at the end of this
email.

On Mon, Jul 18, 2016 at 1:06 PM Stefan Monnier <monnier@iro.umontreal.ca>
wrote:

> It looks like the (remove-text-properties last-line-beg last-line-end
> '(fontified)) doesn't do its job, indeed.  AFAICT it seems to work
> correctly when moving down but not when moving up, so maybe it's just an
> off-by-one error somewhere.
>

It works! I assumed incorrectly that line-beginning-position and
line-end-position accept negative arguments too. Fixed by doing
(save-excursion (forward-line diff) ..) before calling those.


> BTW, Elisp generally works better with positions than with line numbers.
> Is there a particular reason why you keep the nlinum--current-*
> (which I think of nlinum--last-*) as a line-number rather than as
> a buffer-position (probably a marker), or is it just how it turned out?
>

Using line numbers came just intuitively. I will anyways need to get line
numbers to calculate the line diffs. So I cannot think of a way using just
positions.

I'm asking because I'm thinking that without using markers it could
> prove tricky to de-highlight the right line-number after buffer
> modifications (since it could still say "line 178" for a little while
> (e.g. jit-lock-context-time) while it's actually now the 200th line).
> So I think a marker might work better.
>

I cannot get to recreate a scenario where the said failure would happen. I
tried evaluating:

(save-excursion (goto-line (- (line-number-at-pos) 2)) (insert
"a\nb\nc\nd"))

But the line number update was fine. Adding the line number update to
post-command-hook is helping, is seems.

Also, I do not know how to do it using just markers :)

Its usefulness as a global variable runs from the end of
> a call to nlinum--current-line-update to the beginning of the next.
> During that time it holds the line-number that was current in the
> last call.
>

I have not yet made this change. This seems like chicken-egg scenario. We
have references to the current line in nlinum-highlight-current-line,
nlinum-current-line (face), is-current-line let-bound var in
nlinum-format-function, nlinum--curent-line-update function.

=====
(defvar nlinum-format-function
  (lambda (line width)
    (let* ((is-current-line (= line nlinum--current-line))
=====

Also on doing C-h v nlinum--current-line, it actually shows the current
line number.

In nlinum--current-line-update, I have a let-bound last-line to store the
previous value of nlinum--current-line. If we rename nlinum--current-line
to nlinum--last-line, then all 'current' references I listed above will
have to become 'last'. But then nlinum-highlight-last-line and
nlinum-last-line face seem non-intuitive. And then the let-bound last-line
will have to have a name like prev-to-last-line. WDYT?


>
> >> +(defun nlinum--current-line-update ()
> >> > +  "Update current line number, flush text properties for last and
> current
> >> > line."
> >> Actually, it shouldn't (and doesn't) flush text-properties.  It should
> >> only update the current-line highlighting or cause it to be
> >> updated later.
> > I did not understand this too. I refer to the remove-text-properties
> action
> > as "flushing".
>
> That's an internal detail of how it works and if we change it to work
> differently there's no reason to think that it would affect the callers,
> so it needn't be documented in the docstring.
>
> And of course it doesn't "flush text properties": it flushes one
> particular property (this nitpick is actually the detail that made me
> re-read the docstring and think harder about what it said ;-).
>

Agreed. Thanks.

And the patch now follows. I believe we need agreement only on the naming
of nlinum--current-line.

=====

From e423adb3cf91d8a7623922e2de88d678d814e370 Mon Sep 17 00:00:00 2001
From: Kaushal Modi <kaushal.modi@gmail.com>
Date: Mon, 18 Jul 2016 17:42:45 -0400
Subject: [PATCH] Add ability to highlight current line number

* nlinum.el (nlinum-highlight-current-line): New defcustom to enable
highlighting current line number when non-nil (default is nil).
        (nlinum-current-line): New face for highlighting the current
line number.
---
 packages/nlinum/nlinum.el | 79
+++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 69 insertions(+), 10 deletions(-)

diff --git a/packages/nlinum/nlinum.el b/packages/nlinum/nlinum.el
index 98c9cbc..6e7429c 100644
--- a/packages/nlinum/nlinum.el
+++ b/packages/nlinum/nlinum.el
@@ -36,11 +36,27 @@

 ;;; Code:

-(require 'linum)                        ;For its face.
+(require 'linum) ; For its face.
+
+(defcustom nlinum-highlight-current-line nil
+  "Whether the current line number should be highlighted.
+When non-nil, the current line number is highlighted in
`nlinum-current-line'
+face. "
+  :group 'nlinum
+  :type 'boolean)

 (defvar nlinum--width 2)
 (make-variable-buffer-local 'nlinum--width)

+(defface nlinum-current-line
+  '((t :inherit linum :weight bold))
+  "Face for displaying current line."
+  :group 'nlinum)
+
+(defvar nlinum--current-line 0
+  "Store current line number.")
+(make-variable-buffer-local 'nlinum--current-line)
+
 ;; (defvar nlinum--desc "")

 ;;;###autoload
@@ -53,9 +69,10 @@ 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 t)
-  (remove-hook 'text-scale-mode-hook #'nlinum--setup-window t)
-  (remove-hook 'after-change-functions #'nlinum--after-change t)
+  (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)
   (kill-local-variable 'nlinum--line-number-cache)
   (remove-overlays (point-min) (point-max) 'nlinum t)
   ;; (kill-local-variable 'nlinum--ol-counter)
@@ -64,10 +81,13 @@ Linum mode is a buffer-local minor 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 t)
-    (add-hook 'window-configuration-change-hook #'nlinum--setup-window nil
t)
-    (add-hook 'after-change-functions #'nlinum--after-change nil t)
-    (jit-lock-register #'nlinum--region t))
+    (add-hook 'text-scale-mode-hook #'nlinum--setup-window nil :local)
+    (add-hook 'window-configuration-change-hook #'nlinum--setup-window nil
:local)
+    (add-hook 'after-change-functions #'nlinum--after-change nil :local)
+    (if nlinum-highlight-current-line
+        (add-hook 'post-command-hook #'nlinum--current-line-update nil
:local)
+      (remove-hook 'post-command-hook #'nlinum--current-line-update
:local))
+    (jit-lock-register #'nlinum--region :contextual))
   (nlinum--setup-windows))

 (defun nlinum--face-height (face)
@@ -131,6 +151,39 @@ Linum mode is a buffer-local minor mode."
                          (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
+                                 (unless (bolp)
+                                   (forward-line 0))
+                                 (nlinum--line-number-at-pos)))
+
+    ;; Remove the text properties only if the current line has changed.
+    (when (not (eq nlinum--current-line last-line))
+      (let* ((line-diff (- last-line nlinum--current-line))
+             (last-line-beg (save-excursion
+                              (forward-line line-diff)
+                              (line-beginning-position)))
+             (last-line-end (save-excursion
+                              (forward-line (1+ line-diff))
+                              (line-beginning-position)))
+             (curr-line-beg (line-beginning-position))
+             ;; Handle the case of blank lines too.
+             ;; Using the beginning of the next line ensures that the
+             ;; curr-line-end is not equal to curr-line-beg.
+             (curr-line-end (save-excursion
+                              (forward-line 1)
+                              (line-beginning-position))))
+        ;; (message "last:%d [%d,%d], curr:%d [%d,%d], line diff:%d"
+        ;;          last-line last-line-beg last-line-end
+        ;;          nlinum--current-line curr-line-beg curr-line-end
+        ;;          line-diff)
+
+        (with-silent-modifications
+          (remove-text-properties curr-line-beg curr-line-end '(fontified))
+          (remove-text-properties last-line-beg last-line-end
'(fontified)))))))
+
 ;; (defun nlinum--ol-count ()
 ;;   (let ((i 0))
 ;;     (dolist (ol (overlays-in (point-min) (point-max)))
@@ -215,11 +268,17 @@ Used by the default `nlinum-format-function'."

 (defvar nlinum-format-function
   (lambda (line width)
-    (let ((str (format nlinum-format line)))
+    (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 'linum 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
-- 
2.6.0.rc0.24.gec371ff

-- 

Kaushal Modi

[-- Attachment #2: Type: text/html, Size: 13950 bytes --]

  reply	other threads:[~2016-07-18 22:05 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-15 17:10 Patch to highlight current line number [nlinum.el] Kaushal Modi
2016-07-16  2:15 ` Stefan Monnier
2016-07-18  4:31   ` Kaushal Modi
2016-07-18 13:40     ` Stefan Monnier
2016-07-18 15:28       ` Kaushal Modi
2016-07-18 17:09         ` Stefan Monnier
2016-07-18 22:05           ` Kaushal Modi [this message]
2016-07-18 22:55             ` Kaushal Modi
2016-07-19  0:32             ` Stefan Monnier
2016-07-19  5:00               ` Kaushal Modi
2016-07-19 12:28                 ` Stefan Monnier
2016-07-19 12:40                   ` Kaushal Modi
2016-07-20 19:30                     ` Stefan Monnier
2016-07-20 19:38                       ` Kaushal Modi
2016-07-20 20:28                         ` Stefan Monnier
2016-07-20 20:31                           ` Kaushal Modi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAFyQvY0GeKh145SH1ep-9wbps4FsHEO3Sipw4Nhknd3wzs980A@mail.gmail.com \
    --to=kaushal.modi@gmail.com \
    --cc=code.falling@gmail.com \
    --cc=emacs-devel@gnu.org \
    --cc=monnier@iro.umontreal.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).