diff options
| author | Eli Zaretskii <eliz@gnu.org> | 2026-05-28 18:36:11 +0300 |
|---|---|---|
| committer | Eli Zaretskii <eliz@gnu.org> | 2026-05-28 18:36:11 +0300 |
| commit | 7ee33143981199184e8b12db12ed7d0a26b947f5 (patch) | |
| tree | 1e1a3d8d23dd60bd3f90eac9bdebfb1ee900ef4b | |
| parent | 833553dd9aec0072961a7f1a7797f9481855a07f (diff) | |
Speed-up cursor motion under 'display-line-numbers-mode'
* src/xfaces.c (Finternal_lisp_face_equal_p): Accept an additional
optional argument INHERIT; if non-nil, consider two faces equal if
one inherits from the other and doesn't specify any other
attributes to be different from it.
* src/xdisp.c (try_cursor_movement, try_window_id): Call
'Finternal_lisp_face_equal_p' with non-nil INHERIT argument, to
speed up redisplay in the default case when line numbers are shown.
(Bug#81133)
* test/src/xfaces-tests.el (xfaces-test-face-equality): New test.
| -rw-r--r-- | src/xdisp.c | 4 | ||||
| -rw-r--r-- | src/xfaces.c | 49 | ||||
| -rw-r--r-- | test/src/xfaces-tests.el | 10 |
3 files changed, 58 insertions, 5 deletions
diff --git a/src/xdisp.c b/src/xdisp.c index 1691bd0d80e..dabe63b902a 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -19856,7 +19856,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, && !(!NILP (Vdisplay_line_numbers) && NILP (Finternal_lisp_face_equal_p (Qline_number, Qline_number_current_line, - w->frame))) + w->frame, Qt))) /* This code is not used for mini-buffer for the sake of the case of redisplaying to replace an echo area message; since in that case the mini-buffer contents per se are usually @@ -22657,7 +22657,7 @@ try_window_id (struct window *w) || (!NILP (Vdisplay_line_numbers) && NILP (Finternal_lisp_face_equal_p (Qline_number, Qline_number_current_line, - w->frame)))) + w->frame, Qt)))) GIVE_UP (24); /* composition-break-at-point is incompatible with the optimizations diff --git a/src/xfaces.c b/src/xfaces.c index 73d475c757f..fcec00fbc1f 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -4527,12 +4527,16 @@ lface_equal_p (Lisp_Object *v1, Lisp_Object *v2) DEFUN ("internal-lisp-face-equal-p", Finternal_lisp_face_equal_p, - Sinternal_lisp_face_equal_p, 2, 3, 0, + Sinternal_lisp_face_equal_p, 2, 4, 0, doc: /* True if FACE1 and FACE2 are equal. If the optional argument FRAME is given, report on FACE1 and FACE2 in that frame. If FRAME is t, report on the defaults for FACE1 and FACE2 (for new frames). -If FRAME is omitted or nil, use the selected frame. */) - (Lisp_Object face1, Lisp_Object face2, Lisp_Object frame) +If FRAME is omitted or nil, use the selected frame. +Optional fourth argument INHERIT, if non-nil, means the faces +are considered equal if one inherits from the other in a way +that makes them have the same attributes when used on display. */) + (Lisp_Object face1, Lisp_Object face2, Lisp_Object frame, + Lisp_Object inherit) { bool equal_p; struct frame *f; @@ -4548,6 +4552,45 @@ If FRAME is omitted or nil, use the selected frame. */) lface2 = lface_from_face_name (f, face2, true); equal_p = lface_equal_p (XVECTOR (lface1)->contents, XVECTOR (lface2)->contents); + if (!(NILP (inherit) || equal_p)) + { + /* The below is a subset of merging the descendant face with its + parent(s). We only consider a direct inheritance (so no FACE1 + that inherits from some other face which inherits from FACE2), + and the values of :inherit that are lists are not considered. + This is enough in simple cases such as the line-number-current + face that inherits from line-number. */ + Lisp_Object attrs1[LFACE_VECTOR_SIZE], attrs2[LFACE_VECTOR_SIZE]; + int i; + equal_p = true; + memcpy (attrs1, xvector_contents (lface1), sizeof attrs1); + memcpy (attrs2, xvector_contents (lface2), sizeof attrs2); + /* If either face inherits from the other one, and all the other + face attributes of the inheriting face are either unspecified + or equal to those of the parent face, consider the faces equal. */ + if (EQ (attrs1[LFACE_INHERIT_INDEX], face2)) + { + for (i = 1; i < LFACE_VECTOR_SIZE && equal_p; ++i) + { + if (i == LFACE_INHERIT_INDEX) + continue; + equal_p = face_attr_equal_p (attrs1[i], attrs2[i]) + || UNSPECIFIEDP (attrs1[i]); + } + } + else if (EQ (attrs2[LFACE_INHERIT_INDEX], face1)) + { + for (i = 1; i < LFACE_VECTOR_SIZE && equal_p; ++i) + { + if (i == LFACE_INHERIT_INDEX) + continue; + equal_p = face_attr_equal_p (attrs1[i], attrs2[i]) + || UNSPECIFIEDP (attrs2[i]); + } + } + + } + return equal_p ? Qt : Qnil; } diff --git a/test/src/xfaces-tests.el b/test/src/xfaces-tests.el index ae57909a664..e79d2e88543 100644 --- a/test/src/xfaces-tests.el +++ b/test/src/xfaces-tests.el @@ -65,6 +65,16 @@ 'button)))) (kill-buffer buf))) +(ert-deftest xfaces-test-face-equality () + "Test `internal-lisp-face-equal-p'." + (should (internal-lisp-face-equal-p 'default 'default)) + (should-not (internal-lisp-face-equal-p 'default 'region)) + (should-not (internal-lisp-face-equal-p 'line-number 'default)) + (should-not (internal-lisp-face-equal-p 'line-number ' + line-number-current-line)) + (should (internal-lisp-face-equal-p 'line-number + 'line-number-current-line t))) + (provide 'xfaces-tests) ;;; xfaces-tests.el ends here |
