unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
@ 2019-10-07  1:04 Juanma Barranquero
  2019-10-07  3:42 ` Juanma Barranquero
  0 siblings, 1 reply; 11+ messages in thread
From: Juanma Barranquero @ 2019-10-07  1:04 UTC (permalink / raw)
  To: 37641


[-- Attachment #1.1: Type: text/plain, Size: 258 bytes --]

Quite easy to see with:

(setq display-line-numbers-major-tick 5)
(set-face-attribute 'line-number-major-tick nil :foreground "white"
:background "black")

and then just enable line numbers in *Scratch* and insert a few lines at
the end.

[image: image.png]

[-- Attachment #1.2: Type: text/html, Size: 452 bytes --]

[-- Attachment #2: image.png --]
[-- Type: image/png, Size: 5658 bytes --]

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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-07  1:04 bug#37641: major/minor tick faces bleed into empty lines at the end of buffer Juanma Barranquero
@ 2019-10-07  3:42 ` Juanma Barranquero
  2019-10-07 16:17   ` Eli Zaretskii
  0 siblings, 1 reply; 11+ messages in thread
From: Juanma Barranquero @ 2019-10-07  3:42 UTC (permalink / raw)
  To: 37641

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

This patch seems to fix the problem.

diff --git i/src/xdisp.c w/src/xdisp.c
index 563cf473cf..a2d605f3ea 100644
--- i/src/xdisp.c
+++ w/src/xdisp.c
@@ -22679,9 +22679,11 @@ maybe_produce_line_number (struct it *it)
   && it->what != IT_EOB)
  tem_it.face_id = current_lnum_face_id;
-      else if (display_line_numbers_major_tick > 0
+      else if (!beyond_zv
+       && display_line_numbers_major_tick > 0
        && (lnum_to_display % display_line_numbers_major_tick == 0))
  tem_it.face_id = merge_faces (it->w, Qline_number_major_tick,
       0, DEFAULT_FACE_ID);
-      else if (display_line_numbers_minor_tick > 0
+      else if (!beyond_zv
+       && display_line_numbers_minor_tick > 0
        && (lnum_to_display % display_line_numbers_minor_tick == 0))
  tem_it.face_id = merge_faces (it->w, Qline_number_minor_tick,

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

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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-07  3:42 ` Juanma Barranquero
@ 2019-10-07 16:17   ` Eli Zaretskii
  2019-10-08  2:38     ` Juanma Barranquero
  0 siblings, 1 reply; 11+ messages in thread
From: Eli Zaretskii @ 2019-10-07 16:17 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: 37641

> From: Juanma Barranquero <lekktu@gmail.com>
> Date: Mon, 7 Oct 2019 05:42:46 +0200
> 
> This patch seems to fix the problem.

Looks good, but please simplify by having 2-level if, the outer one
checking when to display a number, the inner which face to use for
that.  There's no need to test beyond_zv more than once, and AFAIR
beyond_zv and it->what == IT_EOB are equivalent.

Thanks.





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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-07 16:17   ` Eli Zaretskii
@ 2019-10-08  2:38     ` Juanma Barranquero
  2019-10-08  4:23       ` Juanma Barranquero
  2019-10-08  8:49       ` Eli Zaretskii
  0 siblings, 2 replies; 11+ messages in thread
From: Juanma Barranquero @ 2019-10-08  2:38 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 37641


[-- Attachment #1.1: Type: text/plain, Size: 2975 bytes --]

On Mon, Oct 7, 2019 at 6:17 PM Eli Zaretskii <eliz@gnu.org> wrote:

> Looks good, but please simplify by having 2-level if, the outer one
> checking when to display a number, the inner which face to use for
> that.  There's no need to test beyond_zv more than once, and AFAIR
> beyond_zv and it->what == IT_EOB are equivalent.

beyond_zv and it->what == IT_EOB are similar, but not equivalent. I see the
difference when deleting empty lines at the end of the buffer
(specifically, when deleting from the last line, and not past the last
line).

With the `what' check, the face still bleed info the first post-EOB line.
Checking beyond_zv it works (see attached images).

As for simplifying the check, it is possible to check beyond_zv only once,
with the minor downside of having two paths to set lnum_face (which works
as the default face, and the face post-EOB).

if (check for current line)  // checks also it->what != IT_EOB
   set face to current_lnum_face;
else if (beyond_zv)
   set face to lnum_face;  // 1
else if (check for major tick)
   set face to major_tick;
else if (check for minor tick)
   set face to minor_tick;
else
   set face to lnum_face;  // 2

BTW, if the "it->what != IT_EOB" comparison in the current line check can
indeed be changed to !beyond_zv (which seems to work, at least on my
tests), then you can go to

if (beyond_zv)
   set face to lnum_face;  // 1
else if (check for current line)  // does not check it->what != IT_EOB
   set face to current_lnum_face;
else if (check for major tick)
   set face to major_tick;
else if (check for minor tick)
   set face to minor_tick;
else
   set face to lnum_face; // 2

which is equally clean and saves another comparison.

And the nicest thing is that the patch is very clean (attached also because
Gmail as usual is screwing with it).

diff --git a/src/xdisp.c b/src/xdisp.c
index 29d49d57df..ad73981c1d 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -22662,13 +22662,14 @@ maybe_produce_line_number (struct it *it)
     {
       /* For continuation lines and lines after ZV, instead of a line
         number, produce a blank prefix of the same width.  */
-      if (lnum_face_id != current_lnum_face_id
-         && (EQ (Vdisplay_line_numbers, Qvisual)
-             ? this_line == 0
-             : this_line == it->pt_lnum)
-         /* Avoid displaying the line-number-current-line face on
-            empty lines beyond EOB.  */
-         && it->what != IT_EOB)
+      if (beyond_zv)
+       /* Avoid displaying any face other than line-number on
+          empty lines beyond EOB.  */
+       tem_it.face_id = lnum_face_id;
+      else if (lnum_face_id != current_lnum_face_id
+              && (EQ (Vdisplay_line_numbers, Qvisual)
+                  ? this_line == 0
+                  : this_line == it->pt_lnum))
        tem_it.face_id = current_lnum_face_id;
       else if (display_line_numbers_major_tick > 0
               && (lnum_to_display % display_line_numbers_major_tick == 0))

[-- Attachment #1.2: Type: text/html, Size: 3644 bytes --]

[-- Attachment #2: it_eob.png --]
[-- Type: image/png, Size: 4796 bytes --]

[-- Attachment #3: beyond_zv.png --]
[-- Type: image/png, Size: 5327 bytes --]

[-- Attachment #4: beyond.patch --]
[-- Type: application/octet-stream, Size: 1058 bytes --]

diff --git a/src/xdisp.c b/src/xdisp.c
index 29d49d57df..ad73981c1d 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -22662,13 +22662,14 @@ maybe_produce_line_number (struct it *it)
     {
       /* For continuation lines and lines after ZV, instead of a line
 	 number, produce a blank prefix of the same width.  */
-      if (lnum_face_id != current_lnum_face_id
-	  && (EQ (Vdisplay_line_numbers, Qvisual)
-	      ? this_line == 0
-	      : this_line == it->pt_lnum)
-	  /* Avoid displaying the line-number-current-line face on
-	     empty lines beyond EOB.  */
-	  && it->what != IT_EOB)
+      if (beyond_zv)
+	/* Avoid displaying any face other than line-number on
+	   empty lines beyond EOB.  */
+	tem_it.face_id = lnum_face_id;
+      else if (lnum_face_id != current_lnum_face_id
+	       && (EQ (Vdisplay_line_numbers, Qvisual)
+		   ? this_line == 0
+		   : this_line == it->pt_lnum))
 	tem_it.face_id = current_lnum_face_id;
       else if (display_line_numbers_major_tick > 0
 	       && (lnum_to_display % display_line_numbers_major_tick == 0))

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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-08  2:38     ` Juanma Barranquero
@ 2019-10-08  4:23       ` Juanma Barranquero
  2019-10-08  8:51         ` Eli Zaretskii
  2019-10-08  8:49       ` Eli Zaretskii
  1 sibling, 1 reply; 11+ messages in thread
From: Juanma Barranquero @ 2019-10-08  4:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 37641

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

As an aside, if it is safe to assume that the faces are not going to change
between digits of the line number, perhaps this change would be a gain.

It moves merging the tick faces outside the lnum_buf loop, and it is done
only for the right line numbers and when not beyond_zv.

diff --git i/src/xdisp.c w/src/xdisp.c
index ad73981c1d..2d79a42270 100644
--- i/src/xdisp.c
+++ w/src/xdisp.c
@@ -22657,6 +22657,21 @@ maybe_produce_line_number (struct it *it)
   int width_limit =
     tem_it.last_visible_x - tem_it.first_visible_x
     - 3 * FRAME_COLUMN_WIDTH (it->f);
+
+  /* Select face for tick line numbers, if needed */
+  int tick_face_id = -1;
+  if (!beyond_zv)
+    {
+      if (display_line_numbers_major_tick > 0
+     && (lnum_to_display % display_line_numbers_major_tick == 0))
+   tick_face_id = merge_faces (it->w, Qline_number_major_tick,
+                   0, DEFAULT_FACE_ID);
+      else if (display_line_numbers_minor_tick > 0
+          && (lnum_to_display % display_line_numbers_minor_tick == 0))
+   tick_face_id = merge_faces (it->w, Qline_number_minor_tick,
+                   0, DEFAULT_FACE_ID);
+    }
+
   /* Produce glyphs for the line number in a scratch glyph_row.  */
   for (const char *p = lnum_buf; *p; p++)
     {
@@ -22671,14 +22686,8 @@ maybe_produce_line_number (struct it *it)
           ? this_line == 0
           : this_line == it->pt_lnum))
    tem_it.face_id = current_lnum_face_id;
-      else if (display_line_numbers_major_tick > 0
-          && (lnum_to_display % display_line_numbers_major_tick == 0))
-   tem_it.face_id = merge_faces (it->w, Qline_number_major_tick,
-                     0, DEFAULT_FACE_ID);
-      else if (display_line_numbers_minor_tick > 0
-          && (lnum_to_display % display_line_numbers_minor_tick == 0))
-   tem_it.face_id = merge_faces (it->w, Qline_number_minor_tick,
-                     0, DEFAULT_FACE_ID);
+      else if (tick_face_id >= 0)
+   tem_it.face_id = tick_face_id;
       else
    tem_it.face_id = lnum_face_id;
       if (beyond_zv

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

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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-08  2:38     ` Juanma Barranquero
  2019-10-08  4:23       ` Juanma Barranquero
@ 2019-10-08  8:49       ` Eli Zaretskii
  2019-10-08  9:37         ` Juanma Barranquero
  1 sibling, 1 reply; 11+ messages in thread
From: Eli Zaretskii @ 2019-10-08  8:49 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: 37641

> From: Juanma Barranquero <lekktu@gmail.com>
> Date: Tue, 8 Oct 2019 04:38:18 +0200
> Cc: 37641@debbugs.gnu.org
> 
> > Looks good, but please simplify by having 2-level if, the outer one
> > checking when to display a number, the inner which face to use for
> > that.  There's no need to test beyond_zv more than once, and AFAIR
> > beyond_zv and it->what == IT_EOB are equivalent.
> 
> beyond_zv and it->what == IT_EOB are similar, but not equivalent. I see the difference when deleting empty
> lines at the end of the buffer (specifically, when deleting from the last line, and not past the last line).
> 
> With the `what' check, the face still bleed info the first post-EOB line. Checking beyond_zv it works (see
> attached images).

Sorry, I don't think I understand what the images show me.  They seem
identical.  Which face bleeds and where?  Please point out what should
I be looking at to understand the difference.

Did you try to arrange for the last line to be a multiple of one of
the ticks as well?  Also, what happens if you use the beyond_zv test
in all the conditions, or use the it->what test in all the conditions?

IOW, I don't understand why we need two different conditions regarding
EOB for displaying a number with different faces.  What am I missing?

> As for simplifying the check, it is possible to check beyond_zv only once, with the minor downside of having
> two paths to set lnum_face (which works as the default face, and the face post-EOB).

You could simply start with

  tem_it.face_id = lnum_face_id;

and then have a series of tests for replacing that with another face
ID; it would at least save you the 'else' clause.

Thanks.





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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-08  4:23       ` Juanma Barranquero
@ 2019-10-08  8:51         ` Eli Zaretskii
  0 siblings, 0 replies; 11+ messages in thread
From: Eli Zaretskii @ 2019-10-08  8:51 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: 37641

> From: Juanma Barranquero <lekktu@gmail.com>
> Date: Tue, 8 Oct 2019 06:23:36 +0200
> Cc: 37641@debbugs.gnu.org
> 
> As an aside, if it is safe to assume that the faces are not going to change between digits of the line number,
> perhaps this change would be a gain.

What does "between digits" mean?  While producing the glyphs for the
digits of a single line number, no faces can change, because no Lisp
is invoked.  Is that what you meant?

> It moves merging the tick faces outside the lnum_buf loop, and it is done only for the right line numbers and
> when not beyond_zv.

Yes, moving code out of the loop is a good idea.





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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-08  8:49       ` Eli Zaretskii
@ 2019-10-08  9:37         ` Juanma Barranquero
  2019-10-08 10:47           ` Juanma Barranquero
  0 siblings, 1 reply; 11+ messages in thread
From: Juanma Barranquero @ 2019-10-08  9:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 37641

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

  On Tue, Oct 8, 2019 at 10:50 AM Eli Zaretskii <eliz@gnu.org> wrote:

> Sorry, I don't think I understand what the images show me.  They seem
> identical.  Which face bleeds and where?  Please point out what should
> I be looking at to understand the difference.

In both images, the line numbered 19 is the last line in the buffer.

In the it_eob image, the "line" past the end of the buffer has an empty
number,
drawn with the major-tick face (but obviously without number). The rest of
non-lines,
until the end of the buffer, have their empty number drawn in the
line-number face.

In the beyond_zv image, the empty line after the end of the buffer is in the
line-number face, as all the other past that point. I think that's the
right behavior.

There's no reason for the line after the end of the buffer to be drawn with
the
major-tick face, even if it would be a major-tick line if it existed. It's
ugly.

> Did you try to arrange for the last line to be a multiple of one of
> the ticks as well?

In my examples? Yes, that's the whole point of the test: knowing what
happens when
the line after EOB would match a tick line number.

>  Also, what happens if you use the beyond_zv test
> in all the conditions

That's what I've done in the second patch I sent (applied after the first
one, not
alone). In my simple tests, everything works as expected.

> or use the it->what test in all the conditions?

I didn't try that, but as the first check (that uses it->what) is trying to
decide
whether to draw with the current-line-number, I don't think it is relevant
to
the problem I was trying to fix. It is relevant for consistency, of course.

> IOW, I don't understand why we need two different conditions regarding
> EOB for displaying a number with different faces.  What am I missing?

I don't know why (or if) the it->what check is necessary, instead of
beyond_zv.
I *know* that the other conditions (the ones affecting the choosing of tick
faces)
need beyond_zv, at least to get what I think is the right behavior (the one
in the
beyond_zv image). As said, I think that in fact it the first check can be
safely
replaced by !beyond_zv.

> You could simply start with
>
>   tem_it.face_id = lnum_face_id;
>
> and then have a series of tests for replacing that with another face
> ID; it would at least save you the 'else' clause.

Yes, good idea. Thanks.

> What does "between digits" mean?  While producing the glyphs for the
> digits of a single line number, no faces can change, because no Lisp
> is invoked.  Is that what you meant?

Yes, thanks. I expected as much, but the way the original code was written,
and
redisplay being notoriously tricky and an arcane art best left to wizards, I
though I was missing something (I'm not joking).

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

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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-08  9:37         ` Juanma Barranquero
@ 2019-10-08 10:47           ` Juanma Barranquero
  2019-10-09 10:22             ` Eli Zaretskii
  0 siblings, 1 reply; 11+ messages in thread
From: Juanma Barranquero @ 2019-10-08 10:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 37641


[-- Attachment #1.1: Type: text/plain, Size: 789 bytes --]

Turns out there's a difference after all. See the attached images. If you
move the
cursor past the EOB, with the beyond_zv check the line is drawn with the
line-number
face, not the line-number-current-line face. If we check with it->what !=
IT_EOB,
then the line-number-current-line face is used.

I think the right thing to do, when dealing with the "phantom line" just
past the EOB,
is to:
- Use line-number-current-line, if the cursor is there.
- Use the line-number face, and not the tick faces, if the cursor is not,
regardless
  of whether this phantom line would be a tick line or not if it were used.

So there's a patch that checks for tick faces with beyond_zv, for the
current line
face with it->what, and that moves all face setting for line numbers
entirely out of
the loop.

[-- Attachment #1.2: Type: text/html, Size: 924 bytes --]

[-- Attachment #2: bug-37641.patch --]
[-- Type: application/x-patch, Size: 2277 bytes --]

[-- Attachment #3: it_eob.png --]
[-- Type: image/png, Size: 4796 bytes --]

[-- Attachment #4: beyond_zv.png --]
[-- Type: image/png, Size: 5327 bytes --]

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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-08 10:47           ` Juanma Barranquero
@ 2019-10-09 10:22             ` Eli Zaretskii
  2019-10-09 10:39               ` Juanma Barranquero
  0 siblings, 1 reply; 11+ messages in thread
From: Eli Zaretskii @ 2019-10-09 10:22 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: 37641

> From: Juanma Barranquero <lekktu@gmail.com>
> Date: Tue, 8 Oct 2019 12:47:22 +0200
> Cc: 37641@debbugs.gnu.org
> 
> Turns out there's a difference after all. See the attached images. If you move the
> cursor past the EOB, with the beyond_zv check the line is drawn with the line-number
> face, not the line-number-current-line face. If we check with it->what != IT_EOB,
> then the line-number-current-line face is used.
> 
> I think the right thing to do, when dealing with the "phantom line" just past the EOB,
> is to:
> - Use line-number-current-line, if the cursor is there.
> - Use the line-number face, and not the tick faces, if the cursor is not, regardless
>   of whether this phantom line would be a tick line or not if it were used.

Agreed.

> So there's a patch that checks for tick faces with beyond_zv, for the current line
> face with it->what, and that moves all face setting for line numbers entirely out of
> the loop.

LGTM, thanks.





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

* bug#37641: major/minor tick faces bleed into empty lines at the end of buffer
  2019-10-09 10:22             ` Eli Zaretskii
@ 2019-10-09 10:39               ` Juanma Barranquero
  0 siblings, 0 replies; 11+ messages in thread
From: Juanma Barranquero @ 2019-10-09 10:39 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 37641-done

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

Closing. Fixed by this commit:

commit 4b06250ef1fe98a766938862912383d2ee051dfb
 Author: Juanma Barranquero <lekktu@gmail.com>
 Date:   2019-10-09 12:36:57 +0200

     Do not use tick faces beyond ZV (bug#37641)

     * src/xdisp.c (maybe_produce_line_number): Check beyond_zv
     before using a tick face for the line number.  Move all face
     selection code outside the loop that draws the line number.

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

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

end of thread, other threads:[~2019-10-09 10:39 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-10-07  1:04 bug#37641: major/minor tick faces bleed into empty lines at the end of buffer Juanma Barranquero
2019-10-07  3:42 ` Juanma Barranquero
2019-10-07 16:17   ` Eli Zaretskii
2019-10-08  2:38     ` Juanma Barranquero
2019-10-08  4:23       ` Juanma Barranquero
2019-10-08  8:51         ` Eli Zaretskii
2019-10-08  8:49       ` Eli Zaretskii
2019-10-08  9:37         ` Juanma Barranquero
2019-10-08 10:47           ` Juanma Barranquero
2019-10-09 10:22             ` Eli Zaretskii
2019-10-09 10:39               ` Juanma Barranquero

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