* Re: Question about display engine [not found] <318675867.1913640.1567711569517.ref@mail.yahoo.com> @ 2019-09-05 19:26 ` Ergus 2019-09-06 8:22 ` martin rudalics 2019-09-06 8:55 ` Eli Zaretskii 0 siblings, 2 replies; 183+ messages in thread From: Ergus @ 2019-09-05 19:26 UTC (permalink / raw) To: rudalics; +Cc: eliz, emacs-devel [-- Attachment #1.1: Type: text/plain, Size: 5169 bytes --] Hi Eli and Martin: I attach here a new patch with all the changes I have just made. After fixing the latest Martin's issue there was exposed a new issue maybe related with the initialization per line. (picture attached) The issue is actually related with the fact that extend_face_id is never restarted to face_id when going back from an extend to a non_extend face between lines (for example when mark is active and the iterator crosses the pointer to outside the selected region like in the picture). I made all the updates of the extend_face_id in the same places where face_id was updated (even when uneeded for now.) But I don't see any special function that is called before display_line. I can set extend_face_id = face_id at the beginning of display_line... but I am not sure if this is consistent or the right to do. In some face_id merges I ignored the merge for extend_face_id because Qnobreak_space, Qglyphless_char or Qescape_glyph I don't think are expected to be :extend t in any case. So the conditional merge is only called in next_element_from_display_vector and the conditionals there seems to be the key for this. The rest of the times the extend_face_id is only saved and restored so as there were no merges I just asign to convenient values (caches, saved or face_id). But maybe this last could be also the problem. I am not convinced that I am doing this right. maybe some experts eyes could help. Lets expect this time marting can execute it ;p Thanks in advance,Ergus. -----Original Message----- From: Ergus <spacibba@aol.com> To: rudalics <rudalics@gmx.at> Cc: eliz <eliz@gnu.org>; emacs-devel <emacs-devel@gnu.org> Sent: Thu, Sep 5, 2019 3:55 pm Subject: Re: Question about display engine For some reason I was not facing this; but it was actually a bug I just fixed. I'll send a patch in a while because this exposed an issue somewhere else. -----Original Message----- From: martin rudalics <rudalics@gmx.at> To: Ergus <spacibba@aol.com> Cc: Eli Zaretskii <eliz@gnu.org>; emacs-devel <emacs-devel@gnu.org> Sent: Thu, Sep 5, 2019 11:24 am Subject: Re: Question about display engine > Here is the diff of the latest commit. (Patch attached anyway). Thanks. I tried with the patch.patch you attached. When trying a gtk build I get: ../../src/xfaces.c:5434: Emacs fatal error: assertion failed: lface_fully_specified_p (XVECTOR (lface)->contents) Fatal error 6: Aborted Backtrace: ../src/bootstrap-emacs[0x67e32f] ../src/bootstrap-emacs[0x6344c8] ../src/bootstrap-emacs[0x74fb6f] ../src/bootstrap-emacs[0x5a8e43] ../src/bootstrap-emacs[0x5a83f8] ../src/bootstrap-emacs[0x59bccf] ../src/bootstrap-emacs[0x436ad1] ../src/bootstrap-emacs[0x4fd0ad] ../src/bootstrap-emacs[0x76376c] ../src/bootstrap-emacs[0x63530c] ../src/bootstrap-emacs[0x635860] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f68217952e1] ../src/bootstrap-emacs[0x4151aa] /bin/bash: Zeile 2: 12088 Abgebrochen EMACSLOADPATH= '../src/bootstrap-emacs' -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)' -l bytecomp -f byte-compile-refresh-preloaded -f batch-byte-compile ../../lisp/cus-face.el Makefile:280: die Regel für Ziel „../../lisp/cus-face.elc“ scheiterte make[2]: *** [../../lisp/cus-face.elc] Fehler 134 Makefile:784: die Regel für Ziel „../../lisp/cus-face.elc“ scheiterte make[1]: *** [../../lisp/cus-face.elc] Fehler 2 make[1]: *** Es wird auf noch nicht beendete Prozesse gewartet... ../../src/xfaces.c:5434: Emacs fatal error: assertion failed: lface_fully_specified_p (XVECTOR (lface)->contents) Backtrace: ../src/bootstrap-emacs[0x67e32f] ../src/bootstrap-emacs[0x6344c8] ../src/bootstrap-emacs[0x74fb6f] ../src/bootstrap-emacs[0x5a8e43] ../src/bootstrap-emacs[0x5a83f8] ../src/bootstrap-emacs[0x59bccf] ../src/bootstrap-emacs[0x436ad1] ../src/bootstrap-emacs[0x4fd0ad] ../src/bootstrap-emacs[0x76376c] ../src/bootstrap-emacs[0x63530c] ../src/bootstrap-emacs[0x635860] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f0e8f3a32e1] ../src/bootstrap-emacs[0x4151aa] /bin/bash: Zeile 2: 12090 Abgebrochen EMACSLOADPATH= '../src/bootstrap-emacs' -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)' -l bytecomp -f byte-compile-refresh-preloaded -f batch-byte-compile ../../lisp/faces.el Makefile:280: die Regel für Ziel „../../lisp/faces.elc“ scheiterte make[2]: *** [../../lisp/faces.elc] Fehler 134 Makefile:784: die Regel für Ziel „../../lisp/faces.elc“ scheiterte make[1]: *** [../../lisp/faces.elc] Fehler 2 make[1]: Verzeichnis „/home/martin/emacs-git/trunk/obj-gtk/src“ wird verlassen Makefile:424: die Regel für Ziel „src“ scheiterte make: *** [src] Fehler 2 and a similar crash on Windows. Before proceeding to dig into this I'd like to hear your ideas. > https://github.com/Ergus/Emacs/commit/4943087027acd3f2c7a54a092b64bc839ef8850e Is there any way to get the diffs wrt current master on that site? I never use github for such a thing and my browser settings are quite restrictive. Thanks, martin [-- Attachment #1.2: Type: text/html, Size: 7578 bytes --] [-- Attachment #2: Screenshot_2019-09-05_20-49-41.png --] [-- Type: image/png, Size: 29280 bytes --] [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: patch.patch --] [-- Type: text/x-patch, Size: 45844 bytes --] diff --git a/lisp/cus-face.el b/lisp/cus-face.el index d73bce42c3..5a49a81043 100644 --- a/lisp/cus-face.el +++ b/lisp/cus-face.el @@ -233,7 +233,11 @@ custom-face-attributes (file :tag "File" :help-echo "Name of bitmap file." :must-match t))) - + (:extend + (choice :tag "Extend" + :help-echo "Control whether attributes should be extended after EOL." + (const :tag "Off" nil) + (const :tag "On" t))) (:inherit (repeat :tag "Inherit" :help-echo "List of faces to inherit attributes from." diff --git a/lisp/faces.el b/lisp/faces.el index 5193c216d0..814a4b2c9a 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -342,6 +342,7 @@ face-x-resources (:box (".attributeBox" . "Face.AttributeBox")) (:underline (".attributeUnderline" . "Face.AttributeUnderline")) (:inverse-video (".attributeInverse" . "Face.AttributeInverse")) + (:extend (".attributeExtend" . "Face.AttributeExtend")) (:stipple (".attributeStipple" . "Face.AttributeStipple") (".attributeBackgroundPixmap" . "Face.AttributeBackgroundPixmap")) @@ -594,6 +595,13 @@ face-italic-p (let ((italic (face-attribute face :slant frame inherit))) (memq italic '(italic oblique)))) +(defun face-extend-p (face &optional frame inherit) + "Return non-nil if FACE specifies a non-nil extend. +If the optional argument FRAME is given, report on face FACE in that frame. +If FRAME is t, report on the defaults for face FACE (for new frames). +If FRAME is omitted or nil, use the selected frame. +Optional argument INHERIT is passed to `face-attribute'." + (eq (face-attribute face :extend frame inherit) t)) \f ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -760,6 +768,11 @@ set-face-attribute `:height', `:weight', and `:slant' may also be set in one step from an X font name: +`:extend' + +VALUE specifies whether the FACE should be extended after EOL. +VALUE must be one of t or nil. + `:font' Set font-related face attributes from VALUE. @@ -979,6 +992,18 @@ set-face-italic (define-obsolete-function-alias 'set-face-italic-p 'set-face-italic "24.4") +(defun set-face-extend (face extend-p &optional frame) + "Specify whether face FACE should be extended. +EXTEND-P nil means FACE explicitly doesn't extend after EOL. +EXTEND-P t means FACE extends after EOL. + +FRAME nil or not specified means change face on all frames. +Use `set-face-attribute' to \"unspecify\" underlining." + (interactive + (let ((list (read-face-and-attribute :extend))) + (list (car list) (if (cadr list) t)))) + (set-face-attribute face frame :extend extend-p)) + (defalias 'set-face-background-pixmap 'set-face-stipple) @@ -1102,7 +1127,7 @@ face-valid-attribute-values (:slant (mapcar #'(lambda (x) (cons (symbol-name (aref x 1)) (aref x 1))) font-slant-table)) - (:inverse-video + ((or :inverse-video :extend) (mapcar #'(lambda (x) (cons (symbol-name x) x)) (internal-lisp-face-attribute-values attribute))) ((or :underline :overline :strike-through :box) @@ -1147,6 +1172,7 @@ face-attribute-name-alist (:slant . "slant") (:underline . "underline") (:overline . "overline") + (:extend . "extend") (:strike-through . "strike-through") (:box . "box") (:inverse-video . "inverse-video display") @@ -1448,6 +1474,7 @@ describe-face (:stipple . "Stipple") (:font . "Font") (:fontset . "Fontset") + (:extend . "Extend") (:inherit . "Inherit"))) (max-width (apply #'max (mapcar #'(lambda (x) (length (cdr x))) attrs)))) @@ -1667,7 +1694,8 @@ face-spec-reset-face ;; (see also realize_default_face in xfaces.c). (append '(:underline nil :overline nil :strike-through nil - :box nil :inverse-video nil :stipple nil :inherit nil) + :box nil :inverse-video nil :stipple nil :inherit nil + :extend nil) ;; `display-graphic-p' is unavailable when running ;; temacs, prior to loading frame.el. (when (fboundp 'display-graphic-p) @@ -2432,24 +2460,24 @@ highlight ;; if background is light. (defface region '((((class color) (min-colors 88) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 88) (background light) (type gtk)) :distant-foreground "gtk_selection_fg_color" - :background "gtk_selection_bg_color") + :background "gtk_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light) (type ns)) :distant-foreground "ns_selection_fg_color" - :background "ns_selection_bg_color") + :background "ns_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 16) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 16) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 8)) - :background "blue" :foreground "white") + :background "blue" :foreground "white" :extend t) (((type tty) (class mono)) :inverse-video t) - (t :background "gray")) + (t :background "gray" :extend t)) "Basic face for highlighting the region." :version "21.1" :group 'basic-faces) diff --git a/src/dispextern.h b/src/dispextern.h index 05f199ff35..c11a3a7b54 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1564,6 +1564,7 @@ #define FONT_TOO_HIGH(ft) \ LFACE_INHERIT_INDEX, LFACE_FONTSET_INDEX, LFACE_DISTANT_FOREGROUND_INDEX, + LFACE_EXTEND_INDEX, LFACE_VECTOR_SIZE }; @@ -1589,6 +1590,7 @@ #define FONT_TOO_HIGH(ft) \ enum face_underline_type { + FACE_NO_UNDERLINE = 0, FACE_UNDER_LINE, FACE_UNDER_WAVE }; @@ -1632,11 +1634,9 @@ #define FONT_TOO_HIGH(ft) \ /* Pixel value or color index of background color. */ unsigned long background; - /* Pixel value or color index of underline color. */ + /* Pixel value or color index of underline, overlined, + strike-through, or box color. */ unsigned long underline_color; - - /* Pixel value or color index of overlined, strike-through, or box - color. */ unsigned long overline_color; unsigned long strike_through_color; unsigned long box_color; @@ -1663,7 +1663,7 @@ #define FONT_TOO_HIGH(ft) \ ENUM_BF (face_box_type) box : 2; /* Style of underlining. */ - ENUM_BF (face_underline_type) underline_type : 1; + ENUM_BF (face_underline_type) underline : 2; /* If `box' above specifies a 3D type, true means use box_color for drawing shadows. */ @@ -1671,7 +1671,6 @@ #define FONT_TOO_HIGH(ft) \ /* Non-zero if text in this face should be underlined, overlined, strike-through or have a box drawn around it. */ - bool_bf underline_p : 1; bool_bf overline_p : 1; bool_bf strike_through_p : 1; @@ -1681,14 +1680,10 @@ #define FONT_TOO_HIGH(ft) \ bool_bf foreground_defaulted_p : 1; bool_bf background_defaulted_p : 1; - /* True means that either no color is specified for underlining or that - the specified color couldn't be loaded. Use the foreground - color when drawing in that case. */ - bool_bf underline_defaulted_p : 1; - /* True means that either no color is specified for the corresponding attribute or that the specified color couldn't be loaded. Use the foreground color when drawing in that case. */ + bool_bf underline_defaulted_p : 1; bool_bf overline_color_defaulted_p : 1; bool_bf strike_through_color_defaulted_p : 1; bool_bf box_color_defaulted_p : 1; @@ -1822,6 +1817,9 @@ #define FACE_FROM_ID_OR_NULL(F, ID) \ ? FRAME_FACE_CACHE (F)->faces_by_id[ID] \ : NULL) +#define FACE_EXTENSIBLE_P(F) \ + (!NILP (F->lface[LFACE_EXTEND_INDEX])) + /* True if FACE is suitable for displaying ASCII characters. */ INLINE bool FACE_SUITABLE_FOR_ASCII_CHAR_P (struct face *face) @@ -2328,7 +2326,7 @@ #define IT_STACK_SIZE 5 /* Face id of the iterator saved in case a glyph from dpvec contains a face. The face is restored when all glyphs from dpvec have been delivered. */ - int saved_face_id; + int saved_face_id, saved_extend_face_id; /* Vector of glyphs for control character translation. The pointer dpvec is set to ctl_chars when a control character is translated. @@ -2390,7 +2388,7 @@ #define OVERLAY_STRING_CHUNK_SIZE 16 ptrdiff_t prev_stop; ptrdiff_t base_level_stop; struct composition_it cmp_it; - int face_id; + int face_id, extend_face_id; /* Save values specific to a given method. */ union { @@ -2448,6 +2446,9 @@ #define OVERLAY_STRING_CHUNK_SIZE 16 /* Face to use. */ int face_id; + /* Face to extend at EOL/ */ + int extend_face_id; + /* Setting of buffer-local variable selective-display-ellipses. */ bool_bf selective_display_ellipsis_p : 1; diff --git a/src/nsterm.m b/src/nsterm.m index 42ef4dd010..99b621533a 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3404,9 +3404,9 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; /* Do underline. */ - if (face->underline_p) + if (face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { if (face->underline_defaulted_p) [defaultCol set]; @@ -3415,15 +3415,15 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. ns_draw_underwave (s, width, x); } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { NSRect r; unsigned long thickness, position; /* If the prev was underlined, match its appearance. */ - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE + if (s->prev + && s->prev->face->underline == FACE_UNDER_LINE && s->prev->underline_thickness > 0) { thickness = s->prev->underline_thickness; diff --git a/src/w32term.c b/src/w32term.c index e5874f2d36..99a1db5784 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -2479,9 +2479,9 @@ w32_draw_glyph_string (struct glyph_string *s) if (!s->for_overlaps) { /* Draw underline. */ - if (s->face->underline_p) + if (s->face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { COLORREF color; @@ -2492,13 +2492,13 @@ w32_draw_glyph_string (struct glyph_string *s) w32_draw_underwave (s, color); } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { unsigned long thickness, position; int y; - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE) + if (s->prev + && s->prev->face->underline == FACE_UNDER_LINE) { /* We use the same underline style as the previous one. */ thickness = s->prev->underline_thickness; @@ -2512,7 +2512,7 @@ w32_draw_glyph_string (struct glyph_string *s) BOOL use_underline_position_properties; Lisp_Object val = buffer_local_value (Qunderline_minimum_offset, - s->w->contents); + s->w->contents); if (FIXNUMP (val)) minimum_offset = max (0, XFIXNUM (val)); else diff --git a/src/xdisp.c b/src/xdisp.c index 94f969f37c..62730903fd 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3120,6 +3120,7 @@ init_iterator (struct it *it, struct window *w, struct face *face; it->face_id = remapped_base_face_id; + it->extend_face_id = remapped_base_face_id; /* If we have a boxed mode line, make the first character appear with a left box line. */ @@ -3141,6 +3142,8 @@ init_iterator (struct it *it, struct window *w, /* We will rely on `reseat' to set this up properly, via handle_face_prop. */ it->face_id = it->base_face_id; + it->extend_face_id = it->base_face_id; // ERGUS: FIX_THIS + it->start = it->current; /* Do we need to reorder bidirectional text? Not if this is a @@ -3536,7 +3539,10 @@ handle_stop (struct it *it) /* Use face of preceding text for ellipsis (if invisible) */ if (it->selective_display_ellipsis_p) - it->saved_face_id = it->face_id; + { + it->saved_face_id = it->face_id; + it->saved_extend_face_id = it->extend_face_id; + } /* Here's the description of the semantics of, and the logic behind, the various HANDLED_* statuses: @@ -4154,7 +4160,15 @@ handle_face_prop (struct it *it) it->start_of_box_run_p = (new_face->box != FACE_NO_BOX && (old_face == NULL || !old_face->box)); it->face_box_p = new_face->box != FACE_NO_BOX; + + /* Update the faces id and extend. */ + it->face_id = new_face_id; + + if (FACE_EXTENSIBLE_P (new_face)) + it->extend_face_id = new_face_id; + } + } else { @@ -4250,13 +4264,19 @@ handle_face_prop (struct it *it) /* If new face has a box but old face hasn't, this is the start of a run of characters with box, i.e. it has a shadow on the left side. */ - it->start_of_box_run_p - = new_face->box && (old_face == NULL || !old_face->box); + it->start_of_box_run_p = (new_face->box != FACE_NO_BOX + && (old_face == NULL || !old_face->box)); it->face_box_p = new_face->box != FACE_NO_BOX; + + /* Update the faces id and extend. */ + it->face_id = new_face_id; + + if (FACE_EXTENSIBLE_P (new_face)) + it->extend_face_id = new_face_id; + } } - it->face_id = new_face_id; return HANDLED_NORMALLY; } @@ -4854,6 +4874,9 @@ setup_for_ellipsis (struct it *it, int len) if (it->saved_face_id >= 0) it->face_id = it->saved_face_id; + if (it->saved_extend_face_id >= 0) + it->extend_face_id = it->saved_extend_face_id; + /* If the ellipsis represents buffer text, it means we advanced in the buffer, so we should no longer ignore overlay strings. */ if (it->method == GET_FROM_BUFFER) @@ -5063,7 +5086,8 @@ display_prop_end (struct it *it, Lisp_Object object, struct text_pos start_pos) of buffer or string text. */ static int -handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, +handle_single_display_spec (struct it *it, Lisp_Object spec, + Lisp_Object object, Lisp_Object overlay, struct text_pos *position, ptrdiff_t bufpos, int display_replaced, bool frame_window_p, bool enable_eval_p) @@ -5137,7 +5161,11 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, int steps = XFIXNUM (XCAR (XCDR (it->font_height))); if (EQ (XCAR (it->font_height), Qplus)) steps = - steps; + it->face_id = smaller_face (it->f, it->face_id, steps); + it->extend_face_id + = smaller_face (it->f, it->extend_face_id, steps); + } else if (FUNCTIONP (it->font_height) && enable_eval_p) { @@ -5180,7 +5208,12 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, } if (new_height > 0) - it->face_id = face_with_height (it->f, it->face_id, new_height); + { + it->face_id + = face_with_height (it->f, it->face_id, new_height); + it->extend_face_id + = face_with_height (it->f, it->extend_face_id, new_height); + } } } @@ -5370,6 +5403,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, it->method = GET_FROM_IMAGE; it->from_overlay = Qnil; it->face_id = face_id; + it->extend_face_id = face_id; // ERGUS: FIX_THIS it->from_disp_prop_p = true; /* Say that we haven't consumed the characters with @@ -6263,6 +6297,7 @@ push_it (struct it *it, struct text_pos *position) p->cmp_it = it->cmp_it; eassert (it->face_id >= 0); p->face_id = it->face_id; + p->extend_face_id = it->extend_face_id; p->string = it->string; p->method = it->method; p->from_overlay = it->from_overlay; @@ -6366,6 +6401,7 @@ pop_it (struct it *it) it->base_level_stop = p->base_level_stop; it->cmp_it = p->cmp_it; it->face_id = p->face_id; + it->extend_face_id = p->extend_face_id; it->current = p->current; it->position = p->position; it->string = p->string; @@ -7142,17 +7178,32 @@ lookup_glyphless_char_display (int c, struct it *it) /* Merge escape glyph face and cache the result. */ +static int +merge_extend_glyph_face (struct it *it, int lface_id) +{ + + struct face *lface = FACE_FROM_ID (it->f, lface_id); + + if (lface && FACE_EXTENSIBLE_P (lface)) + return merge_faces (it->w, Qt, lface_id, it->extend_face_id); + + return it->extend_face_id; +} + +/* Merge escape glyph face and cache the result. */ static struct frame *last_escape_glyph_frame = NULL; static int last_escape_glyph_face_id = (1 << FACE_ID_BITS); static int last_escape_glyph_merged_face_id = 0; static int -merge_escape_glyph_face (struct it *it) +merge_escape_glyph_face (struct it *it, int lface_id) { int face_id; - if (it->f == last_escape_glyph_frame - && it->face_id == last_escape_glyph_face_id) + if (lface_id) + face_id = merge_faces (it->w, Qt, lface_id, it->face_id); + else if (it->f == last_escape_glyph_frame + && it->face_id == last_escape_glyph_face_id) face_id = last_escape_glyph_merged_face_id; else { @@ -7162,6 +7213,7 @@ merge_escape_glyph_face (struct it *it) last_escape_glyph_face_id = it->face_id; last_escape_glyph_merged_face_id = face_id; } + return face_id; } @@ -7190,6 +7242,7 @@ merge_glyphless_glyph_face (struct it *it) return face_id; } + /* Forget the `escape-glyph' and `glyphless-char' faces. This should be called before redisplaying windows, and when the frame's face cache is freed. */ @@ -7275,6 +7328,7 @@ get_next_display_element (struct it *it) it->current.dpvec_index = 0; it->dpvec_face_id = -1; it->saved_face_id = it->face_id; + it->saved_extend_face_id = it->extend_face_id; it->method = GET_FROM_DISPLAY_VECTOR; it->ellipsis_p = false; } @@ -7355,9 +7409,7 @@ get_next_display_element (struct it *it) lface_id = GLYPH_CODE_FACE (gc); } - face_id = (lface_id - ? merge_faces (it->w, Qt, lface_id, it->face_id) - : merge_escape_glyph_face (it)); + face_id = merge_escape_glyph_face (it, lface_id); XSETINT (it->ctl_chars[0], g); XSETINT (it->ctl_chars[1], c ^ 0100); @@ -7373,6 +7425,7 @@ get_next_display_element (struct it *it) /* Merge `nobreak-space' into the current face. */ face_id = merge_faces (it->w, Qnobreak_space, 0, it->face_id); + XSETINT (it->ctl_chars[0], ' '); ctl_len = 1; goto display_control; @@ -7385,7 +7438,8 @@ get_next_display_element (struct it *it) { /* Merge `nobreak-space' into the current face. */ face_id = merge_faces (it->w, Qnobreak_hyphen, 0, - it->face_id); + it->face_id); + XSETINT (it->ctl_chars[0], '-'); ctl_len = 1; goto display_control; @@ -7403,12 +7457,9 @@ get_next_display_element (struct it *it) lface_id = GLYPH_CODE_FACE (gc); } - face_id = (lface_id - ? merge_faces (it->w, Qt, lface_id, it->face_id) - : merge_escape_glyph_face (it)); + face_id = merge_escape_glyph_face (it, lface_id); /* Draw non-ASCII space/hyphen with escape glyph: */ - if (nonascii_space_p || nonascii_hyphen_p) { XSETINT (it->ctl_chars[0], escape_glyph); @@ -7443,6 +7494,7 @@ get_next_display_element (struct it *it) it->current.dpvec_index = 0; it->dpvec_face_id = face_id; it->saved_face_id = it->face_id; + it->saved_extend_face_id = it->extend_face_id; it->method = GET_FROM_DISPLAY_VECTOR; it->ellipsis_p = false; goto get_next; @@ -7778,6 +7830,7 @@ set_iterator_to_next (struct it *it, bool reseat_p) /* Restore face of the iterator to what they were before the display vector entry (these entries may contain faces). */ it->face_id = it->saved_face_id; + it->extend_face_id = it->saved_extend_face_id; if (it->dpvec + it->current.dpvec_index >= it->dpend) { @@ -8012,6 +8065,7 @@ next_element_from_display_vector (struct it *it) eassert (it->dpvec && it->current.dpvec_index >= 0); it->face_id = it->saved_face_id; + it->extend_face_id = it->saved_extend_face_id; /* KFS: This code used to check ip->dpvec[0] instead of the current element. That seemed totally bogus - so I changed it... */ @@ -8027,13 +8081,21 @@ next_element_from_display_vector (struct it *it) the id of a Lisp face, not a realized face. A face id of zero means no face is specified. */ if (it->dpvec_face_id >= 0) - it->face_id = it->dpvec_face_id; + { + it->face_id = it->dpvec_face_id; + it->extend_face_id = it->dpvec_face_id; // ERGUS: FIX_THIS + } else { int lface_id = GLYPH_CODE_FACE (gc); if (lface_id > 0) - it->face_id = merge_faces (it->w, Qt, lface_id, - it->saved_face_id); + { + it->face_id = merge_faces (it->w, Qt, lface_id, + it->saved_face_id); + + it->extend_face_id = + merge_extend_glyph_face (it, lface_id); + } } /* Glyphs in the display vector could have the box face, so we @@ -8061,8 +8123,12 @@ next_element_from_display_vector (struct it *it) GLYPH_CODE_FACE (it->dpvec[it->current.dpvec_index + 1]); if (lface_id > 0) - next_face_id = merge_faces (it->w, Qt, lface_id, - it->saved_face_id); + { + next_face_id = merge_faces (it->w, Qt, lface_id, + it->saved_face_id); + it->extend_face_id = + merge_extend_glyph_face (it, lface_id); + } } } next_face = FACE_FROM_ID_OR_NULL (it->f, next_face_id); @@ -8411,6 +8477,7 @@ next_element_from_ellipsis (struct it *it) was in IT->saved_face_id, and signal that it's there by setting face_before_selective_p. */ it->saved_face_id = it->face_id; + it->saved_extend_face_id = it->extend_face_id; it->method = GET_FROM_BUFFER; it->object = it->w->contents; reseat_at_next_visible_line_start (it, true); @@ -12848,7 +12915,10 @@ display_tool_bar_line (struct it *it, int height) use the tool-bar face for the border too. */ if (!MATRIX_ROW_DISPLAYS_TEXT_P (row) && !EQ (Vauto_resize_tool_bars, Qgrow_only)) - it->face_id = DEFAULT_FACE_ID; + { + it->face_id = DEFAULT_FACE_ID; + it->extend_face_id = DEFAULT_FACE_ID; + } extend_face_to_end_of_line (it); last = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1; @@ -20301,7 +20371,7 @@ append_space_for_newline (struct it *it, bool default_face_p) /* Corner case for when display-fill-column-indicator-mode is active and the extra character should be added in the - same place than the line. */ + same place than the space. */ int indicator_column = (it->w->pseudo_window_p == 0 ? fill_column_indicator_column (it) : -1); @@ -20325,7 +20395,7 @@ append_space_for_newline (struct it *it, bool default_face_p) = XFIXNAT (Vdisplay_fill_column_indicator_character); it->face_id = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); + 0, it->face_id); face = FACE_FROM_ID (it->f, it->face_id); goto produce_glyphs; } @@ -20337,7 +20407,7 @@ append_space_for_newline (struct it *it, bool default_face_p) if (default_face_p) it->face_id = local_default_face_id; else if (it->face_before_selective_p) - it->face_id = it->saved_face_id; + it->face_id = it->face_id; face = FACE_FROM_ID (it->f, it->face_id); it->face_id = FACE_FOR_CHAR (it->f, face, 0, -1, Qnil); @@ -20472,33 +20542,35 @@ extend_face_to_end_of_line (struct it *it) 1-``pixel'' wide, so they hit the equality too early. This grace is needed only for R2L rows that are not continued, to produce one extra blank where we could display the cursor. */ - if ((it->current_x >= it->last_visible_x - + (!FRAME_WINDOW_P (f) - && it->glyph_row->reversed_p - && !it->glyph_row->continued_p)) - /* If the window has display margins, we will need to extend - their face even if the text area is filled. */ - && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 - || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) - return; - - /* Face extension extends the background and box of IT->face_id - to the end of the line. If the background equals the background - of the frame, we don't have to do anything. */ - face = FACE_FROM_ID (f, (it->face_before_selective_p - ? it->saved_face_id - : it->face_id)); - - if (FRAME_WINDOW_P (f) - && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) - && face->box == FACE_NO_BOX - && FACE_COLOR_TO_PIXEL (face->background, f) == FRAME_BACKGROUND_PIXEL (f) -#ifdef HAVE_WINDOW_SYSTEM - && !face->stipple -#endif - && !it->glyph_row->reversed_p - && !Vdisplay_fill_column_indicator) - return; +/* if ((it->current_x >= it->last_visible_x */ +/* + (!FRAME_WINDOW_P (f) */ +/* && it->glyph_row->reversed_p */ +/* && !it->glyph_row->continued_p)) */ +/* /\* If the window has display margins, we will need to extend */ +/* their face even if the text area is filled. *\/ */ +/* && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 */ +/* || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) */ +/* return; */ + +/* /\* Face extension extends the background and box of IT->face_id */ +/* to the end of the line. If the background equals the background */ +/* of the frame, we don't have to do anything. *\/ */ + /* face = FACE_FROM_ID (f, (it->face_before_selective_p */ + /* ? it->saved_extend_face_id */ + /* : it->extend_face_id)); */ + + face = FACE_FROM_ID (f, it->extend_face_id); + +/* if (FRAME_WINDOW_P (f) */ +/* && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) */ +/* && face->box == FACE_NO_BOX */ +/* && FACE_COLOR_TO_PIXEL (face->background, f) == FRAME_BACKGROUND_PIXEL (f) */ +/* #ifdef HAVE_WINDOW_SYSTEM */ +/* && !face->stipple */ +/* #endif */ +/* && !it->glyph_row->reversed_p */ +/* && !Vdisplay_fill_column_indicator) */ +/* return; */ /* Set the glyph row flag indicating that the face of the last glyph in the text area has to be drawn to the end of the text area. */ @@ -20561,79 +20633,88 @@ extend_face_to_end_of_line (struct it *it) /* Display fill column indicator if not in modeline or toolbar and display fill column indicator mode is active. */ + const char saved_char = it->char_to_display; + const struct text_pos saved_pos = it->position; + const bool saved_avoid_cursor = it->avoid_cursor_p; + const int saved_face_id = it->face_id; + const bool saved_box_start = it->start_of_box_run_p; + Lisp_Object save_object = it->object; + + it->avoid_cursor_p = true; + it->object = Qnil; + memset (&it->position, 0, sizeof it->position); + int indicator_column = (it->w->pseudo_window_p == 0 ? fill_column_indicator_column (it) : -1); - if (indicator_column >= 0) - { - struct font *font = (default_face->font + + struct font *font = (default_face->font ? default_face->font : FRAME_FONT (f)); - const int char_width = (font->average_width - ? font->average_width - : font->space_width); - int column_x; - - if (!INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) - && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) - && column_x >= it->current_x - && column_x <= it->last_visible_x) - { - const char saved_char = it->char_to_display; - const struct text_pos saved_pos = it->position; - const bool saved_avoid_cursor = it->avoid_cursor_p; - const int saved_face_id = it->face_id; - const bool saved_box_start = it->start_of_box_run_p; - Lisp_Object save_object = it->object; - - /* The stretch width needs to considet the latter - added glyph. */ - const int stretch_width - = column_x - it->current_x - char_width; - - memset (&it->position, 0, sizeof it->position); - it->avoid_cursor_p = true; - it->object = Qnil; - - /* Only generate a stretch glyph if there is distance - between current_x and and the indicator position. */ - if (stretch_width > 0) - { - int stretch_ascent = (((it->ascent + it->descent) - * FONT_BASE (font)) / FONT_HEIGHT (font)); - append_stretch_glyph (it, Qnil, stretch_width, - it->ascent + it->descent, - stretch_ascent); - } + const int char_width = (font->average_width + ? font->average_width + : font->space_width); + int column_x; + + if (indicator_column >= 0 + && !INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) + && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) + && column_x >= it->current_x + && column_x <= it->last_visible_x) + { + + /* The stretch width needs to considet the latter + added glyph. */ + const int stretch_width + = column_x - it->current_x - char_width; + + /* Only generate a stretch glyph if there is distance + between current_x and and the indicator position. */ + if (stretch_width > 0) + { + it->face_id = it->extend_face_id; - /* Generate the glyph indicator only if - append_space_for_newline didn't already. */ - if (it->current_x < column_x) - { - it->char_to_display - = XFIXNAT (Vdisplay_fill_column_indicator_character); - it->face_id - = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); - PRODUCE_GLYPHS (it); - } - - /* Restore the face after the indicator was generated. */ - it->face_id = saved_face_id; - - /* If there is space after the indicator generate an - extra empty glyph to restore the face. Issue was - observed in X systems. */ - it->char_to_display = ' '; - PRODUCE_GLYPHS (it); - - it->char_to_display = saved_char; - it->position = saved_pos; - it->avoid_cursor_p = saved_avoid_cursor; - it->start_of_box_run_p = saved_box_start; - it->object = save_object; - } - } + int stretch_ascent = (((it->ascent + it->descent) + * FONT_BASE (font)) / FONT_HEIGHT (font)); + append_stretch_glyph (it, Qnil, stretch_width, + it->ascent + it->descent, + stretch_ascent); + } + + /* Generate the glyph indicator only if + append_space_for_newline didn't already. */ + if (it->current_x < column_x) + { + it->char_to_display + = XFIXNAT (Vdisplay_fill_column_indicator_character); + it->face_id + = merge_faces (it->w, Qfill_column_indicator, + 0, it->extend_face_id); + PRODUCE_GLYPHS (it); + it->char_to_display = saved_char; + } + + } + + const int stretch_width = it->last_visible_x - it->current_x; + + if (stretch_width > 0) + { + it->face_id = it->extend_face_id; + + int stretch_ascent = (((it->ascent + it->descent) + * FONT_BASE (font)) / FONT_HEIGHT (font)); + append_stretch_glyph (it, Qnil, stretch_width, + it->ascent + it->descent, + stretch_ascent); + } + + it->char_to_display = saved_char; + it->position = saved_pos; + it->avoid_cursor_p = saved_avoid_cursor; + it->face_id = saved_face_id; + it->start_of_box_run_p = saved_box_start; + it->object = save_object; } if (it->glyph_row->reversed_p) { @@ -20679,10 +20760,9 @@ extend_face_to_end_of_line (struct it *it) /* The last row's stretch glyph should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ - if (it->glyph_row->ends_at_zv_p) - it->face_id = default_face->id; - else - it->face_id = face->id; + it->face_id = (it->glyph_row->ends_at_zv_p ? + default_face->id : face->id); + it->start_of_box_run_p = false; append_stretch_glyph (it, Qnil, stretch_width, it->ascent + it->descent, stretch_ascent); @@ -20719,7 +20799,7 @@ extend_face_to_end_of_line (struct it *it) it->len = 1; if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 - && (it->glyph_row->used[LEFT_MARGIN_AREA] + && (it->glyph_row->used[LEFT_MARGIN_AREA] < WINDOW_LEFT_MARGIN_WIDTH (it->w)) && !it->glyph_row->mode_line_p && FACE_COLOR_TO_PIXEL (face->background, f) != FRAME_BACKGROUND_PIXEL (f)) @@ -20750,10 +20830,8 @@ extend_face_to_end_of_line (struct it *it) /* The last row's blank glyphs should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ - if (it->glyph_row->ends_at_zv_p) - it->face_id = default_face->id; - else - it->face_id = face->id; + it->face_id = (it->glyph_row->ends_at_zv_p ? + default_face->id : face->id); /* Display fill-column indicator if needed. */ int indicator_column = fill_column_indicator_column (it); @@ -20763,24 +20841,25 @@ extend_face_to_end_of_line (struct it *it) indicator_column = -1; do { - int saved_face_id; - bool indicate = it->current_x == indicator_column; - if (indicate) + if (it->current_x == indicator_column) { - saved_face_id = it->face_id; + int saved_face_id = it->face_id; + it->face_id - = merge_faces (it->w, Qfill_column_indicator, 0, saved_face_id); + = merge_faces (it->w, Qfill_column_indicator, 0, + it->extend_face_id); it->c = it->char_to_display = XFIXNAT (Vdisplay_fill_column_indicator_character); - } - PRODUCE_GLYPHS (it); + PRODUCE_GLYPHS (it); - if (indicate) - { it->face_id = saved_face_id; it->c = it->char_to_display = ' '; } + else + { + PRODUCE_GLYPHS (it); + } } while (it->current_x <= it->last_visible_x); @@ -25423,7 +25502,8 @@ display_count_lines (ptrdiff_t start_byte, Value is the number of columns displayed. */ static int -display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_string, +display_string (const char *string, Lisp_Object lisp_string, + Lisp_Object face_string, ptrdiff_t face_string_pos, ptrdiff_t start, struct it *it, int field_width, int precision, int max_x, int multibyte) { @@ -25446,12 +25526,13 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st if (STRINGP (face_string)) { ptrdiff_t endptr; - struct face *face; it->face_id = face_at_string_position (it->w, face_string, face_string_pos, 0, &endptr, it->base_face_id, false); - face = FACE_FROM_ID (it->f, it->face_id); + + struct face *face = FACE_FROM_ID (it->f, it->face_id); + it->face_box_p = face->box != FACE_NO_BOX; } @@ -27355,7 +27436,7 @@ font_for_underline_metrics (struct glyph_string *s) for (g = s->first_glyph - 1; g >= g0; g--) { struct face *prev_face = FACE_FROM_ID (s->f, g->face_id); - if (!(prev_face && prev_face->underline_p)) + if (!(prev_face && prev_face->underline != FACE_NO_UNDERLINE)) break; } diff --git a/src/xfaces.c b/src/xfaces.c index c3cae7e2a6..9c58e3e51a 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -1209,7 +1209,7 @@ free_face_colors (struct frame *f, struct face *face) IF_DEBUG (--ncolors_allocated); } - if (face->underline_p + if (face->underline && !face->underline_defaulted_p) { x_free_colors (f, &face->underline_color, 1); @@ -1590,6 +1590,7 @@ #define LFACE_BOX(LFACE) AREF ((LFACE), LFACE_BOX_INDEX) #define LFACE_FONT(LFACE) AREF ((LFACE), LFACE_FONT_INDEX) #define LFACE_INHERIT(LFACE) AREF ((LFACE), LFACE_INHERIT_INDEX) #define LFACE_FONTSET(LFACE) AREF ((LFACE), LFACE_FONTSET_INDEX) +#define LFACE_EXTEND(LFACE) AREF ((LFACE), LFACE_EXTEND_INDEX) #define LFACE_DISTANT_FOREGROUND(LFACE) \ AREF ((LFACE), LFACE_DISTANT_FOREGROUND_INDEX) @@ -1633,6 +1634,10 @@ check_lface_attrs (Lisp_Object attrs[LFACE_VECTOR_SIZE]) || SYMBOLP (attrs[LFACE_UNDERLINE_INDEX]) || STRINGP (attrs[LFACE_UNDERLINE_INDEX]) || CONSP (attrs[LFACE_UNDERLINE_INDEX])); + eassert (UNSPECIFIEDP (attrs[LFACE_EXTEND_INDEX]) + || IGNORE_DEFFACE_P (attrs[LFACE_EXTEND_INDEX]) + || SYMBOLP (attrs[LFACE_EXTEND_INDEX]) + || STRINGP (attrs[LFACE_EXTEND_INDEX])); eassert (UNSPECIFIEDP (attrs[LFACE_OVERLINE_INDEX]) || IGNORE_DEFFACE_P (attrs[LFACE_OVERLINE_INDEX]) || SYMBOLP (attrs[LFACE_OVERLINE_INDEX]) @@ -2512,6 +2517,13 @@ merge_face_ref (struct window *w, err_msgs, named_merge_points)) err = true; } + else if (EQ (keyword, QCextend)) + { + if (EQ (value, Qt) || NILP (value)) + to[LFACE_EXTEND_INDEX] = value; + else + err = true; + } else err = true; @@ -3030,6 +3042,17 @@ DEFUN ("internal-set-lisp-face-attribute", Finternal_set_lisp_face_attribute, old_value = LFACE_INVERSE (lface); ASET (lface, LFACE_INVERSE_INDEX, value); } + else if (EQ (attr, QCextend)) + { + if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) + { + CHECK_SYMBOL (value); + if (!EQ (value, Qt) && !NILP (value)) + signal_error ("Invalid extend face attribute value", value); + } + old_value = LFACE_EXTEND (lface); + ASET (lface, LFACE_EXTEND_INDEX, value); + } else if (EQ (attr, QCforeground)) { /* Compatibility with 20.x. */ @@ -3503,7 +3526,9 @@ DEFUN ("internal-set-lisp-face-attribute-from-resource", value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCweight) || EQ (attr, QCslant) || EQ (attr, QCwidth)) value = intern (SSDATA (value)); - else if (EQ (attr, QCreverse_video) || EQ (attr, QCinverse_video)) + else if (EQ (attr, QCreverse_video) + || EQ (attr, QCinverse_video) + || EQ (attr, QCextend)) value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCunderline) || EQ (attr, QCoverline) @@ -3727,6 +3752,8 @@ DEFUN ("internal-get-lisp-face-attribute", Finternal_get_lisp_face_attribute, value = LFACE_SWIDTH (lface); else if (EQ (keyword, QCinherit)) value = LFACE_INHERIT (lface); + else if (EQ (keyword, QCextend)) + value = LFACE_EXTEND (lface); else if (EQ (keyword, QCfont)) value = LFACE_FONT (lface); else if (EQ (keyword, QCfontset)) @@ -3754,7 +3781,9 @@ DEFUN ("internal-lisp-face-attribute-values", if (EQ (attr, QCunderline) || EQ (attr, QCoverline) || EQ (attr, QCstrike_through) - || EQ (attr, QCinverse_video) || EQ (attr, QCreverse_video)) + || EQ (attr, QCinverse_video) + || EQ (attr, QCreverse_video) + || EQ (attr, QCextend)) result = list2 (Qt, Qnil); return result; @@ -4782,6 +4811,9 @@ gui_supports_face_attributes_p (struct frame *f, || (!UNSPECIFIEDP (attrs[LFACE_INVERSE_INDEX]) && face_attr_equal_p (attrs[LFACE_INVERSE_INDEX], def_attrs[LFACE_INVERSE_INDEX])) + || (!UNSPECIFIEDP (attrs[LFACE_EXTEND_INDEX]) + && face_attr_equal_p (attrs[LFACE_EXTEND_INDEX], + def_attrs[LFACE_EXTEND_INDEX])) || (!UNSPECIFIEDP (attrs[LFACE_FOREGROUND_INDEX]) && face_attr_equal_p (attrs[LFACE_FOREGROUND_INDEX], def_attrs[LFACE_FOREGROUND_INDEX])) @@ -5358,6 +5390,9 @@ realize_default_face (struct frame *f) ASET (lface, LFACE_FONTSET_INDEX, Qnil); } + if (UNSPECIFIEDP (LFACE_EXTEND (lface))) + ASET (lface, LFACE_EXTEND_INDEX, Qnil); + if (UNSPECIFIEDP (LFACE_UNDERLINE (lface))) ASET (lface, LFACE_UNDERLINE_INDEX, Qnil); @@ -5694,16 +5729,14 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] if (EQ (underline, Qt)) { /* Use default color (same as foreground color). */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = true; face->underline_color = 0; } else if (STRINGP (underline)) { /* Use specified color. */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = false; face->underline_color = load_color (f, face, underline, @@ -5711,7 +5744,7 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] } else if (NILP (underline)) { - face->underline_p = false; + face->underline = FACE_NO_UNDERLINE; face->underline_defaulted_p = false; face->underline_color = 0; } @@ -5719,10 +5752,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] { /* `(:color COLOR :style STYLE)'. STYLE being one of `line' or `wave'. */ - face->underline_p = true; + face->underline = FACE_UNDER_LINE; face->underline_color = 0; face->underline_defaulted_p = true; - face->underline_type = FACE_UNDER_LINE; /* FIXME? This is also not robust about checking the precise form. See comments in Finternal_set_lisp_face_attribute. */ @@ -5755,9 +5787,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] else if (EQ (keyword, QCstyle)) { if (EQ (value, Qline)) - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; else if (EQ (value, Qwave)) - face->underline_type = FACE_UNDER_WAVE; + face->underline = FACE_UNDER_WAVE; } } } @@ -6292,9 +6324,8 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, { struct frame *f = WINDOW_XFRAME (w); Lisp_Object attrs[LFACE_VECTOR_SIZE]; - struct face *base_face; + struct face *base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); - base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); if (!base_face) return base_face_id; @@ -6319,12 +6350,14 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, } else { - struct face *face; if (face_id < 0) return base_face_id; - face = FACE_FROM_ID_OR_NULL (f, face_id); + + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); + if (!face) return base_face_id; + merge_face_vectors (w, f, face->lface, attrs, 0); } @@ -6412,7 +6445,7 @@ dump_realized_face (struct face *face) #endif fprintf (stderr, "fontset: %d\n", face->fontset); fprintf (stderr, "underline: %d (%s)\n", - face->underline_p, + face->underline, SDATA (Fsymbol_name (face->lface[LFACE_UNDERLINE_INDEX]))); fprintf (stderr, "hash: %" PRIuPTR "\n", face->hash); } @@ -6537,6 +6570,7 @@ syms_of_xfaces (void) DEFSYM (QCstrike_through, ":strike-through"); DEFSYM (QCbox, ":box"); DEFSYM (QCinherit, ":inherit"); + DEFSYM (QCextend, ":extend"); /* Symbols used for Lisp face attribute values. */ DEFSYM (QCcolor, ":color"); diff --git a/src/xterm.c b/src/xterm.c index b761eaf4d1..b8f8db56a7 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3798,9 +3798,9 @@ x_draw_glyph_string (struct glyph_string *s) if (!s->for_overlaps) { /* Draw underline. */ - if (s->face->underline_p) + if (s->face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { if (s->face->underline_defaulted_p) x_draw_underwave (s); @@ -3814,13 +3814,13 @@ x_draw_glyph_string (struct glyph_string *s) XSetForeground (display, s->gc, xgcv.foreground); } } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { unsigned long thickness, position; int y; - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE) + if (s->prev && + s->prev->face->underline == FACE_UNDER_LINE) { /* We use the same underline style as the previous one. */ thickness = s->prev->underline_thickness; ^ permalink raw reply related [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-05 19:26 ` Question about display engine Ergus @ 2019-09-06 8:22 ` martin rudalics 2019-09-06 9:31 ` Ergus 2019-09-06 8:55 ` Eli Zaretskii 1 sibling, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-06 8:22 UTC (permalink / raw) To: Ergus; +Cc: eliz, emacs-devel Thanks for the new patch. It applies and Emacs builds here on Windows without problems. > The issue is actually related with the fact that > extend_face_id is never restarted to face_id when going back from an > extend to a non_extend face between lines (for example when mark is > active and the iterator crosses the pointer to outside the selected > region like in the picture). The end of the region is a stop position for the iterator. It can occur in the middle of a line, so handling this problem at the beginning of a display line would be neither sufficient nor useful. When the stop position coinciding with the end of the region is processed, the extend_face_id has to be reset to some new face_id at that position. I'm yet too silly to understand your patch so I cannot figure out where this should happen. But the following parts appear somehow suspicious: /* Update the faces id and extend. */ it->face_id = new_face_id; if (FACE_EXTENSIBLE_P (new_face)) it->extend_face_id = new_face_id; At the end of the region this may get you a new_face that is not extensible. But that means that you do not reset it->extend_face_id although you should (IMHO). Just to make sure that we see the same things: Is my interpretation correct that in your screenshot you use blue for the region and black as default background and the regions starts at line 9 of your window? martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-06 8:22 ` martin rudalics @ 2019-09-06 9:31 ` Ergus 2019-09-07 6:52 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-06 9:31 UTC (permalink / raw) To: martin rudalics; +Cc: eliz, emacs-devel On Fri, Sep 06, 2019 at 10:22:48AM +0200, martin rudalics wrote: >Thanks for the new patch. It applies and Emacs builds here on Windows >without problems. > >> The issue is actually related with the fact that >> extend_face_id is never restarted to face_id when going back from an >> extend to a non_extend face between lines (for example when mark is >> active and the iterator crosses the pointer to outside the selected >> region like in the picture). > >The end of the region is a stop position for the iterator. It can >occur in the middle of a line, so handling this problem at the >beginning of a display line would be neither sufficient nor useful. >When the stop position coinciding with the end of the region is >processed, the extend_face_id has to be reset to some new face_id at >that position. > >I'm yet too silly to understand your patch so I cannot figure out >where this should happen. But the following parts appear somehow >suspicious: > > /* Update the faces id and extend. */ > it->face_id = new_face_id; > > if (FACE_EXTENSIBLE_P (new_face)) > it->extend_face_id = new_face_id; > >At the end of the region this may get you a new_face that is not >extensible. But that means that you do not reset it->extend_face_id >although you should (IMHO). > >Just to make sure that we see the same things: Is my interpretation >correct that in your screenshot you use blue for the region and black >as default background and the regions starts at line 9 of your window? > Yes that's it. >martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-06 9:31 ` Ergus @ 2019-09-07 6:52 ` martin rudalics 2019-09-07 7:37 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-07 6:52 UTC (permalink / raw) To: Ergus; +Cc: eliz, emacs-devel >> Just to make sure that we see the same things: Is my interpretation >> correct that in your screenshot you use blue for the region and black >> as default background and the regions starts at line 9 of your window? >> > Yes that's it. When I set the :extend attribute of the default face, everything seems to work as expected. The problem is that if, in the earlier mentioned, /* Update the faces id and extend. */ it->face_id = new_face_id; if (FACE_EXTENSIBLE_P (new_face)) it->extend_face_id = new_face_id; no extensible new face is found, the assignment fails and the old region background stays in place for the rest of the window. So it seems that you have to make sure that _some_ default background is always assigned here in case no face applied has the :extend attribute set. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-07 6:52 ` martin rudalics @ 2019-09-07 7:37 ` Eli Zaretskii 2019-09-07 7:55 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-07 7:37 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: eliz@gnu.org, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sat, 7 Sep 2019 08:52:56 +0200 > > When I set the :extend attribute of the default face, everything seems > to work as expected. The problem is that if, in the earlier mentioned, > > /* Update the faces id and extend. */ > it->face_id = new_face_id; > > if (FACE_EXTENSIBLE_P (new_face)) > it->extend_face_id = new_face_id; > > no extensible new face is found, the assignment fails and the old > region background stays in place for the rest of the window. So it > seems that you have to make sure that _some_ default background is > always assigned here in case no face applied has the :extend attribute > set. The default face should always be merged into the face used for line extension, that goes without saying. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-07 7:37 ` Eli Zaretskii @ 2019-09-07 7:55 ` Eli Zaretskii 2019-09-08 0:51 ` Ergus via Emacs development discussions. 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-07 7:55 UTC (permalink / raw) To: rudalics, spacibba; +Cc: emacs-devel > Date: Sat, 07 Sep 2019 10:37:07 +0300 > From: Eli Zaretskii <eliz@gnu.org> > Cc: spacibba@aol.com, emacs-devel@gnu.org > > The default face should always be merged into the face used for line > extension, that goes without saying. IOW, the default face should always be treated as having the :extend attribute by default. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-07 7:55 ` Eli Zaretskii @ 2019-09-08 0:51 ` Ergus via Emacs development discussions. 2019-09-08 8:40 ` martin rudalics 2019-09-08 17:51 ` Eli Zaretskii 0 siblings, 2 replies; 183+ messages in thread From: Ergus via Emacs development discussions. @ 2019-09-08 0:51 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel [-- Attachment #1: Type: text/plain, Size: 2064 bytes --] Hi Eli and Martin: Please give a look to the attached patch and check if it is working fine for you. (I added a new branch "extend_face_id" in savannah too) I tried to make it as optimized and less changes as possible from the beginning. In general I added a parameter to handle_face_prop renamed to handle_face_prop_general (keeping the original name as a wrapper with the same signature.) And the extra parameter is an enum lface_attribute_index. The parameter is passed from function to function until merge_named_face which checks: (attr_filter == 0 || (!NILP (from[attr_filter]) && !UNSPECIFIEDP (from[attr_filter]))) So if we pass zero as the parameter then the merge is unconditional; else the attribute needs to be non-nil and specified to merge. I made it in this way because it is general enough and with low overhead in case we want to condition the merge for different conditions in the future. Right now only region is extensible by default. So you can try with region and hl-line-mode for example. I added also the commands to change extensibility set-face-extend and the internal lisp commands to get/set extend as usual. Now the only annoying thing is that when extend is disabled for the region, the extra space after eol has the same face than the text before (which for me is fine) but in the terminal it is not added... so I should ask if you consider correct to add the space in terminal or remove the extra "colored" space in gui? I vote for the first... but you say. (I made some changes in the extend_face_to_end_of_line code related with fill column indicator to reuse part of the code and avoid unneeded duplication. On Sat, Sep 07, 2019 at 10:55:14AM +0300, Eli Zaretskii wrote: >> Date: Sat, 07 Sep 2019 10:37:07 +0300 >> From: Eli Zaretskii <eliz@gnu.org> >> Cc: spacibba@aol.com, emacs-devel@gnu.org >> >> The default face should always be merged into the face used for line >> extension, that goes without saying. > >IOW, the default face should always be treated as having the :extend >attribute by default. > [-- Attachment #2: test.patch --] [-- Type: text/plain, Size: 46270 bytes --] diff --git a/lisp/cus-face.el b/lisp/cus-face.el index d73bce42c3..5a49a81043 100644 --- a/lisp/cus-face.el +++ b/lisp/cus-face.el @@ -233,7 +233,11 @@ custom-face-attributes (file :tag "File" :help-echo "Name of bitmap file." :must-match t))) - + (:extend + (choice :tag "Extend" + :help-echo "Control whether attributes should be extended after EOL." + (const :tag "Off" nil) + (const :tag "On" t))) (:inherit (repeat :tag "Inherit" :help-echo "List of faces to inherit attributes from." diff --git a/lisp/faces.el b/lisp/faces.el index 5193c216d0..814a4b2c9a 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -342,6 +342,7 @@ face-x-resources (:box (".attributeBox" . "Face.AttributeBox")) (:underline (".attributeUnderline" . "Face.AttributeUnderline")) (:inverse-video (".attributeInverse" . "Face.AttributeInverse")) + (:extend (".attributeExtend" . "Face.AttributeExtend")) (:stipple (".attributeStipple" . "Face.AttributeStipple") (".attributeBackgroundPixmap" . "Face.AttributeBackgroundPixmap")) @@ -594,6 +595,13 @@ face-italic-p (let ((italic (face-attribute face :slant frame inherit))) (memq italic '(italic oblique)))) +(defun face-extend-p (face &optional frame inherit) + "Return non-nil if FACE specifies a non-nil extend. +If the optional argument FRAME is given, report on face FACE in that frame. +If FRAME is t, report on the defaults for face FACE (for new frames). +If FRAME is omitted or nil, use the selected frame. +Optional argument INHERIT is passed to `face-attribute'." + (eq (face-attribute face :extend frame inherit) t)) \f ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -760,6 +768,11 @@ set-face-attribute `:height', `:weight', and `:slant' may also be set in one step from an X font name: +`:extend' + +VALUE specifies whether the FACE should be extended after EOL. +VALUE must be one of t or nil. + `:font' Set font-related face attributes from VALUE. @@ -979,6 +992,18 @@ set-face-italic (define-obsolete-function-alias 'set-face-italic-p 'set-face-italic "24.4") +(defun set-face-extend (face extend-p &optional frame) + "Specify whether face FACE should be extended. +EXTEND-P nil means FACE explicitly doesn't extend after EOL. +EXTEND-P t means FACE extends after EOL. + +FRAME nil or not specified means change face on all frames. +Use `set-face-attribute' to \"unspecify\" underlining." + (interactive + (let ((list (read-face-and-attribute :extend))) + (list (car list) (if (cadr list) t)))) + (set-face-attribute face frame :extend extend-p)) + (defalias 'set-face-background-pixmap 'set-face-stipple) @@ -1102,7 +1127,7 @@ face-valid-attribute-values (:slant (mapcar #'(lambda (x) (cons (symbol-name (aref x 1)) (aref x 1))) font-slant-table)) - (:inverse-video + ((or :inverse-video :extend) (mapcar #'(lambda (x) (cons (symbol-name x) x)) (internal-lisp-face-attribute-values attribute))) ((or :underline :overline :strike-through :box) @@ -1147,6 +1172,7 @@ face-attribute-name-alist (:slant . "slant") (:underline . "underline") (:overline . "overline") + (:extend . "extend") (:strike-through . "strike-through") (:box . "box") (:inverse-video . "inverse-video display") @@ -1448,6 +1474,7 @@ describe-face (:stipple . "Stipple") (:font . "Font") (:fontset . "Fontset") + (:extend . "Extend") (:inherit . "Inherit"))) (max-width (apply #'max (mapcar #'(lambda (x) (length (cdr x))) attrs)))) @@ -1667,7 +1694,8 @@ face-spec-reset-face ;; (see also realize_default_face in xfaces.c). (append '(:underline nil :overline nil :strike-through nil - :box nil :inverse-video nil :stipple nil :inherit nil) + :box nil :inverse-video nil :stipple nil :inherit nil + :extend nil) ;; `display-graphic-p' is unavailable when running ;; temacs, prior to loading frame.el. (when (fboundp 'display-graphic-p) @@ -2432,24 +2460,24 @@ highlight ;; if background is light. (defface region '((((class color) (min-colors 88) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 88) (background light) (type gtk)) :distant-foreground "gtk_selection_fg_color" - :background "gtk_selection_bg_color") + :background "gtk_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light) (type ns)) :distant-foreground "ns_selection_fg_color" - :background "ns_selection_bg_color") + :background "ns_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 16) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 16) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 8)) - :background "blue" :foreground "white") + :background "blue" :foreground "white" :extend t) (((type tty) (class mono)) :inverse-video t) - (t :background "gray")) + (t :background "gray" :extend t)) "Basic face for highlighting the region." :version "21.1" :group 'basic-faces) diff --git a/src/dispextern.h b/src/dispextern.h index 05f199ff35..de438e069e 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1564,6 +1564,7 @@ #define FONT_TOO_HIGH(ft) \ LFACE_INHERIT_INDEX, LFACE_FONTSET_INDEX, LFACE_DISTANT_FOREGROUND_INDEX, + LFACE_EXTEND_INDEX, LFACE_VECTOR_SIZE }; @@ -1589,6 +1590,7 @@ #define FONT_TOO_HIGH(ft) \ enum face_underline_type { + FACE_NO_UNDERLINE = 0, FACE_UNDER_LINE, FACE_UNDER_WAVE }; @@ -1632,11 +1634,9 @@ #define FONT_TOO_HIGH(ft) \ /* Pixel value or color index of background color. */ unsigned long background; - /* Pixel value or color index of underline color. */ + /* Pixel value or color index of underline, overlined, + strike-through, or box color. */ unsigned long underline_color; - - /* Pixel value or color index of overlined, strike-through, or box - color. */ unsigned long overline_color; unsigned long strike_through_color; unsigned long box_color; @@ -1663,7 +1663,7 @@ #define FONT_TOO_HIGH(ft) \ ENUM_BF (face_box_type) box : 2; /* Style of underlining. */ - ENUM_BF (face_underline_type) underline_type : 1; + ENUM_BF (face_underline_type) underline : 2; /* If `box' above specifies a 3D type, true means use box_color for drawing shadows. */ @@ -1671,7 +1671,6 @@ #define FONT_TOO_HIGH(ft) \ /* Non-zero if text in this face should be underlined, overlined, strike-through or have a box drawn around it. */ - bool_bf underline_p : 1; bool_bf overline_p : 1; bool_bf strike_through_p : 1; @@ -1681,14 +1680,10 @@ #define FONT_TOO_HIGH(ft) \ bool_bf foreground_defaulted_p : 1; bool_bf background_defaulted_p : 1; - /* True means that either no color is specified for underlining or that - the specified color couldn't be loaded. Use the foreground - color when drawing in that case. */ - bool_bf underline_defaulted_p : 1; - /* True means that either no color is specified for the corresponding attribute or that the specified color couldn't be loaded. Use the foreground color when drawing in that case. */ + bool_bf underline_defaulted_p : 1; bool_bf overline_color_defaulted_p : 1; bool_bf strike_through_color_defaulted_p : 1; bool_bf box_color_defaulted_p : 1; @@ -1822,6 +1817,9 @@ #define FACE_FROM_ID_OR_NULL(F, ID) \ ? FRAME_FACE_CACHE (F)->faces_by_id[ID] \ : NULL) +#define FACE_EXTENSIBLE_P(F) \ + (!NILP (F->lface[LFACE_EXTEND_INDEX])) + /* True if FACE is suitable for displaying ASCII characters. */ INLINE bool FACE_SUITABLE_FOR_ASCII_CHAR_P (struct face *face) @@ -2328,7 +2326,7 @@ #define IT_STACK_SIZE 5 /* Face id of the iterator saved in case a glyph from dpvec contains a face. The face is restored when all glyphs from dpvec have been delivered. */ - int saved_face_id; + int saved_face_id, saved_extend_face_id; /* Vector of glyphs for control character translation. The pointer dpvec is set to ctl_chars when a control character is translated. @@ -2390,7 +2388,7 @@ #define OVERLAY_STRING_CHUNK_SIZE 16 ptrdiff_t prev_stop; ptrdiff_t base_level_stop; struct composition_it cmp_it; - int face_id; + int face_id, extend_face_id; /* Save values specific to a given method. */ union { @@ -2448,6 +2446,9 @@ #define OVERLAY_STRING_CHUNK_SIZE 16 /* Face to use. */ int face_id; + /* Face to extend at EOL/ */ + int extend_face_id; + /* Setting of buffer-local variable selective-display-ellipses. */ bool_bf selective_display_ellipsis_p : 1; @@ -3458,8 +3459,8 @@ #define RGB_PIXEL_COLOR COLORREF void init_frame_faces (struct frame *); void free_frame_faces (struct frame *); void recompute_basic_faces (struct frame *); -int face_at_buffer_position (struct window *, ptrdiff_t, ptrdiff_t *, ptrdiff_t, - bool, int); +int face_at_buffer_position (struct window *, ptrdiff_t, ptrdiff_t *, + ptrdiff_t, bool, int, enum lface_attribute_index); int face_for_overlay_string (struct window *, ptrdiff_t, ptrdiff_t *, ptrdiff_t, bool, Lisp_Object); int face_at_string_position (struct window *, Lisp_Object, ptrdiff_t, ptrdiff_t, diff --git a/src/font.c b/src/font.c index 935dd64e64..2b16839bba 100644 --- a/src/font.c +++ b/src/font.c @@ -3781,10 +3781,10 @@ font_at (int c, ptrdiff_t pos, struct face *face, struct window *w, if (STRINGP (string)) face_id = face_at_string_position (w, string, pos, 0, &endptr, - DEFAULT_FACE_ID, false); + DEFAULT_FACE_ID, 0); else face_id = face_at_buffer_position (w, pos, &endptr, - pos + 100, false, -1); + pos + 100, false, -1, 0); face = FACE_FROM_ID (f, face_id); } if (multibyte) @@ -3828,7 +3828,7 @@ font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit, if (NILP (string)) face_id = face_at_buffer_position (w, pos, &ignore, *limit, - false, -1); + false, -1, 0); else { face_id = @@ -4614,7 +4614,7 @@ DEFUN ("internal-char-font", Finternal_char_font, Sinternal_char_font, 1, 2, 0, w = XWINDOW (window); f = XFRAME (w->frame); face_id = face_at_buffer_position (w, pos, &dummy, - pos + 100, false, -1); + pos + 100, false, -1, 0); } if (! CHAR_VALID_P (c)) return Qnil; diff --git a/src/nsterm.m b/src/nsterm.m index 42ef4dd010..99b621533a 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3404,9 +3404,9 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; /* Do underline. */ - if (face->underline_p) + if (face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { if (face->underline_defaulted_p) [defaultCol set]; @@ -3415,15 +3415,15 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. ns_draw_underwave (s, width, x); } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { NSRect r; unsigned long thickness, position; /* If the prev was underlined, match its appearance. */ - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE + if (s->prev + && s->prev->face->underline == FACE_UNDER_LINE && s->prev->underline_thickness > 0) { thickness = s->prev->underline_thickness; diff --git a/src/w32term.c b/src/w32term.c index e5874f2d36..99a1db5784 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -2479,9 +2479,9 @@ w32_draw_glyph_string (struct glyph_string *s) if (!s->for_overlaps) { /* Draw underline. */ - if (s->face->underline_p) + if (s->face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { COLORREF color; @@ -2492,13 +2492,13 @@ w32_draw_glyph_string (struct glyph_string *s) w32_draw_underwave (s, color); } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { unsigned long thickness, position; int y; - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE) + if (s->prev + && s->prev->face->underline == FACE_UNDER_LINE) { /* We use the same underline style as the previous one. */ thickness = s->prev->underline_thickness; @@ -2512,7 +2512,7 @@ w32_draw_glyph_string (struct glyph_string *s) BOOL use_underline_position_properties; Lisp_Object val = buffer_local_value (Qunderline_minimum_offset, - s->w->contents); + s->w->contents); if (FIXNUMP (val)) minimum_offset = max (0, XFIXNUM (val)); else diff --git a/src/xdisp.c b/src/xdisp.c index 94f969f37c..9fb4f6be58 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -4105,15 +4105,18 @@ handle_fontified_prop (struct it *it) Faces ***********************************************************************/ -/* Set up iterator IT from face properties at its current position. - Called from handle_stop. */ - static enum prop_handled -handle_face_prop (struct it *it) +handle_face_prop_general (struct it *it, + enum lface_attribute_index attr_filter) { - int new_face_id; + int new_face_id, *face_id_ptr; ptrdiff_t next_stop; + if (attr_filter == LFACE_EXTEND_INDEX) + face_id_ptr = &(it->extend_face_id); + else + face_id_ptr = &(it->face_id); + if (!STRINGP (it->string)) { new_face_id @@ -4122,7 +4125,7 @@ handle_face_prop (struct it *it) &next_stop, (IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT), - false, it->base_face_id); + false, it->base_face_id, attr_filter); /* Is this a start of a run of characters with box face? Caveat: this can be called for a freshly initialized @@ -4130,13 +4133,13 @@ handle_face_prop (struct it *it) face will not change until limit, i.e. if the new face has a box, all characters up to limit will have one. But, as usual, we don't know whether limit is really the end. */ - if (new_face_id != it->face_id) + if (new_face_id != *face_id_ptr) { struct face *new_face = FACE_FROM_ID (it->f, new_face_id); /* If it->face_id is -1, old_face below will be NULL, see the definition of FACE_FROM_ID_OR_NULL. This will happen if this is the initial call that gets the face. */ - struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id); + struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, *face_id_ptr); /* If the value of face_id of the iterator is -1, we have to look in front of IT's position and see whether there is a @@ -4242,10 +4245,10 @@ handle_face_prop (struct it *it) box, all characters up to that position will have a box. But, as usual, we don't know whether that position is really the end. */ - if (new_face_id != it->face_id) + if (new_face_id != *face_id_ptr) { struct face *new_face = FACE_FROM_ID (it->f, new_face_id); - struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id); + struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, *face_id_ptr); /* If new face has a box but old face hasn't, this is the start of a run of characters with box, i.e. it has a @@ -4256,11 +4259,21 @@ handle_face_prop (struct it *it) } } - it->face_id = new_face_id; + *face_id_ptr = new_face_id; return HANDLED_NORMALLY; } +/* Set up iterator IT from face properties at its current position. + Called from handle_stop. */ + +static enum prop_handled +handle_face_prop (struct it *it) +{ + return handle_face_prop_general (it, 0); +} + + /* Return the ID of the face ``underlying'' IT's current position, which is in a string. If the iterator is associated with a buffer, return the face at IT's current buffer position. @@ -4474,7 +4487,7 @@ face_before_or_after_it_pos (struct it *it, bool before_p) face_id = face_at_buffer_position (it->w, CHARPOS (pos), &next_check_charpos, - limit, false, -1); + limit, false, -1, 0); /* Correct the face for charsets different from ASCII. Do it for the multibyte case only. The face returned above is @@ -7596,10 +7609,11 @@ get_next_display_element (struct it *it) else { next_face_id = - face_at_buffer_position (it->w, CHARPOS (pos), &ignore, + face_at_buffer_position (it->w, CHARPOS (pos), + &ignore, CHARPOS (pos) + TEXT_PROP_DISTANCE_LIMIT, - false, -1); + false, -1, 0); it->end_of_box_run_p = (FACE_FROM_ID (it->f, next_face_id)->box == FACE_NO_BOX); @@ -20482,12 +20496,14 @@ extend_face_to_end_of_line (struct it *it) || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) return; - /* Face extension extends the background and box of IT->face_id + handle_face_prop_general (it, LFACE_EXTEND_INDEX); + + /* Face extension extends the background and box of IT->extend_face_id to the end of the line. If the background equals the background of the frame, we don't have to do anything. */ face = FACE_FROM_ID (f, (it->face_before_selective_p ? it->saved_face_id - : it->face_id)); + : it->extend_face_id)); if (FRAME_WINDOW_P (f) && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) @@ -20510,9 +20526,7 @@ extend_face_to_end_of_line (struct it *it) that the character will always be single byte in unibyte text. */ if (!ASCII_CHAR_P (it->c)) - { it->face_id = FACE_FOR_CHAR (f, face, 0, -1, Qnil); - } /* The default face, possibly remapped. */ struct face *default_face = @@ -20561,79 +20575,86 @@ extend_face_to_end_of_line (struct it *it) /* Display fill column indicator if not in modeline or toolbar and display fill column indicator mode is active. */ - int indicator_column = (it->w->pseudo_window_p == 0 + const int indicator_column = (it->w->pseudo_window_p == 0 ? fill_column_indicator_column (it) : -1); - if (indicator_column >= 0) + + struct font *font = (default_face->font + ? default_face->font + : FRAME_FONT (f)); + + const int char_width = (font->average_width + ? font->average_width + : font->space_width); + int column_x; + + const char saved_char = it->char_to_display; + const struct text_pos saved_pos = it->position; + const bool saved_avoid_cursor = it->avoid_cursor_p; + const bool saved_box_start = it->start_of_box_run_p; + Lisp_Object save_object = it->object; + const int saved_face_id = it->face_id; + + it->face_id = it->extend_face_id; + + if (indicator_column >= 0 + && !INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) + && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) + && column_x >= it->current_x + && column_x <= it->last_visible_x) { - struct font *font = (default_face->font - ? default_face->font - : FRAME_FONT (f)); - const int char_width = (font->average_width - ? font->average_width - : font->space_width); - int column_x; - - if (!INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) - && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) - && column_x >= it->current_x - && column_x <= it->last_visible_x) - { - const char saved_char = it->char_to_display; - const struct text_pos saved_pos = it->position; - const bool saved_avoid_cursor = it->avoid_cursor_p; - const int saved_face_id = it->face_id; - const bool saved_box_start = it->start_of_box_run_p; - Lisp_Object save_object = it->object; - - /* The stretch width needs to considet the latter - added glyph. */ - const int stretch_width - = column_x - it->current_x - char_width; - - memset (&it->position, 0, sizeof it->position); - it->avoid_cursor_p = true; - it->object = Qnil; - - /* Only generate a stretch glyph if there is distance - between current_x and and the indicator position. */ - if (stretch_width > 0) - { - int stretch_ascent = (((it->ascent + it->descent) - * FONT_BASE (font)) / FONT_HEIGHT (font)); - append_stretch_glyph (it, Qnil, stretch_width, - it->ascent + it->descent, - stretch_ascent); - } - /* Generate the glyph indicator only if - append_space_for_newline didn't already. */ - if (it->current_x < column_x) - { - it->char_to_display - = XFIXNAT (Vdisplay_fill_column_indicator_character); - it->face_id - = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); - PRODUCE_GLYPHS (it); - } - - /* Restore the face after the indicator was generated. */ - it->face_id = saved_face_id; - - /* If there is space after the indicator generate an - extra empty glyph to restore the face. Issue was - observed in X systems. */ - it->char_to_display = ' '; - PRODUCE_GLYPHS (it); - - it->char_to_display = saved_char; - it->position = saved_pos; - it->avoid_cursor_p = saved_avoid_cursor; - it->start_of_box_run_p = saved_box_start; - it->object = save_object; - } + /* The stretch width needs to considet the latter + added glyph. */ + const int stretch_width + = column_x - it->current_x - char_width; + + memset (&it->position, 0, sizeof it->position); + it->avoid_cursor_p = true; + it->object = Qnil; + + /* Only generate a stretch glyph if there is distance + between current_x and and the indicator position. */ + if (stretch_width > 0) + { + int stretch_ascent = (((it->ascent + it->descent) + * FONT_BASE (font)) / FONT_HEIGHT (font)); + append_stretch_glyph (it, Qnil, stretch_width, + it->ascent + it->descent, + stretch_ascent); + } + + /* Generate the glyph indicator only if + append_space_for_newline didn't already. */ + if (it->current_x < column_x) + { + const int save_face_id = it->face_id; + it->char_to_display + = XFIXNAT (Vdisplay_fill_column_indicator_character); + it->face_id + = merge_faces (it->w, Qfill_column_indicator, + 0, it->extend_face_id); + PRODUCE_GLYPHS (it); + it->face_id = save_face_id; + + } } + + /* Restore the face after the indicator was generated. */ + + /* If there is space after the indicator generate an + extra empty glyph to restore the face. Issue was + observed in X systems. */ + it->char_to_display = ' '; + PRODUCE_GLYPHS (it); + + it->char_to_display = saved_char; + it->position = saved_pos; + it->avoid_cursor_p = saved_avoid_cursor; + it->start_of_box_run_p = saved_box_start; + it->object = save_object; + it->face_id = saved_face_id; + } if (it->glyph_row->reversed_p) { @@ -20679,10 +20700,9 @@ extend_face_to_end_of_line (struct it *it) /* The last row's stretch glyph should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ - if (it->glyph_row->ends_at_zv_p) - it->face_id = default_face->id; - else - it->face_id = face->id; + it->face_id = (it->glyph_row->ends_at_zv_p ? + default_face->id : face->id); + it->start_of_box_run_p = false; append_stretch_glyph (it, Qnil, stretch_width, it->ascent + it->descent, stretch_ascent); @@ -20704,14 +20724,11 @@ extend_face_to_end_of_line (struct it *it) { /* Save some values that must not be changed. */ int saved_x = it->current_x; - struct text_pos saved_pos; - Lisp_Object saved_object; + struct text_pos saved_pos = it->position; + Lisp_Object saved_object = it->object;; enum display_element_type saved_what = it->what; int saved_face_id = it->face_id; - saved_object = it->object; - saved_pos = it->position; - it->what = IT_CHARACTER; memset (&it->position, 0, sizeof it->position); it->object = Qnil; @@ -20750,10 +20767,8 @@ extend_face_to_end_of_line (struct it *it) /* The last row's blank glyphs should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ - if (it->glyph_row->ends_at_zv_p) - it->face_id = default_face->id; - else - it->face_id = face->id; + it->face_id = (it->glyph_row->ends_at_zv_p ? + default_face->id : face->id); /* Display fill-column indicator if needed. */ int indicator_column = fill_column_indicator_column (it); @@ -20763,24 +20778,21 @@ extend_face_to_end_of_line (struct it *it) indicator_column = -1; do { - int saved_face_id; - bool indicate = it->current_x == indicator_column; - if (indicate) + if (it->current_x == indicator_column) { - saved_face_id = it->face_id; + int saved_face_id = it->face_id; it->face_id - = merge_faces (it->w, Qfill_column_indicator, 0, saved_face_id); + = merge_faces (it->w, Qfill_column_indicator, 0, it->extend_face_id); it->c = it->char_to_display = XFIXNAT (Vdisplay_fill_column_indicator_character); - } - PRODUCE_GLYPHS (it); + PRODUCE_GLYPHS (it); - if (indicate) - { it->face_id = saved_face_id; it->c = it->char_to_display = ' '; } + else + PRODUCE_GLYPHS (it); } while (it->current_x <= it->last_visible_x); @@ -27355,7 +27367,7 @@ font_for_underline_metrics (struct glyph_string *s) for (g = s->first_glyph - 1; g >= g0; g--) { struct face *prev_face = FACE_FROM_ID (s->f, g->face_id); - if (!(prev_face && prev_face->underline_p)) + if (!(prev_face && prev_face->underline != FACE_NO_UNDERLINE)) break; } @@ -30919,7 +30931,7 @@ mouse_face_from_buffer_pos (Lisp_Object window, hlinfo->mouse_face_face_id = face_at_buffer_position (w, mouse_charpos, &ignore, mouse_charpos + 1, - !hlinfo->mouse_face_hidden, -1); + !hlinfo->mouse_face_hidden, -1, 0); show_mouse_face (hlinfo, DRAW_MOUSE_FACE); } diff --git a/src/xfaces.c b/src/xfaces.c index c3cae7e2a6..7c5a0858bb 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -347,7 +347,8 @@ #define CLEAR_FONT_TABLE_NFONTS 10 static void free_face_cache (struct face_cache *); static bool merge_face_ref (struct window *w, struct frame *, Lisp_Object, Lisp_Object *, - bool, struct named_merge_point *); + bool, struct named_merge_point *, + enum lface_attribute_index); static int color_distance (Emacs_Color *x, Emacs_Color *y); #ifdef HAVE_WINDOW_SYSTEM @@ -1209,7 +1210,7 @@ free_face_colors (struct frame *f, struct face *face) IF_DEBUG (--ncolors_allocated); } - if (face->underline_p + if (face->underline && !face->underline_defaulted_p) { x_free_colors (f, &face->underline_color, 1); @@ -1590,6 +1591,7 @@ #define LFACE_BOX(LFACE) AREF ((LFACE), LFACE_BOX_INDEX) #define LFACE_FONT(LFACE) AREF ((LFACE), LFACE_FONT_INDEX) #define LFACE_INHERIT(LFACE) AREF ((LFACE), LFACE_INHERIT_INDEX) #define LFACE_FONTSET(LFACE) AREF ((LFACE), LFACE_FONTSET_INDEX) +#define LFACE_EXTEND(LFACE) AREF ((LFACE), LFACE_EXTEND_INDEX) #define LFACE_DISTANT_FOREGROUND(LFACE) \ AREF ((LFACE), LFACE_DISTANT_FOREGROUND_INDEX) @@ -1633,6 +1635,10 @@ check_lface_attrs (Lisp_Object attrs[LFACE_VECTOR_SIZE]) || SYMBOLP (attrs[LFACE_UNDERLINE_INDEX]) || STRINGP (attrs[LFACE_UNDERLINE_INDEX]) || CONSP (attrs[LFACE_UNDERLINE_INDEX])); + eassert (UNSPECIFIEDP (attrs[LFACE_EXTEND_INDEX]) + || IGNORE_DEFFACE_P (attrs[LFACE_EXTEND_INDEX]) + || SYMBOLP (attrs[LFACE_EXTEND_INDEX]) + || STRINGP (attrs[LFACE_EXTEND_INDEX])); eassert (UNSPECIFIEDP (attrs[LFACE_OVERLINE_INDEX]) || IGNORE_DEFFACE_P (attrs[LFACE_OVERLINE_INDEX]) || SYMBOLP (attrs[LFACE_OVERLINE_INDEX]) @@ -1905,7 +1911,8 @@ get_lface_attributes (struct window *w, attrs[i] = Qunspecified; return merge_face_ref (w, f, XCDR (face_remapping), attrs, - signal_p, named_merge_points); + signal_p, named_merge_points, + 0); } } @@ -2060,7 +2067,8 @@ merge_face_vectors (struct window *w, if (!UNSPECIFIEDP (from[LFACE_INHERIT_INDEX]) && !NILP (from[LFACE_INHERIT_INDEX])) merge_face_ref (w, f, from[LFACE_INHERIT_INDEX], - to, false, named_merge_points); + to, false, named_merge_points, + 0); if (FONT_SPEC_P (from[LFACE_FONT_INDEX])) { @@ -2126,7 +2134,8 @@ merge_face_vectors (struct window *w, static bool merge_named_face (struct window *w, struct frame *f, Lisp_Object face_name, Lisp_Object *to, - struct named_merge_point *named_merge_points) + struct named_merge_point *named_merge_points, + enum lface_attribute_index attr_filter) { struct named_merge_point named_merge_point; @@ -2136,9 +2145,13 @@ merge_named_face (struct window *w, { Lisp_Object from[LFACE_VECTOR_SIZE]; bool ok = get_lface_attributes (w, f, face_name, from, false, - named_merge_points); + named_merge_points); - if (ok) + eassert (attr_filter < LFACE_VECTOR_SIZE); + + if (ok && (attr_filter == 0 + || (!NILP (from[attr_filter]) + && !UNSPECIFIEDP (from[attr_filter])))) merge_face_vectors (w, f, from, to, named_merge_points); return ok; @@ -2269,6 +2282,11 @@ filter_face_ref (Lisp_Object face_ref, of ERR_MSGS). Use NAMED_MERGE_POINTS to detect loops in face inheritance or list structure; it may be 0 for most callers. + attr_filter is the index of a parameter that conditions the merging + for named faces (case 1) to only the face_ref where + lface[merge_face_ref] is non-nil. To merge unconditionally set this + value to 0. + FACE_REF may be a single face specification or a list of such specifications. Each face specification can be: @@ -2297,7 +2315,8 @@ filter_face_ref (Lisp_Object face_ref, static bool merge_face_ref (struct window *w, struct frame *f, Lisp_Object face_ref, Lisp_Object *to, - bool err_msgs, struct named_merge_point *named_merge_points) + bool err_msgs, struct named_merge_point *named_merge_points, + enum lface_attribute_index attr_filter) { bool ok = true; /* Succeed without an error? */ Lisp_Object filtered_face_ref; @@ -2509,7 +2528,15 @@ merge_face_ref (struct window *w, /* This is not really very useful; it's just like a normal face reference. */ if (! merge_face_ref (w, f, value, to, - err_msgs, named_merge_points)) + err_msgs, named_merge_points, + 0)) + err = true; + } + else if (EQ (keyword, QCextend)) + { + if (EQ (value, Qt) || NILP (value)) + to[LFACE_EXTEND_INDEX] = value; + else err = true; } else @@ -2532,16 +2559,19 @@ merge_face_ref (struct window *w, Lisp_Object next = XCDR (face_ref); if (! NILP (next)) - ok = merge_face_ref (w, f, next, to, err_msgs, named_merge_points); + ok = merge_face_ref (w, f, next, to, err_msgs, + named_merge_points, 0); - if (! merge_face_ref (w, f, first, to, err_msgs, named_merge_points)) + if (! merge_face_ref (w, f, first, to, err_msgs, + named_merge_points, 0)) ok = false; } } else { /* FACE_REF ought to be a face name. */ - ok = merge_named_face (w, f, face_ref, to, named_merge_points); + ok = merge_named_face (w, f, face_ref, to, named_merge_points, + attr_filter); if (!ok && err_msgs) add_to_log ("Invalid face reference: %s", face_ref); } @@ -3030,6 +3060,17 @@ DEFUN ("internal-set-lisp-face-attribute", Finternal_set_lisp_face_attribute, old_value = LFACE_INVERSE (lface); ASET (lface, LFACE_INVERSE_INDEX, value); } + else if (EQ (attr, QCextend)) + { + if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) + { + CHECK_SYMBOL (value); + if (!EQ (value, Qt) && !NILP (value)) + signal_error ("Invalid extend face attribute value", value); + } + old_value = LFACE_EXTEND (lface); + ASET (lface, LFACE_EXTEND_INDEX, value); + } else if (EQ (attr, QCforeground)) { /* Compatibility with 20.x. */ @@ -3503,7 +3544,9 @@ DEFUN ("internal-set-lisp-face-attribute-from-resource", value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCweight) || EQ (attr, QCslant) || EQ (attr, QCwidth)) value = intern (SSDATA (value)); - else if (EQ (attr, QCreverse_video) || EQ (attr, QCinverse_video)) + else if (EQ (attr, QCreverse_video) + || EQ (attr, QCinverse_video) + || EQ (attr, QCextend)) value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCunderline) || EQ (attr, QCoverline) @@ -3727,6 +3770,8 @@ DEFUN ("internal-get-lisp-face-attribute", Finternal_get_lisp_face_attribute, value = LFACE_SWIDTH (lface); else if (EQ (keyword, QCinherit)) value = LFACE_INHERIT (lface); + else if (EQ (keyword, QCextend)) + value = LFACE_EXTEND (lface); else if (EQ (keyword, QCfont)) value = LFACE_FONT (lface); else if (EQ (keyword, QCfontset)) @@ -3754,7 +3799,9 @@ DEFUN ("internal-lisp-face-attribute-values", if (EQ (attr, QCunderline) || EQ (attr, QCoverline) || EQ (attr, QCstrike_through) - || EQ (attr, QCinverse_video) || EQ (attr, QCreverse_video)) + || EQ (attr, QCinverse_video) + || EQ (attr, QCreverse_video) + || EQ (attr, QCextend)) result = list2 (Qt, Qnil); return result; @@ -4505,7 +4552,8 @@ lookup_face (struct frame *f, Lisp_Object *attr) suitable face is found, realize a new one. */ int -face_for_font (struct frame *f, Lisp_Object font_object, struct face *base_face) +face_for_font (struct frame *f, Lisp_Object font_object, + struct face *base_face) { struct face_cache *cache = FRAME_FACE_CACHE (f); unsigned hash; @@ -4738,7 +4786,7 @@ DEFUN ("face-attributes-as-vector", Fface_attributes_as_vector, Lisp_Object lface = make_vector (LFACE_VECTOR_SIZE, Qunspecified); merge_face_ref (NULL, XFRAME (selected_frame), plist, XVECTOR (lface)->contents, - true, 0); + true, NULL, 0); return lface; } @@ -4782,6 +4830,9 @@ gui_supports_face_attributes_p (struct frame *f, || (!UNSPECIFIEDP (attrs[LFACE_INVERSE_INDEX]) && face_attr_equal_p (attrs[LFACE_INVERSE_INDEX], def_attrs[LFACE_INVERSE_INDEX])) + || (!UNSPECIFIEDP (attrs[LFACE_EXTEND_INDEX]) + && face_attr_equal_p (attrs[LFACE_EXTEND_INDEX], + def_attrs[LFACE_EXTEND_INDEX])) || (!UNSPECIFIEDP (attrs[LFACE_FOREGROUND_INDEX]) && face_attr_equal_p (attrs[LFACE_FOREGROUND_INDEX], def_attrs[LFACE_FOREGROUND_INDEX])) @@ -5092,7 +5143,7 @@ Point (2) implies that a `:weight black' attribute will be satisfied by for (i = 0; i < LFACE_VECTOR_SIZE; i++) attrs[i] = Qunspecified; - merge_face_ref (NULL, f, attributes, attrs, true, 0); + merge_face_ref (NULL, f, attributes, attrs, true, NULL, 0); def_face = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID); if (def_face == NULL) @@ -5358,6 +5409,9 @@ realize_default_face (struct frame *f) ASET (lface, LFACE_FONTSET_INDEX, Qnil); } + if (UNSPECIFIEDP (LFACE_EXTEND (lface))) + ASET (lface, LFACE_EXTEND_INDEX, Qnil); + if (UNSPECIFIEDP (LFACE_UNDERLINE (lface))) ASET (lface, LFACE_UNDERLINE_INDEX, Qnil); @@ -5694,16 +5748,14 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] if (EQ (underline, Qt)) { /* Use default color (same as foreground color). */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = true; face->underline_color = 0; } else if (STRINGP (underline)) { /* Use specified color. */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = false; face->underline_color = load_color (f, face, underline, @@ -5711,7 +5763,7 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] } else if (NILP (underline)) { - face->underline_p = false; + face->underline = FACE_NO_UNDERLINE; face->underline_defaulted_p = false; face->underline_color = 0; } @@ -5719,10 +5771,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] { /* `(:color COLOR :style STYLE)'. STYLE being one of `line' or `wave'. */ - face->underline_p = true; + face->underline = FACE_UNDER_LINE; face->underline_color = 0; face->underline_defaulted_p = true; - face->underline_type = FACE_UNDER_LINE; /* FIXME? This is also not robust about checking the precise form. See comments in Finternal_set_lisp_face_attribute. */ @@ -5755,9 +5806,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] else if (EQ (keyword, QCstyle)) { if (EQ (value, Qline)) - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; else if (EQ (value, Qwave)) - face->underline_type = FACE_UNDER_WAVE; + face->underline = FACE_UNDER_WAVE; } } } @@ -5976,7 +6027,7 @@ compute_char_face (struct frame *f, int ch, Lisp_Object prop) Lisp_Object attrs[LFACE_VECTOR_SIZE]; struct face *default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID); memcpy (attrs, default_face->lface, sizeof attrs); - merge_face_ref (NULL, f, prop, attrs, true, 0); + merge_face_ref (NULL, f, prop, attrs, true, NULL, 0); face_id = lookup_face (f, attrs); } @@ -5988,6 +6039,8 @@ compute_char_face (struct frame *f, int ch, Lisp_Object prop) which a different face is needed, as far as text properties and overlays are concerned. W is a window displaying current_buffer. + attr_filter is passed merge_face_ref. + REGION_BEG, REGION_END delimit the region, so it can be highlighted. @@ -6007,7 +6060,8 @@ compute_char_face (struct frame *f, int ch, Lisp_Object prop) int face_at_buffer_position (struct window *w, ptrdiff_t pos, ptrdiff_t *endptr, ptrdiff_t limit, - bool mouse, int base_face_id) + bool mouse, int base_face_id, + enum lface_attribute_index attr_filter) { struct frame *f = XFRAME (w->frame); Lisp_Object attrs[LFACE_VECTOR_SIZE]; @@ -6068,8 +6122,7 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos, } /* Optimize common cases where we can use the default face. */ - if (noverlays == 0 - && NILP (prop)) + if (noverlays == 0 && NILP (prop)) { SAFE_FREE (); return default_face->id; @@ -6080,7 +6133,7 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos, /* Merge in attributes specified via text properties. */ if (!NILP (prop)) - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, 0); /* Now merge the overlay data. */ noverlays = sort_overlays (overlay_vec, noverlays, w); @@ -6100,7 +6153,7 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos, so discard the mouse-face text property, if any, and use the overlay property instead. */ memcpy (attrs, default_face->lface, sizeof attrs); - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, attr_filter); } oend = OVERLAY_END (overlay_vec[i]); @@ -6117,8 +6170,9 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos, ptrdiff_t oendpos; prop = Foverlay_get (overlay_vec[i], propname); + if (!NILP (prop)) - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, attr_filter); oend = OVERLAY_END (overlay_vec[i]); oendpos = OVERLAY_POSITION (oend); @@ -6184,7 +6238,7 @@ face_for_overlay_string (struct window *w, ptrdiff_t pos, /* Merge in attributes specified via text properties. */ if (!NILP (prop)) - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, 0); *endptr = endpos; @@ -6219,7 +6273,7 @@ face_for_overlay_string (struct window *w, ptrdiff_t pos, face_at_string_position (struct window *w, Lisp_Object string, ptrdiff_t pos, ptrdiff_t bufpos, ptrdiff_t *endptr, enum face_id base_face_id, - bool mouse_p) + bool mouse_p) { Lisp_Object prop, position, end, limit; struct frame *f = XFRAME (WINDOW_FRAME (w)); @@ -6263,7 +6317,7 @@ face_at_string_position (struct window *w, Lisp_Object string, /* Merge in attributes specified via text properties. */ if (!NILP (prop)) - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, 0); /* Look up a realized face with the given face attributes, or realize a new one for ASCII characters. */ @@ -6292,9 +6346,8 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, { struct frame *f = WINDOW_XFRAME (w); Lisp_Object attrs[LFACE_VECTOR_SIZE]; - struct face *base_face; + struct face *base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); - base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); if (!base_face) return base_face_id; @@ -6314,17 +6367,19 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, if (!NILP (face_name)) { - if (!merge_named_face (w, f, face_name, attrs, 0)) + if (!merge_named_face (w, f, face_name, attrs, NULL, 0)) return base_face_id; } else { - struct face *face; if (face_id < 0) return base_face_id; - face = FACE_FROM_ID_OR_NULL (f, face_id); + + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); + if (!face) return base_face_id; + merge_face_vectors (w, f, face->lface, attrs, 0); } @@ -6412,7 +6467,7 @@ dump_realized_face (struct face *face) #endif fprintf (stderr, "fontset: %d\n", face->fontset); fprintf (stderr, "underline: %d (%s)\n", - face->underline_p, + face->underline, SDATA (Fsymbol_name (face->lface[LFACE_UNDERLINE_INDEX]))); fprintf (stderr, "hash: %" PRIuPTR "\n", face->hash); } @@ -6537,6 +6592,7 @@ syms_of_xfaces (void) DEFSYM (QCstrike_through, ":strike-through"); DEFSYM (QCbox, ":box"); DEFSYM (QCinherit, ":inherit"); + DEFSYM (QCextend, ":extend"); /* Symbols used for Lisp face attribute values. */ DEFSYM (QCcolor, ":color"); diff --git a/src/xterm.c b/src/xterm.c index b761eaf4d1..b8f8db56a7 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3798,9 +3798,9 @@ x_draw_glyph_string (struct glyph_string *s) if (!s->for_overlaps) { /* Draw underline. */ - if (s->face->underline_p) + if (s->face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { if (s->face->underline_defaulted_p) x_draw_underwave (s); @@ -3814,13 +3814,13 @@ x_draw_glyph_string (struct glyph_string *s) XSetForeground (display, s->gc, xgcv.foreground); } } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { unsigned long thickness, position; int y; - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE) + if (s->prev && + s->prev->face->underline == FACE_UNDER_LINE) { /* We use the same underline style as the previous one. */ thickness = s->prev->underline_thickness; ^ permalink raw reply related [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-08 0:51 ` Ergus via Emacs development discussions. @ 2019-09-08 8:40 ` martin rudalics 2019-09-08 12:53 ` Ergus 2019-09-08 17:51 ` Eli Zaretskii 1 sibling, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-08 8:40 UTC (permalink / raw) To: Ergus, Eli Zaretskii; +Cc: emacs-devel > Please give a look to the attached patch and check if it is working fine > for you. (I added a new branch "extend_face_id" in savannah too) Thanks. The problem with my standard use case on your branch is that when I customize 'font-lock-comment-face' to have a specific :background and :extend nil, the background I specified nevertheless extends to the end of the line. So I wonder why it works to not extend the region while it apparently does not work to not extend 'font-lock-comment-face'. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-08 8:40 ` martin rudalics @ 2019-09-08 12:53 ` Ergus 2019-09-09 7:39 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-08 12:53 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Sun, Sep 08, 2019 at 10:40:42AM +0200, martin rudalics wrote: >> Please give a look to the attached patch and check if it is working fine >> for you. (I added a new branch "extend_face_id" in savannah too) > >Thanks. The problem with my standard use case on your branch is that >when I customize 'font-lock-comment-face' to have a specific >:background and :extend nil, the background I specified nevertheless >extends to the end of the line. So I wonder why it works to not >extend the region while it apparently does not work to not extend >'font-lock-comment-face'. > >martin > I fixed that, try now please (it is in savannah already). The problem was the merge I was doing in face_at_buffer_position which was unconditionaly merged for props. I conditioned only the overlays. It seems like font-lock-comment-face is a prop while region is an overlay. Right now as I modified merge_face_ref the conditional merge only works when CONSP (face_ref) == false and I am not sure what to do to make it work also for CONSP (face_ref) or if it even needed... ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-08 12:53 ` Ergus @ 2019-09-09 7:39 ` martin rudalics 2019-09-09 13:56 ` Ergus 2019-09-09 16:00 ` Eli Zaretskii 0 siblings, 2 replies; 183+ messages in thread From: martin rudalics @ 2019-09-09 7:39 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel > I fixed that, try now please (it is in savannah already). Thank you. Works now as expected. I'm still not convinced that it is a good idea to unconditionally run handle_face_prop_general from extend_face_to_end_of_line. It will penalize processing every line shown in a window even if no attribute processed is affected by a nil :extend attribute. But if you and Eli think it's cleaner to do it this way, I will not object further. Thanks again, martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-09 7:39 ` martin rudalics @ 2019-09-09 13:56 ` Ergus 2019-09-09 16:00 ` Eli Zaretskii 1 sibling, 0 replies; 183+ messages in thread From: Ergus @ 2019-09-09 13:56 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Mon, Sep 09, 2019 at 09:39:13AM +0200, martin rudalics wrote: >> I fixed that, try now please (it is in savannah already). > >Thank you. Works now as expected. > >I'm still not convinced that it is a good idea to unconditionally run >handle_face_prop_general from extend_face_to_end_of_line. It will >penalize processing every line shown in a window even if no attribute >processed is affected by a nil :extend attribute. But if you and Eli >think it's cleaner to do it this way, I will not object further. > >Thanks again, martin > Hi Martin: I actually don't agree either... but the merge process is a destructive operation (like a binary | ) So it means that we lost information during the merge process and we don't have a method to know the merged faces only with the face_id (in the general case) and mergng different faces could produce the same result. We can do some optimizations like condition the call if the face_id at position is not the default face for example. Or compare with the previous call result... but I think that only Eli can suggest which are applicable in this case. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-09 7:39 ` martin rudalics 2019-09-09 13:56 ` Ergus @ 2019-09-09 16:00 ` Eli Zaretskii 2019-09-09 17:08 ` Ergus 1 sibling, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-09 16:00 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Mon, 9 Sep 2019 09:39:13 +0200 > > > I fixed that, try now please (it is in savannah already). > > Thank you. Works now as expected. > > I'm still not convinced that it is a good idea to unconditionally run > handle_face_prop_general from extend_face_to_end_of_line. It will > penalize processing every line shown in a window even if no attribute > processed is affected by a nil :extend attribute. The penalty is just a call to merge faces and look up the merged face in the face cache (which, under most usual circumstances, will always find an already realized face in the cache). If you are worried about face merging itself, then don't be: we do this in redisplay all the time when displaying buffers, except in the most boring cases (like buffer of all-ASCII text in Fundamental mode). And the alternative is IMO worse: it will require tracking all the face changes and deciding upon each change whether it does or doesn't affect the line extension. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-09 16:00 ` Eli Zaretskii @ 2019-09-09 17:08 ` Ergus 2019-09-09 18:08 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-09 17:08 UTC (permalink / raw) To: Eli Zaretskii; +Cc: martin rudalics, emacs-devel On Mon, Sep 09, 2019 at 07:00:00PM +0300, Eli Zaretskii wrote: >> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org >> From: martin rudalics <rudalics@gmx.at> >> Date: Mon, 9 Sep 2019 09:39:13 +0200 >> >> > I fixed that, try now please (it is in savannah already). >> >> Thank you. Works now as expected. >> >> I'm still not convinced that it is a good idea to unconditionally run >> handle_face_prop_general from extend_face_to_end_of_line. It will >> penalize processing every line shown in a window even if no attribute >> processed is affected by a nil :extend attribute. > >The penalty is just a call to merge faces and look up the merged face >in the face cache (which, under most usual circumstances, will always >find an already realized face in the cache). If you are worried about >face merging itself, then don't be: we do this in redisplay all the >time when displaying buffers, except in the most boring cases (like >buffer of all-ASCII text in Fundamental mode). > >And the alternative is IMO worse: it will require tracking all the >face changes and deciding upon each change whether it does or doesn't >affect the line extension. Hi Eli: About this; I agree that the penalty should be negligible at the end compared to other things that happens on re-display. But after working on that parts I recognize that the actual algorithm for merge are extremely complicated and some parts are redundant. All the code is full of conditions and branch divergences and the design of faces infrastructure could be more efficient. Code that is used very often like "PRODUCE_GLYPHS" checks 3 if conditions every time (we should unify at least the if/else to bypass directly to the pointer, asserting that it is always initialized in terminal or gui). face_at_buffer_position and merge_face_ref are actually full of nested and nested conditional calls and even (direct and indirect) recursive calls. Some functions that could call merge_named_face I think they call merge_face_ref instead (with the extra checks and divergences). While other "low level" calls at the end also call merge_face_ref (probably for safety) ex get_lface_attributes, merge_face_vectors and so on. I understand that all this is probably negligible... but all that inhibits many optimizations very important these days like code inlining, branch prediction and vectorization. But also a big part of the code is needed just because the divergence between the tui and the gui code... if we unify the interfaces; then an important part of the code will be simplified and reduced and easier to maintain and modify. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-09 17:08 ` Ergus @ 2019-09-09 18:08 ` Eli Zaretskii 2019-09-09 19:29 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-09 18:08 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 9 Sep 2019 19:08:58 +0200 > From: Ergus <spacibba@aol.com> > Cc: martin rudalics <rudalics@gmx.at>, emacs-devel@gnu.org > > But after working on that parts I recognize that the actual > algorithm for merge are extremely complicated and some parts are > redundant. All the code is full of conditions and branch divergences > and the design of faces infrastructure could be more efficient. I don't think I agree. Given the complexity of the face-related functionalities -- face remapping, the need to recompute all the faces when some basic face changes, the various sources of face-related information for each buffer/string position, etc. -- I find the design and implementation of face code quite elegant and easy to understand, maintain and change. > Code that is used very often like "PRODUCE_GLYPHS" checks 3 if conditions > every time (we should unify at least the if/else to bypass directly to > the pointer, asserting that it is always initialized in terminal or gui). I don't think I see the optimization opportunity you are talking about here. If you want to make a produce_glyphs method available as a TTY hook, then why do you think it will make any tangible change of code efficiency? It's just a dereference and a call through a function pointer vs a test and a direct call. > face_at_buffer_position and merge_face_ref are actually full of nested > and nested conditional calls and even (direct and indirect) recursive > calls. Some functions that could call merge_named_face I think they call > merge_face_ref instead (with the extra checks and divergences). While > other "low level" calls at the end also call merge_face_ref (probably > for safety) ex get_lface_attributes, merge_face_vectors and so on. All of this is necessary to support the immense flexibility of face-related functionality we have, starting from the half a dozen different ways Lisp can specify a face. There's nothing redundant in that code, AFAIK, and unlike you, I don't find it too complicated at all. > I understand that all this is probably negligible... but all that > inhibits many optimizations very important these days like code > inlining, branch prediction and vectorization. What can I say? code should be correct first, and fast only after that. If the functionality we want to support disables some optimizations, so be it. And I wouldn't worry about this particular part of display code anyway, because the most expensive parts of redisplay are elsewhere. It should be clear from a simple consideration: the number of face changes in a typical window is an order of magnitude or more smaller than the number of characters and other display elements in that window. So if we want to optimize redisplay, we should look at the 90% part of the code, not at the 10%. > But also a big part of the code is needed just because the > divergence between the tui and the gui code... I don't think I follow. There's no difference between TTY and GUI frames wrt face handling, except where TTY color translation is involved. > if we unify the interfaces; then an important part of the > code will be simplified and reduced and easier to maintain and modify. Which interfaces would you like to unify? I don't think I understand. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-09 18:08 ` Eli Zaretskii @ 2019-09-09 19:29 ` Ergus 2019-09-10 2:27 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-09 19:29 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Mon, Sep 09, 2019 at 09:08:51PM +0300, Eli Zaretskii wrote: >> Date: Mon, 9 Sep 2019 19:08:58 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: martin rudalics <rudalics@gmx.at>, emacs-devel@gnu.org >> >> But after working on that parts I recognize that the actual >> algorithm for merge are extremely complicated and some parts are >> redundant. All the code is full of conditions and branch divergences >> and the design of faces infrastructure could be more efficient. > >I don't think I agree. Given the complexity of the face-related >functionalities -- face remapping, the need to recompute all the faces >when some basic face changes, the various sources of face-related >information for each buffer/string position, etc. -- I find the design >and implementation of face code quite elegant and easy to understand, >maintain and change. > I am talking about efficiency. >> Code that is used very often like "PRODUCE_GLYPHS" checks 3 if conditions >> every time (we should unify at least the if/else to bypass directly to >> the pointer, asserting that it is always initialized in terminal or gui). > >I don't think I see the optimization opportunity you are talking about >here. If you want to make a produce_glyphs method available as a TTY >hook, then why do you think it will make any tangible change of code >efficiency? It's just a dereference and a call through a function >pointer vs a test and a direct call. > This won't be an important optimization. It is just not standard. If there is no difference why are there different methods to select with if/else? The macro simply looks like a workaround. In any case, if the it/frame/rif structs are standard; then they should be always initialized. the tests will go away. And we could add an assert to test only in debug code. >> face_at_buffer_position and merge_face_ref are actually full of nested >> and nested conditional calls and even (direct and indirect) recursive >> calls. Some functions that could call merge_named_face I think they call >> merge_face_ref instead (with the extra checks and divergences). While >> other "low level" calls at the end also call merge_face_ref (probably >> for safety) ex get_lface_attributes, merge_face_vectors and so on. > >All of this is necessary to support the immense flexibility of face-related >functionality we have, starting from the half a dozen different ways >Lisp can specify a face. There's nothing redundant in that code, >AFAIK, and unlike you, I don't find it too complicated at all. > To add one field to the faces it required many modifications. Most of them with very similar changes here and there; else if and similar changes... every time I see an if-else-if with more than 3-4 conditions I start wondering. >> I understand that all this is probably negligible... but all that >> inhibits many optimizations very important these days like code >> inlining, branch prediction and vectorization. > >What can I say? code should be correct first, and fast only after >that. If the functionality we want to support disables some >optimizations, so be it. And I wouldn't worry about this particular >part of display code anyway, because the most expensive parts of >redisplay are elsewhere. It should be clear from a simple >consideration: the number of face changes in a typical window is an >order of magnitude or more smaller than the number of characters and >other display elements in that window. So if we want to optimize >redisplay, we should look at the 90% part of the code, not at the 10%. > Agree. But then why when the GC fails the lagging is so intense? I thought that the main part of the display engine related with GC was the faces part. >> But also a big part of the code is needed just because the >> divergence between the tui and the gui code... > >I don't think I follow. There's no difference between TTY and GUI >frames wrt face handling, except where TTY color translation is >involved. > >> if we unify the interfaces; then an important part of the >> code will be simplified and reduced and easier to maintain and modify. > >Which interfaces would you like to unify? I don't think I understand. > Most of the code conditioned with: if (FRAME_WINDOW_P (f)) could be simplified. But I understand that this could be a lot of work and I don't know enough about this. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-09 19:29 ` Ergus @ 2019-09-10 2:27 ` Eli Zaretskii 2019-09-12 3:37 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-10 2:27 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 9 Sep 2019 21:29:34 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >I don't think I agree. Given the complexity of the face-related > >functionalities -- face remapping, the need to recompute all the faces > >when some basic face changes, the various sources of face-related > >information for each buffer/string position, etc. -- I find the design > >and implementation of face code quite elegant and easy to understand, > >maintain and change. > > > I am talking about efficiency. Efficiency is secondary to clean design and correct implementation. > It is just not standard. If there is no difference why are there > different methods to select with if/else? History, I guess. > To add one field to the faces it required many modifications. That isn't a problem in my eyes. > But then why when the GC fails the lagging is so intense? I > thought that the main part of the display engine related with GC was the > faces part. No, faces code cannot GC. What causes GC is the calls to Lisp, which is JIT font-lock and other Lisp hooks. > >Which interfaces would you like to unify? I don't think I understand. > > > Most of the code conditioned with: if (FRAME_WINDOW_P (f)) could be > simplified. But I understand that this could be a lot of work and I > don't know enough about this. This work is being done, and most of it has been done already. Some display features are only possible on GUI frames (multiple fonts, for example), so such conditions are necessary, at least to some extent. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-10 2:27 ` Eli Zaretskii @ 2019-09-12 3:37 ` Ergus 2019-09-13 8:50 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-12 3:37 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel Hi Eli: Could you answer please the questions about the modifications in other functions (face_at_string and so on)? And could you tell me which are the faces that are supposed to be :extend t by default. I made a couple of changes in the interface to avoid passing the values by reference. And other small fixed in the branch. Please give a look and tell me what do you think. It will be nice if you could tell me where in the manual I am supposed to documents this as this actually enables 2 different functionalities: 1) Extend a face. 2) Change the region looking (whole screen width or "fixed to text" as a side effect). And fixes the issues with fill-column-indicator in org and the other issue that martin indicated. I will push tomorrow a fix for the extra space in term mode. So after that; your comments and the documentations I think I will rename the branch to a feature one in order to suggest people to test it your recommended two weeks. Is it fine? On Tue, Sep 10, 2019 at 05:27:39AM +0300, Eli Zaretskii wrote: >> Date: Mon, 9 Sep 2019 21:29:34 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >I don't think I agree. Given the complexity of the face-related >> >functionalities -- face remapping, the need to recompute all the faces >> >when some basic face changes, the various sources of face-related >> >information for each buffer/string position, etc. -- I find the design >> >and implementation of face code quite elegant and easy to understand, >> >maintain and change. >> > >> I am talking about efficiency. > >Efficiency is secondary to clean design and correct implementation. > >> It is just not standard. If there is no difference why are there >> different methods to select with if/else? > >History, I guess. > >> To add one field to the faces it required many modifications. > >That isn't a problem in my eyes. > >> But then why when the GC fails the lagging is so intense? I >> thought that the main part of the display engine related with GC was the >> faces part. > >No, faces code cannot GC. What causes GC is the calls to Lisp, which >is JIT font-lock and other Lisp hooks. > >> >Which interfaces would you like to unify? I don't think I understand. >> > >> Most of the code conditioned with: if (FRAME_WINDOW_P (f)) could be >> simplified. But I understand that this could be a lot of work and I >> don't know enough about this. > >This work is being done, and most of it has been done already. Some >display features are only possible on GUI frames (multiple fonts, for >example), so such conditions are necessary, at least to some extent. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-12 3:37 ` Ergus @ 2019-09-13 8:50 ` Eli Zaretskii 0 siblings, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-09-13 8:50 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Thu, 12 Sep 2019 05:37:33 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > Hi Eli: > > Could you answer please the questions about the modifications in other > functions (face_at_string and so on)? Sorry, I probably lost context, because I cannot figure out which questions are those. Could you please repeat them? > And could you tell me which are the faces that are supposed to be > :extend t by default. I think 'default', 'region', and 'hl-line'. > I made a couple of changes in the interface to avoid passing the values > by reference. And other small fixed in the branch. Please give a look > and tell me what do you think. Will do. > It will be nice if you could tell me where in the manual I am supposed > to documents this as this actually enables 2 different functionalities: > > 1) Extend a face. > 2) Change the region looking (whole screen width or "fixed to text" as a > side effect). > > And fixes the issues with fill-column-indicator in org and the other > issue that martin indicated. I think the right place is in "Face Attributes". > So after that; your comments and the documentations I think I will > rename the branch to a feature one in order to suggest people to test it > your recommended two weeks. I don't see a reason for renaming the branch, you could leave it as is. Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-08 0:51 ` Ergus via Emacs development discussions. 2019-09-08 8:40 ` martin rudalics @ 2019-09-08 17:51 ` Eli Zaretskii 2019-09-08 18:23 ` Ergus 1 sibling, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-08 17:51 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sun, 8 Sep 2019 02:51:10 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > Please give a look to the attached patch and check if it is working fine > for you. (I added a new branch "extend_face_id" in savannah too) > > I tried to make it as optimized and less changes as possible from the > beginning. > > In general I added a parameter to handle_face_prop renamed to > handle_face_prop_general (keeping the original name as a wrapper with > the same signature.) > > And the extra parameter is an enum lface_attribute_index. The parameter > is passed from function to function until merge_named_face which checks: > > (attr_filter == 0 || (!NILP (from[attr_filter]) > && !UNSPECIFIEDP (from[attr_filter]))) > > So if we pass zero as the parameter then the merge is unconditional; > else the attribute needs to be non-nil and specified to merge. > > I made it in this way because it is general enough and with low overhead > in case we want to condition the merge for different conditions in > the future. I didn't yet have time to have a close look at the changes, but I can already say that this handle_face_prop_general business I don't like. Passing a pointer to a face ID, like this: +handle_face_prop_general (struct it *it, int *face_id_ptr, + enum lface_attribute_index attr_filter) and then assigning to it via the pointer is gross. Also, the extension code doesn't need to return the HANDLED_NORMALLY value, AFAIU. Instead, it is much cleaner to have a new function with the guts of handle_face_prop, which would _return_ a face ID. Then handle_face_prop would then plug this into it->face_id, and the extension code will do what it needs. Can you make this change, please? > Now the only annoying thing is that when extend is disabled for the > region, the extra space after eol has the same face than the text before > (which for me is fine) but in the terminal it is not added... so I > should ask if you consider correct to add the space in terminal or > remove the extra "colored" space in gui? I vote for the first... but you > say. Yes, the terminal should use the same face as GUI for the first blank after end of line. Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-08 17:51 ` Eli Zaretskii @ 2019-09-08 18:23 ` Ergus 2019-09-14 20:42 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-08 18:23 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel Hi Eli: I know all that, I was just concerned about functionality and the changes I made in the merge_ref function if they are conceptually right or if they could produce some issues in some use cases that maybe I am ignoring. (specially the method I use to filter.) I implemented this in the face_at_buffer but in the same function there is a face_at_string equivalent... is it possible in some conditions to reach that part of the code at eol? if so I will need to modify that one too... The filter now in merge_ref only works when !CONSP(ref_name). As it only bypass the extra parameter to merge_named... it this right in the general case? I will change that detail you mention and some others in the interface later. But I need to be sure if the filter conditions already implemented are enough. (With the first implementation I learned that functional does not mean right.) On Sun, Sep 08, 2019 at 08:51:52PM +0300, Eli Zaretskii wrote: >> Date: Sun, 8 Sep 2019 02:51:10 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> Please give a look to the attached patch and check if it is working fine >> for you. (I added a new branch "extend_face_id" in savannah too) >> >> I tried to make it as optimized and less changes as possible from the >> beginning. >> >> In general I added a parameter to handle_face_prop renamed to >> handle_face_prop_general (keeping the original name as a wrapper with >> the same signature.) >> >> And the extra parameter is an enum lface_attribute_index. The parameter >> is passed from function to function until merge_named_face which checks: >> >> (attr_filter == 0 || (!NILP (from[attr_filter]) >> && !UNSPECIFIEDP (from[attr_filter]))) >> >> So if we pass zero as the parameter then the merge is unconditional; >> else the attribute needs to be non-nil and specified to merge. >> >> I made it in this way because it is general enough and with low overhead >> in case we want to condition the merge for different conditions in >> the future. > >I didn't yet have time to have a close look at the changes, but I can >already say that this handle_face_prop_general business I don't like. >Passing a pointer to a face ID, like this: > > +handle_face_prop_general (struct it *it, int *face_id_ptr, > + enum lface_attribute_index attr_filter) > >and then assigning to it via the pointer is gross. Also, the >extension code doesn't need to return the HANDLED_NORMALLY value, >AFAIU. > >Instead, it is much cleaner to have a new function with the guts of >handle_face_prop, which would _return_ a face ID. Then >handle_face_prop would then plug this into it->face_id, and the >extension code will do what it needs. Can you make this change, >please? > >> Now the only annoying thing is that when extend is disabled for the >> region, the extra space after eol has the same face than the text before >> (which for me is fine) but in the terminal it is not added... so I >> should ask if you consider correct to add the space in terminal or >> remove the extra "colored" space in gui? I vote for the first... but you >> say. > >Yes, the terminal should use the same face as GUI for the first blank >after end of line. > >Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-08 18:23 ` Ergus @ 2019-09-14 20:42 ` Ergus 2019-09-15 8:25 ` martin rudalics 2019-09-15 15:32 ` Eli Zaretskii 0 siblings, 2 replies; 183+ messages in thread From: Ergus @ 2019-09-14 20:42 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel Hi Eli & Martin: I just made some extra changes in the branch to fix the issues for the extra space in terminal gui. To test them try to disable the :extend for the region face and select a region with empty lines see if this is a right behavior (I think so). Now the extra space is colored like the text no with the extend face in gui and tui interfaces.. Eli: The questions I asked before were: > >I implemented this in the face_at_buffer_position but in the same >function (handle_face_prop_general) there is a function called >face_at_string_position equivalent to face_at_buffer_position... is it >possible in some conditions to reach that part of the code at eol? if >so I will need to modify that one too maybe right? > >The filter now in merge_ref only works when !CONSP(ref_name). As it only >bypass the extra parameter to merge_named... it this right in the >general case? > Could you suggest (if any) if there are some conditions we can use to avoid the call to handle_face_prop_general in some cases? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-14 20:42 ` Ergus @ 2019-09-15 8:25 ` martin rudalics 2019-09-15 11:26 ` Ergus 2019-09-15 15:32 ` Eli Zaretskii 1 sibling, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-15 8:25 UTC (permalink / raw) To: Ergus, Eli Zaretskii; +Cc: emacs-devel > To test them try to disable the :extend for the region face and select a > region with empty lines see if this is a right behavior (I think > so). Now the extra space is colored like the text no with the extend > face in gui and tui interfaces.. FWIW I see no problems in this regard. One thing that surprises me on a TTY is that the 'region' background does not cover the background of 'widget-field' (as it does on a GUI) but apparently this seems to have been the case ever since. Maybe also the :extend attribute of the default face should show up as "On" by default but I wouldn't even know where to specify that. For the rest, I'm all for installing this ASAP so we can see what kind of problems people have with it. I do expect some sort of breakage in external packages. Thanks for all your work, martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-15 8:25 ` martin rudalics @ 2019-09-15 11:26 ` Ergus 2019-09-15 12:22 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-15 11:26 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Sun, Sep 15, 2019 at 10:25:58AM +0200, martin rudalics wrote: > >FWIW I see no problems in this regard. One thing that surprises me on >a TTY is that the 'region' background does not cover the background of >'widget-field' (as it does on a GUI) but apparently this seems to have >been the case ever since. > Please. Could you give me how to reproduce this issue?? Maybe I could fix it too. (if there is not a reason for having this as is, of course) >Maybe also the :extend attribute of the default face should show up as >"On" by default but I wouldn't even know where to specify that. > I didn't for two reasons. 1) In the merge process the default face is used to initialize always the vector, so it is not needed to set it :extend t. But also many other faces (specially in extern packages) inherit from default and then set other attributes in their faces so all of them will need to be changed... to behave correctly... so better not to change the default face in my opinion... What do you think? >For the rest, I'm all for installing this ASAP so we can see what kind >of problems people have with it. I do expect some sort of breakage in >external packages. > I usually (as suggested by Eli) wait around 2 weeks until more people have time to test the changes and report issues before adding this in master. I need to update also the documentation (manual and NEWS) before merging in master. If you want to propose what to put there it will be very nice. Documentation takes me a lot of time because I am not familiar with the texi format Best, Ergus ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-15 11:26 ` Ergus @ 2019-09-15 12:22 ` martin rudalics 2019-09-15 14:28 ` Stefan Monnier 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-15 12:22 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel > Please. Could you give me how to reproduce this issue?? Maybe I could > fix it too. (if there is not a reason for having this as is, of course) M-x customize-face RET region RET C-x h Here there are two areas painted with yellow3 background instead of the region's blue3. I see no particular reason for that behavior. >> Maybe also the :extend attribute of the default face should show up as >> "On" by default but I wouldn't even know where to specify that. >> > I didn't for two reasons. 1) In the merge process the default face is > used to initialize always the vector, so it is not needed to set it > :extend t. But also many other faces (specially in extern packages) > inherit from default and then set other attributes in their faces so all > of them will need to be changed... to behave correctly... so better not > to change the default face in my opinion... What do you think? I think that you are right. Maybe we should leave a note in a doc-string or in *info* about that fact. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-15 12:22 ` martin rudalics @ 2019-09-15 14:28 ` Stefan Monnier 2019-09-16 9:05 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Stefan Monnier @ 2019-09-15 14:28 UTC (permalink / raw) To: martin rudalics; +Cc: Ergus, Eli Zaretskii, emacs-devel > M-x customize-face RET region RET C-x h > > Here there are two areas painted with yellow3 background instead of > the region's blue3. I see no particular reason for that behavior. I'm not sure what you're describing (the colors don't seem to match what I see), but it sounds like normal behavior (smaller overlays having precedence over larger ones). Stefan ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-15 14:28 ` Stefan Monnier @ 2019-09-16 9:05 ` martin rudalics 0 siblings, 0 replies; 183+ messages in thread From: martin rudalics @ 2019-09-16 9:05 UTC (permalink / raw) To: Stefan Monnier; +Cc: Ergus, Eli Zaretskii, emacs-devel > I'm not sure what you're describing (the colors don't seem to match > what I see), but it sounds like normal behavior (smaller overlays > having precedence over larger ones). Not really. This is 'redisplay-highlight-region-function' at work and it's by design. The idea is that when the region starts or ends within an overlay, it is shown within that overlay. If the region covers the overlay completely, it is not shown within that overlay. The effect is slightly different for GUIs and TTYs. On TTYs only 'widget-field' is affected here, on GUIs 'custom-button' as well. Which is probably by design too but I don't know why. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-14 20:42 ` Ergus 2019-09-15 8:25 ` martin rudalics @ 2019-09-15 15:32 ` Eli Zaretskii 2019-09-15 21:42 ` Ergus 1 sibling, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-15 15:32 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sat, 14 Sep 2019 22:42:07 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >I implemented this in the face_at_buffer_position but in the same > >function (handle_face_prop_general) there is a function called > >face_at_string_position equivalent to face_at_buffer_position... is it > >possible in some conditions to reach that part of the code at eol? if > >so I will need to modify that one too maybe right? Yes, it's possible. You need to arrange for a display string or an overlay string with en embedded newline. > >The filter now in merge_ref only works when !CONSP(ref_name). As it only > >bypass the extra parameter to merge_named... it this right in the > >general case? I think we should support all the cases, otherwise the feature will behave inconsistently, and we will get bug reports. > Could you suggest (if any) if there are some conditions we can use to > avoid the call to handle_face_prop_general in some cases? Why, did you see any tangible slow-down of redisplay due to these changes? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-15 15:32 ` Eli Zaretskii @ 2019-09-15 21:42 ` Ergus 2019-09-17 2:17 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-15 21:42 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sun, Sep 15, 2019 at 06:32:12PM +0300, Eli Zaretskii wrote: >> Date: Sat, 14 Sep 2019 22:42:07 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >I implemented this in the face_at_buffer_position but in the same >> >function (handle_face_prop_general) there is a function called >> >face_at_string_position equivalent to face_at_buffer_position... is it >> >possible in some conditions to reach that part of the code at eol? if >> >so I will need to modify that one too maybe right? > >Yes, it's possible. You need to arrange for a display string or an >overlay string with en embedded newline. > Done, new commit uploaded >> >The filter now in merge_ref only works when !CONSP(ref_name). As it only >> >bypass the extra parameter to merge_named... it this right in the >> >general case? > >I think we should support all the cases, otherwise the feature will >behave inconsistently, and we will get bug reports. > About this; the problem is that in the general case I'm not sure what's the "right" behavior for the other cases. When !CONSP(ref_name) it means that the parameter is a face_name; but in the other cases it means that we are explicitly specifying the attributes as a cons list or as :atribute value pairs... What's expected to happen in those cases?? >> Could you suggest (if any) if there are some conditions we can use to >> avoid the call to handle_face_prop_general in some cases? > >Why, did you see any tangible slow-down of redisplay due to these >changes? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-15 21:42 ` Ergus @ 2019-09-17 2:17 ` Ergus 2019-09-17 9:48 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-17 2:17 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel >>>>The filter now in merge_ref only works when !CONSP(ref_name). As it only >>>>bypass the extra parameter to merge_named... it this right in the >>>>general case? >> >>I think we should support all the cases, otherwise the feature will >>behave inconsistently, and we will get bug reports. >> >About this; the problem is that in the general case I'm not sure what's >the "right" behavior for the other cases. When !CONSP(ref_name) it means >that the parameter is a face_name; but in the other cases it means that >we are explicitly specifying the attributes as a cons list or as >:atribute value pairs... What's expected to happen in those cases?? > Hi: Any Idea about this? Could you suggest what to do when CONSP(ref_name) is true? > >>>Could you suggest (if any) if there are some conditions we can use to >>>avoid the call to handle_face_prop_general in some cases? >> >>Why, did you see any tangible slow-down of redisplay due to these >>changes? > No actually, but I think that there should be many cases where we could avoid calling the new function. So it is better to put them and avoid unneeded calls. For example when face_id is the default_face_id maybe? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-17 2:17 ` Ergus @ 2019-09-17 9:48 ` Eli Zaretskii 2019-09-21 8:20 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-17 9:48 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Tue, 17 Sep 2019 04:17:26 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >>>>The filter now in merge_ref only works when !CONSP(ref_name). As it only > >>>>bypass the extra parameter to merge_named... it this right in the > >>>>general case? > >> > >>I think we should support all the cases, otherwise the feature will > >>behave inconsistently, and we will get bug reports. > >> > >About this; the problem is that in the general case I'm not sure what's > >the "right" behavior for the other cases. When !CONSP(ref_name) it means > >that the parameter is a face_name; but in the other cases it means that > >we are explicitly specifying the attributes as a cons list or as > >:atribute value pairs... What's expected to happen in those cases?? > > > Hi: > Any Idea about this? Could you suggest what to do when CONSP(ref_name) > is true? I will reply to this soon, too swamped now. > >>>Could you suggest (if any) if there are some conditions we can use to > >>>avoid the call to handle_face_prop_general in some cases? > >> > >>Why, did you see any tangible slow-down of redisplay due to these > >>changes? > > > No actually, but I think that there should be many cases where we could > avoid calling the new function. So it is better to put them and avoid > unneeded calls. > > For example when face_id is the default_face_id maybe? Yes, for the default face ID it might be a good idea to add some optimization, as that will be the most frequent case. But beware of remapped default face, though. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-17 9:48 ` Eli Zaretskii @ 2019-09-21 8:20 ` Eli Zaretskii 2019-09-21 13:57 ` Ergus 2019-09-21 21:55 ` Ergus 0 siblings, 2 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-09-21 8:20 UTC (permalink / raw) To: spacibba; +Cc: rudalics, emacs-devel > Date: Tue, 17 Sep 2019 12:48:02 +0300 > From: Eli Zaretskii <eliz@gnu.org> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > > Date: Tue, 17 Sep 2019 04:17:26 +0200 > > From: Ergus <spacibba@aol.com> > > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > > > >>>>The filter now in merge_ref only works when !CONSP(ref_name). As it only > > >>>>bypass the extra parameter to merge_named... it this right in the > > >>>>general case? > > >> > > >>I think we should support all the cases, otherwise the feature will > > >>behave inconsistently, and we will get bug reports. > > >> > > >About this; the problem is that in the general case I'm not sure what's > > >the "right" behavior for the other cases. When !CONSP(ref_name) it means > > >that the parameter is a face_name; but in the other cases it means that > > >we are explicitly specifying the attributes as a cons list or as > > >:atribute value pairs... What's expected to happen in those cases?? > > > > > Hi: > > Any Idea about this? Could you suggest what to do when CONSP(ref_name) > > is true? > > I will reply to this soon, too swamped now. Sorry for the delay. Having looked at the code, I'm not sure I understand the problem. Why not simply pass the attr_filter down to the respective merge_face_ref calls, where you currently force zero instead? Am I missing something? Some other comments about your code: . Please rename handle_face_prop_general into something like face_at_pos, and make it just return the face ID, without assigning any field in 'struct it'. handle_face_prop will then call face_at_pos and assign the face ID as needed. . handle_face_prop_general is supposed to be called just once with the last argument non-zero, so I see no reason why it should be also passed the initial_face_id argument. It looks wrong to call that function with it->extend_face_id as the 2nd argument, and have it compute it->extend_face_id, because the value you pass as an argument is undefined: it hasn't been computed yet. I think the function should use it->face_id internally instead of that argument. . I don't understand why you need new members of 'struct it', like extend_face_id, saved_extend_face_id, etc. extend_face_to_end_of_line correctly assigns the value of extend face ID to it->face_id, after saving it->face_id in a local variable, so I see no need for it->extend_face_id, certainly not for it->saved_extend_face_id. You also have extend_face_id in other related structures, where it is never used. Regarding documentation: if you have difficulties with the Texinfo markup, you could write plain text, and someone else could then add markup. Adding markup is a mostly mechanical procedure, unlike coming up with a useful text. Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-21 8:20 ` Eli Zaretskii @ 2019-09-21 13:57 ` Ergus 2019-09-21 21:55 ` Ergus 1 sibling, 0 replies; 183+ messages in thread From: Ergus @ 2019-09-21 13:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sat, Sep 21, 2019 at 11:20:44AM +0300, Eli Zaretskii wrote: >> Date: Tue, 17 Sep 2019 12:48:02 +0300 >> From: Eli Zaretskii <eliz@gnu.org> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> > Date: Tue, 17 Sep 2019 04:17:26 +0200 >> > From: Ergus <spacibba@aol.com> >> > Cc: rudalics@gmx.at, emacs-devel@gnu.org >> > >> > >>>>The filter now in merge_ref only works when !CONSP(ref_name). As it only >> > >>>>bypass the extra parameter to merge_named... it this right in the >> > >>>>general case? >> > >> >> > >>I think we should support all the cases, otherwise the feature will >> > >>behave inconsistently, and we will get bug reports. >> > >> >> > >About this; the problem is that in the general case I'm not sure what's >> > >the "right" behavior for the other cases. When !CONSP(ref_name) it means >> > >that the parameter is a face_name; but in the other cases it means that >> > >we are explicitly specifying the attributes as a cons list or as >> > >:atribute value pairs... What's expected to happen in those cases?? >> > > >> > Hi: >> > Any Idea about this? Could you suggest what to do when CONSP(ref_name) >> > is true? >> >> I will reply to this soon, too swamped now. > Hi: Thanks for the reply. >Sorry for the delay. > >Having looked at the code, I'm not sure I understand the problem. Why >not simply pass the attr_filter down to the respective merge_face_ref >calls, where you currently force zero instead? Am I missing >something? > That's what I do actually are you in the last changes? Probably I am the one who is missing something otherwise. >Some other comments about your code: > > . Please rename handle_face_prop_general into something like > face_at_pos, and make it just return the face ID, without assigning > any field in 'struct it'. handle_face_prop will then call > face_at_pos and assign the face ID as needed. Yes, I change that already to return the id without assigning anything. > . handle_face_prop_general is supposed to be called just once with > the last argument non-zero, so I see no reason why it should be > also passed the initial_face_id argument. It looks wrong to call > that function with it->extend_face_id as the 2nd argument, and have > it compute it->extend_face_id, because the value you pass as an > argument is undefined: it hasn't been computed yet. I think the > function should use it->face_id internally instead of that > argument. The initial face if has nothing to do with the last argument. It is needed for an optimization at the end of the function. But yes, using it internally is better. > . I don't understand why you need new members of 'struct it', like > extend_face_id, saved_extend_face_id, etc. > extend_face_to_end_of_line correctly assigns the value of extend > face ID to it->face_id, after saving it->face_id in a local > variable, so I see no need for it->extend_face_id, certainly not > for it->saved_extend_face_id. You also have extend_face_id in > other related structures, where it is never used. > This was for the idea to avoid recomputing it->extend_face_id in some cases, and reuse the previous value when possible too. (that's why I pass it as a parameter face_id actually.) But I can change that if you think it is not needed. >Regarding documentation: if you have difficulties with the Texinfo >markup, you could write plain text, and someone else could then add >markup. Adding markup is a mostly mechanical procedure, unlike coming >up with a useful text. > >Thanks. Thanks to you ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-21 8:20 ` Eli Zaretskii 2019-09-21 13:57 ` Ergus @ 2019-09-21 21:55 ` Ergus 2019-09-26 16:32 ` Ergus 1 sibling, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-21 21:55 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sat, Sep 21, 2019 at 11:20:44AM +0300, Eli Zaretskii wrote: > >Sorry for the delay. > >Having looked at the code, I'm not sure I understand the problem. Why >not simply pass the attr_filter down to the respective merge_face_ref >calls, where you currently force zero instead? Am I missing >something? > >Some other comments about your code: > > . Please rename handle_face_prop_general into something like > face_at_pos, and make it just return the face ID, without assigning > any field in 'struct it'. handle_face_prop will then call > face_at_pos and assign the face ID as needed. > . handle_face_prop_general is supposed to be called just once with > the last argument non-zero, so I see no reason why it should be > also passed the initial_face_id argument. It looks wrong to call > that function with it->extend_face_id as the 2nd argument, and have > it compute it->extend_face_id, because the value you pass as an > argument is undefined: it hasn't been computed yet. I think the > function should use it->face_id internally instead of that > argument. > . I don't understand why you need new members of 'struct it', like > extend_face_id, saved_extend_face_id, etc. > extend_face_to_end_of_line correctly assigns the value of extend > face ID to it->face_id, after saving it->face_id in a local > variable, so I see no need for it->extend_face_id, certainly not > for it->saved_extend_face_id. You also have extend_face_id in > other related structures, where it is never used. > >Regarding documentation: if you have difficulties with the Texinfo >markup, you could write plain text, and someone else could then add >markup. Adding markup is a mostly mechanical procedure, unlike coming >up with a useful text. > Hi: I just added some documentation in the reference manuals please check it. I should add a comment in the NEWS file, in which part is the right one? >Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-21 21:55 ` Ergus @ 2019-09-26 16:32 ` Ergus 2019-09-28 10:35 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-26 16:32 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sat, Sep 21, 2019 at 11:55:51PM +0200, Ergus wrote: >On Sat, Sep 21, 2019 at 11:20:44AM +0300, Eli Zaretskii wrote: Hi Eli: Please check the branch scratch/extend_face_id and tell me what's missing to merge in master. Best, Ergus >Hi: > >I just added some documentation in the reference manuals please check >it. > >I should add a comment in the NEWS file, in which part is the right one? > > > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-26 16:32 ` Ergus @ 2019-09-28 10:35 ` Eli Zaretskii 2019-09-29 10:30 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-28 10:35 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Thu, 26 Sep 2019 18:32:04 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > Please check the branch scratch/extend_face_id and tell me what's > missing to merge in master. Thanks, I took a look. I think the branch is almost ready to be merged, once we address the following minor comments: . I don't understand why you changed the underlined_p and underline_type stuff in struct face. What were the reasons for that part of the changeset? Its sole effect seems to be to generate some redundant changes, or am I missing something? . In this hunk from append_space_for_newline, why did you change FACE_FROM_ID_OR_NULL to FACE_FROM_ID? - int local_default_face_id = + int char_width = 1; + + if (default_face_p +#ifdef HAVE_WINDOW_SYSTEM + || FRAME_WINDOW_P (it->f) +#endif + ) + { + const int local_default_face_id = lookup_basic_face (it->w, it->f, DEFAULT_FACE_ID); struct face* default_face = - FACE_FROM_ID_OR_NULL (it->f, local_default_face_id); + FACE_FROM_ID (it->f, local_default_face_id); . Please use comments /* in this style */, not // like this. . In this hunk from extend_face_to_end_of_line you lost the comment. Is that comment no longer correct? - int column_x; - if (!INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) - && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) - && column_x >= it->current_x - && column_x <= it->last_visible_x) - { + const int indicator_column = + fill_column_indicator_column (it, char_width); + const char saved_char = it->char_to_display; const struct text_pos saved_pos = it->position; const bool saved_avoid_cursor = it->avoid_cursor_p; - const int saved_face_id = it->face_id; const bool saved_box_start = it->start_of_box_run_p; Lisp_Object save_object = it->object; + const int saved_face_id = it->face_id; - /* The stretch width needs to considet the latter - added glyph. */ - const int stretch_width - = column_x - it->current_x - char_width; - - memset (&it->position, 0, sizeof it->position); + it->face_id = extend_face_id; it->avoid_cursor_p = true; it->object = Qnil; + if (indicator_column >= 0 + && indicator_column > it->current_x + && indicator_column < it->last_visible_x) + { + + const int stretch_width = + indicator_column - it->current_x - char_width; + + memset (&it->position, 0, sizeof it->position); + . And here the comment was not moved with the code which it describes: /* Restore the face after the indicator was generated. */ - it->face_id = saved_face_id; /* If there is space after the indicator generate an extra empty glyph to restore the face. Issue was @@ -20634,8 +20633,8 @@ extend_face_to_end_of_line (struct it *it) it->avoid_cursor_p = saved_avoid_cursor; it->start_of_box_run_p = saved_box_start; it->object = save_object; - } - } + it->face_id = saved_face_id; . This hunk looks redundant to me: @@ -20681,10 +20680,9 @@ extend_face_to_end_of_line (struct it *it) /* The last row's stretch glyph should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ - if (it->glyph_row->ends_at_zv_p) - it->face_id = default_face->id; - else - it->face_id = face->id; + it->face_id = (it->glyph_row->ends_at_zv_p ? + default_face->id : face->id); (there's at least one more like it in the changeset). . This also looks redundant: @@ -25436,8 +25423,8 @@ display_string (const char *string, Lisp_Object lisp_str /* Initialize the iterator IT for iteration over STRING beginning with index START. */ - reseat_to_string (it, NILP (lisp_string) ? string : NULL, lisp_string, start, - precision, field_width, multibyte); + reseat_to_string (it, NILP (lisp_string) ? string : NULL, lisp_string, + start, precision, field_width, multibyte); . In this commentary, please upcase attr_filter, as that is our convention for describing function arguments in comments: @@ -2269,6 +2282,11 @@ filter_face_ref (Lisp_Object face_ref, of ERR_MSGS). Use NAMED_MERGE_POINTS to detect loops in face inheritance or list structure; it may be 0 for most callers. + attr_filter is the index of a parameter that conditions the merging + for named faces (case 1) to only the face_ref where + lface[merge_face_ref] is non-nil. To merge unconditionally set this + value to 0. . Likewise here: @@ -5988,6 +6039,8 @@ compute_char_face (struct frame *f, int ch, Lisp_Object pr which a different face is needed, as far as text properties and overlays are concerned. W is a window displaying current_buffer. + attr_filter is passed merge_face_ref. The sentence you added sounds incomplete here: did you mean to say "passed to merge_face_ref"? . This hunk looks redundant: @@ -4505,7 +4552,8 @@ lookup_face (struct frame *f, Lisp_Object *attr) suitable face is found, realize a new one. */ int -face_for_font (struct frame *f, Lisp_Object font_object, struct face *base_face +face_for_font (struct frame *f, Lisp_Object font_object, + struct face *base_face) . This also looks redundant: @@ -6068,19 +6122,18 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos } /* Optimize common cases where we can use the default face. */ - if (noverlays == 0 - && NILP (prop)) + if (noverlays == 0 && NILP (prop)) . And this one: /* Begin with attributes from the default face. */ - memcpy (attrs, default_face->lface, sizeof attrs); + memcpy (attrs, default_face->lface, sizeof(attrs)); . Finally, please write some short description for NEWS, as this feature definitely needs to be mentioned there. Thanks again for working on this, and sorry for my unusually slow responses. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-28 10:35 ` Eli Zaretskii @ 2019-09-29 10:30 ` Ergus 2019-09-29 10:57 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-29 10:30 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sat, Sep 28, 2019 at 01:35:30PM +0300, Eli Zaretskii wrote: Hi Eli: > >Thanks, I took a look. I think the branch is almost ready to be >merged, once we address the following minor comments: > > . I don't understand why you changed the underlined_p and > underline_type stuff in struct face. What were the reasons for > that part of the changeset? Its sole effect seems to be to > generate some redundant changes, or am I missing something? > Use double variable to describe the same is an error prone practice. This change simplifies the checks in all the code related (as there will be only one variable to set/check), reduces one name and member in the struct and avoids errors related to changing one value and not the other. > > . In this hunk from append_space_for_newline, why did you change > FACE_FROM_ID_OR_NULL to FACE_FROM_ID? > > - int local_default_face_id = > + int char_width = 1; > + > + if (default_face_p > +#ifdef HAVE_WINDOW_SYSTEM > + || FRAME_WINDOW_P (it->f) > +#endif > + ) > + { > + const int local_default_face_id = > lookup_basic_face (it->w, it->f, DEFAULT_FACE_ID); > struct face* default_face = > - FACE_FROM_ID_OR_NULL (it->f, local_default_face_id); > + FACE_FROM_ID (it->f, local_default_face_id); > The call is made after a lookup_basic_face and it's for DEFAULT_FACE_ID is it needed the check? Normally for other faces if it is NULL then we use the DEFAULT_FACE_ID. In this case it should be unneeded right? > . Please use comments /* in this style */, not // like this. > Fixed > > . In this hunk from extend_face_to_end_of_line you lost the > comment. Is that comment no longer correct? > > - int column_x; > > - if (!INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) > - && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) > - && column_x >= it->current_x > - && column_x <= it->last_visible_x) > - { > + const int indicator_column = > + fill_column_indicator_column (it, char_width); > + > const char saved_char = it->char_to_display; > const struct text_pos saved_pos = it->position; > const bool saved_avoid_cursor = it->avoid_cursor_p; > - const int saved_face_id = it->face_id; > const bool saved_box_start = it->start_of_box_run_p; > Lisp_Object save_object = it->object; > + const int saved_face_id = it->face_id; > > - /* The stretch width needs to considet the latter > - added glyph. */ > - const int stretch_width > - = column_x - it->current_x - char_width; > - > - memset (&it->position, 0, sizeof it->position); > + it->face_id = extend_face_id; > it->avoid_cursor_p = true; > it->object = Qnil; > > + if (indicator_column >= 0 > + && indicator_column > it->current_x > + && indicator_column < it->last_visible_x) > + { > + > + const int stretch_width = > + indicator_column - it->current_x - char_width; > + > + memset (&it->position, 0, sizeof it->position); > + > The comment is now in the function fill_column_indicator_column where the calculation is performed now. > > . And here the comment was not moved with the code which it > describes: > > /* Restore the face after the indicator was generated. */ > - it->face_id = saved_face_id; > > /* If there is space after the indicator generate an > extra empty glyph to restore the face. Issue was > @@ -20634,8 +20633,8 @@ extend_face_to_end_of_line (struct it *it) > it->avoid_cursor_p = saved_avoid_cursor; > it->start_of_box_run_p = saved_box_start; > it->object = save_object; > - } > - } > + it->face_id = saved_face_id; > Fixed. > . This hunk looks redundant to me: > > @@ -20681,10 +20680,9 @@ extend_face_to_end_of_line (struct it *it) > /* The last row's stretch glyph should get the default > face, to avoid painting the rest of the window with > the region face, if the region ends at ZV. */ > - if (it->glyph_row->ends_at_zv_p) > - it->face_id = default_face->id; > - else > - it->face_id = face->id; > + it->face_id = (it->glyph_row->ends_at_zv_p ? > + default_face->id : face->id); > > (there's at least one more like it in the changeset). > For me this looked better (shorter and clearer), but I will restore it if you prefer that. > . This also looks redundant: > > @@ -25436,8 +25423,8 @@ display_string (const char *string, Lisp_Object lisp_str > > /* Initialize the iterator IT for iteration over STRING beginning > with index START. */ > - reseat_to_string (it, NILP (lisp_string) ? string : NULL, lisp_string, start, > - precision, field_width, multibyte); > + reseat_to_string (it, NILP (lisp_string) ? string : NULL, lisp_string, > + start, precision, field_width, multibyte); > The line was too long. I just tried to reduce it a bit. > . In this commentary, please upcase attr_filter, as that is our > convention for describing function arguments in comments: > > @@ -2269,6 +2282,11 @@ filter_face_ref (Lisp_Object face_ref, > of ERR_MSGS). Use NAMED_MERGE_POINTS to detect loops in face > inheritance or list structure; it may be 0 for most callers. > > + attr_filter is the index of a parameter that conditions the merging > + for named faces (case 1) to only the face_ref where > + lface[merge_face_ref] is non-nil. To merge unconditionally set this > + value to 0. > > . Likewise here: > > @@ -5988,6 +6039,8 @@ compute_char_face (struct frame *f, int ch, Lisp_Object pr > which a different face is needed, as far as text properties and > overlays are concerned. W is a window displaying current_buffer. > > + attr_filter is passed merge_face_ref. > > The sentence you added sounds incomplete here: did you mean to say > "passed to merge_face_ref"? > Fixed both. > . This hunk looks redundant: > > @@ -4505,7 +4552,8 @@ lookup_face (struct frame *f, Lisp_Object *attr) > suitable face is found, realize a new one. */ > > int > -face_for_font (struct frame *f, Lisp_Object font_object, struct face *base_face > +face_for_font (struct frame *f, Lisp_Object font_object, > + struct face *base_face) > The line was too long. 85 chars long. > . This also looks redundant: > > @@ -6068,19 +6122,18 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos > } > > /* Optimize common cases where we can use the default face. */ > - if (noverlays == 0 > - && NILP (prop)) > + if (noverlays == 0 && NILP (prop)) > > . And this one: > > /* Begin with attributes from the default face. */ > - memcpy (attrs, default_face->lface, sizeof attrs); > + memcpy (attrs, default_face->lface, sizeof(attrs)); > > . Finally, please write some short description for NEWS, as this > feature definitely needs to be mentioned there. > It seems unneeded two lines for this; but fixed. >Thanks again for working on this, and sorry for my unusually slow >responses. Thank to you. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-29 10:30 ` Ergus @ 2019-09-29 10:57 ` Eli Zaretskii 2019-10-07 15:40 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-29 10:57 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sun, 29 Sep 2019 12:30:34 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > > . I don't understand why you changed the underlined_p and > > underline_type stuff in struct face. What were the reasons for > > that part of the changeset? Its sole effect seems to be to > > generate some redundant changes, or am I missing something? > > > Use double variable to describe the same is an error prone > practice. This change simplifies the checks in all the code related (as > there will be only one variable to set/check), reduces one name and > member in the struct and avoids errors related to changing one value and > not the other. That's your stylistic preference, and I can understand it. But when the only reason for a change is stylistic preferences, I generally prefer to leave the code intact, so that the original authors' version remains as long as it does TRT. > > . In this hunk from append_space_for_newline, why did you change > > FACE_FROM_ID_OR_NULL to FACE_FROM_ID? > > > > - int local_default_face_id = > > + int char_width = 1; > > + > > + if (default_face_p > > +#ifdef HAVE_WINDOW_SYSTEM > > + || FRAME_WINDOW_P (it->f) > > +#endif > > + ) > > + { > > + const int local_default_face_id = > > lookup_basic_face (it->w, it->f, DEFAULT_FACE_ID); > > struct face* default_face = > > - FACE_FROM_ID_OR_NULL (it->f, local_default_face_id); > > + FACE_FROM_ID (it->f, local_default_face_id); > > > > The call is made after a lookup_basic_face and it's for DEFAULT_FACE_ID > is it needed the check? Normally for other faces if it is NULL then we > use the DEFAULT_FACE_ID. In this case it should be unneeded right? It's the other way around: FACE_FROM_ID could trigger an assertion violation, where FACE_FROM_ID_OR_NULL will silently return a NULL pointer. So we should only use FACE_FROM_ID where we are 110% certain it can never violate the assertion, or where a NULL pointer for a face will cause worse problems than an assertion. Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-29 10:57 ` Eli Zaretskii @ 2019-10-07 15:40 ` Ergus 2019-10-09 9:02 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-10-07 15:40 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel Hi Eli: I made some of the fixes you suggested in the last email about this topic. The reduction of the underline-p + underline-stile into a single underline variable in the struct for me still seems like a good change for readability and simplification in all the code. Any way in the future I will try to avoid this kind of modifications even when they seems to be an improvement... but could you let it pass this time? The other changes that seemed to be stylistic too, were actually in portions of code I wrote for dfci and It was there because I copied some of it from the previous if-else section... but I can correct it now right?... so no problem? If this is fine may I merge in master? Best, Ergus. On Sun, Sep 29, 2019 at 01:57:22PM +0300, Eli Zaretskii wrote: >> Date: Sun, 29 Sep 2019 12:30:34 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> > . I don't understand why you changed the underlined_p and >> > underline_type stuff in struct face. What were the reasons for >> > that part of the changeset? Its sole effect seems to be to >> > generate some redundant changes, or am I missing something? >> > >> Use double variable to describe the same is an error prone >> practice. This change simplifies the checks in all the code related (as >> there will be only one variable to set/check), reduces one name and >> member in the struct and avoids errors related to changing one value and >> not the other. > >That's your stylistic preference, and I can understand it. But when >the only reason for a change is stylistic preferences, I generally >prefer to leave the code intact, so that the original authors' version >remains as long as it does TRT. > >> > . In this hunk from append_space_for_newline, why did you change >> > FACE_FROM_ID_OR_NULL to FACE_FROM_ID? >> > >> > - int local_default_face_id = >> > + int char_width = 1; >> > + >> > + if (default_face_p >> > +#ifdef HAVE_WINDOW_SYSTEM >> > + || FRAME_WINDOW_P (it->f) >> > +#endif >> > + ) >> > + { >> > + const int local_default_face_id = >> > lookup_basic_face (it->w, it->f, DEFAULT_FACE_ID); >> > struct face* default_face = >> > - FACE_FROM_ID_OR_NULL (it->f, local_default_face_id); >> > + FACE_FROM_ID (it->f, local_default_face_id); >> > >> >> The call is made after a lookup_basic_face and it's for DEFAULT_FACE_ID >> is it needed the check? Normally for other faces if it is NULL then we >> use the DEFAULT_FACE_ID. In this case it should be unneeded right? > >It's the other way around: FACE_FROM_ID could trigger an assertion >violation, where FACE_FROM_ID_OR_NULL will silently return a NULL >pointer. So we should only use FACE_FROM_ID where we are 110% certain >it can never violate the assertion, or where a NULL pointer for a face >will cause worse problems than an assertion. > >Thanks. > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-07 15:40 ` Ergus @ 2019-10-09 9:02 ` Eli Zaretskii 2019-10-12 18:16 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-10-09 9:02 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 7 Oct 2019 17:40:55 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > I made some of the fixes you suggested in the last email about this > topic. Thanks, see a couple of comments below. > The reduction of the underline-p + underline-stile into a single > underline variable in the struct for me still seems like a good change > for readability and simplification in all the code. Any way in the > future I will try to avoid this kind of modifications even when they > seems to be an improvement... but could you let it pass this time? I don't understand what makes this time special, but OK. > The other changes that seemed to be stylistic too, were actually in > portions of code I wrote for dfci and It was there because I copied some > of it from the previous if-else section... but I can correct it now > right?... so no problem? > > If this is fine may I merge in master? It's OK to merge, after fixing the following nits: > ++++ > +** There is a new face attribute :extend to use the face attributes to > +extend after the end of the line until the end of the window. Such > +:extend is set to nil by default in all faces except for `hl-line` and > +`region` because those extend until the end of the window by default. Please quote 'like this' in NEWS, not `like this`. Also, this NEWS entry should have a header line: ** New face attribute ':extend' to control face extension at EOL. > + /* The stretch width needs to considet the latter ^^^^^^^^ A typo. > /* Display fill-column indicator if needed. */ > - int indicator_column = fill_column_indicator_column (it); > - if (indicator_column >= 0 > - && INT_ADD_WRAPV (it->lnum_pixel_width, indicator_column, > - &indicator_column)) > - indicator_column = -1; > + const int indicator_column = > + fill_column_indicator_column (it, 1) - 1; Why did you need to subtract 1 in the last line? If this is indeed needed, it needs a comment to explain it. > + ATTR_FILTER is the index of a parameter that conditions the merging > + for named faces (case 1) to only the face_ref where > + lface[merge_face_ref] is non-nil. To merge unconditionally set this > + value to 0. ^^ Two spaces between sentences, please. Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-09 9:02 ` Eli Zaretskii @ 2019-10-12 18:16 ` Ergus 2019-10-12 18:29 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-10-12 18:16 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel Hi Eli: I haven't merged this yet because 2 days ago I found that there is a bug in the code very difficult to locate for me and I have not understand what's going on. The problem is that emacs just freezes in the magit-log buffer in tui. (M-x magit-log-all for example.) This seems to be a weird issue because in gui it doesn't happen only in the terminal interface (which should be agnostic to magit). And I have only observed it in magit-log. And if this happens for magit-log I am wondering that there should be other possible situations that produce the same problem. After some tests and moving in the history of my changes I got that the issue is the call to handle_face_prop in extend_face_to_end_of_line. Trying the next in current master I got the same issue: // =============================== diff --git a/src/xdisp.c b/src/xdisp.c index 893ce9269c..af50dd0bcd 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -21587,6 +21587,7 @@ extend_face_to_end_of_line (struct it *it) || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) return; + handle_face_prop (it); /* Face extension extends the background and box of IT->face_id to the end of the line. If the background equals the background of the frame, we don't have to do anything. */ // =============================== In gdb I saee that it goes in a very complex inf loop within the display engine functions and emacs becomes completely unresponsive (No C-g or ESC ESC ESC) the only solution is to kill it from outside. Magit provides a way to execute emacs loading only magit (magit-emacs-Q-command), so it is nothing in my config... but something probably tricky used in magit-log that exposes the issue. Could you give a look please? ^ permalink raw reply related [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-12 18:16 ` Ergus @ 2019-10-12 18:29 ` Eli Zaretskii 0 siblings, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-10-12 18:29 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sat, 12 Oct 2019 20:16:18 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > Trying the next in current master I got the same issue: > > // =============================== > > diff --git a/src/xdisp.c b/src/xdisp.c > index 893ce9269c..af50dd0bcd 100644 > --- a/src/xdisp.c > +++ b/src/xdisp.c > @@ -21587,6 +21587,7 @@ extend_face_to_end_of_line (struct it *it) > || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) > return; > > + handle_face_prop (it); > /* Face extension extends the background and box of IT->face_id > to the end of the line. If the background equals the background > of the frame, we don't have to do anything. */ > > // =============================== I don't understand why would we want to add a call to handle_face_prop there. > In gdb I saee that it goes in a very complex inf loop within the display > engine functions and emacs becomes completely unresponsive (No C-g or > ESC ESC ESC) the only solution is to kill it from outside. Can you tell where it loops? That is, describe the sequence of calls and the return values for a single iteration through the loop? > Could you give a look please? Not sure what should I look at. If you want me to run a GDB session, I would need a recipe to reproduce the loop. Note that I don't have Magit installed, so loading it (if needed) would have be part of the recipe. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-05 19:26 ` Question about display engine Ergus 2019-09-06 8:22 ` martin rudalics @ 2019-09-06 8:55 ` Eli Zaretskii 2019-09-06 10:30 ` Ergus 1 sibling, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-06 8:55 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Thu, 5 Sep 2019 19:26:09 +0000 (UTC) > From: Ergus <spacibba@aol.com> > Cc: eliz@gnu.org, emacs-devel@gnu.org > > I attach here a new patch with all the changes I have just made. After fixing the latest Martin's issue there was > exposed a new issue maybe related with the initialization per line. (picture attached) Thanks. I admit that I'm confused by your patch: I don't understand your design of calculating and applying the face used for EOL extension. E.g., where's the code that merges only the non-extensible attributes of the face at buffer position and assigns that face ID of the calculated face to it->extend_face_id? And why did you copy all the lines that assign to it->face_id with similar lines that assign something similar (sometimes identical) to it->extend_face_id? And why do you have to save and restore extend_face_id during some operations, like we do with it->face_id? Etc. etc. Can you post a description of the design and the implementation, to help me find the light here? In particular, I don't think I understand the meaning of "the face should be extended after EOL", if that face is merged with other faces to realize the face to be actually used in display. This semantics seems not to be explained anywhere, so it's hard to judge whether the implementation satisfies the requirements/expectations. > The issue is actually related with the fact that extend_face_id is never restarted to face_id when going back > from an extend to a non_extend face between lines (for example when mark is active and the iterator crosses > the pointer to outside the selected region like in the picture). I cannot answer this question because my mental model is the opposite: that the code should temporarily set face_id to be equal to extend_face_id when producing glyphs beyond EOL, then reset face_id back to its previous value. But your code doesn't fit this mental model of mine, so I'm probably missing something. > I made all the updates of the extend_face_id in the same places where face_id was updated (even when > uneeded for now.) This is another place for confusion: I don't understand why extend_face_id should be updated in all those places. In my metal model, extend_face_id is independent of many/most of the factors that cause us update face_id. > But I don't see any special function that is called before > display_line. face_id is initialized in init_iterator, which is always called once before the first call to display_line. Thereafter, any subsequent call to display_line "inherits" the value of face_id left in the iterator object at the end of the previous call to display_line. Whether this fits the logic of using extend_face_id, I cannot say yet; see the above questions that describe my confusion. Thanks for working on this. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-06 8:55 ` Eli Zaretskii @ 2019-09-06 10:30 ` Ergus 2019-09-06 13:28 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-06 10:30 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Fri, Sep 06, 2019 at 11:55:19AM +0300, Eli Zaretskii wrote: >> Date: Thu, 5 Sep 2019 19:26:09 +0000 (UTC) >> From: Ergus <spacibba@aol.com> >> Cc: eliz@gnu.org, emacs-devel@gnu.org >> >> I attach here a new patch with all the changes I have just made. After fixing the latest Martin's issue there was >> exposed a new issue maybe related with the initialization per line. (picture attached) > >Thanks. I admit that I'm confused by your patch: I don't understand >your design of calculating and applying the face used for EOL >extension. E.g., where's the code that merges only the non-extensible >attributes of the face at buffer position and assigns that face ID of >the calculated face to it->extend_face_id? 1) This is something confusing even for me. because I was doing that the other way around as in my initial mental scheme the "extensible" part of the face should be associated (somehow, contained or mapped) with every extensible face || else 0 (DEFAULT_FACE_ID). So it will be easy to check that and go forth and back at EOL. >And why did you copy all >the lines that assign to it->face_id with similar lines that assign >something similar (sometimes identical) to it->extend_face_id? 2) This was a desperate try to check where I was caching something wrong. In some cases it will be needed to do that because there are points were the face_id is set and reset latter and it is faster to cache also the extend_face_id instead of calculating it because there is not conversion method. (explication at the end) >And >why do you have to save and restore extend_face_id during some >operations, like we do with it->face_id? Etc. etc. > 3) Same than above. Hopefully this will be removed. For some reason before Martin faced the issue he reported on yesterday, the code was somehow working for me more or less as expected. So it seems to be that something was not initialized and hiding the bigger issues in my part. >Can you post a description of the design and the implementation, to >help me find the light here? In particular, I don't think I >understand the meaning of "the face should be extended after EOL", if >that face is merged with other faces to realize the face to be >actually used in display. This semantics seems not to be explained >anywhere, so it's hard to judge whether the implementation satisfies >the requirements/expectations. > 4) Sorry for that. the face should be extended after EOL means (somehow) that the attributes specified in the face are merged with the ones in other extensible faces to extend after EOL. The conditional to merge (probably wrong) is in merge_extend_glyph_face in xdisp.c. >> The issue is actually related with the fact that extend_face_id is never restarted to face_id when going back >> from an extend to a non_extend face between lines (for example when mark is active and the iterator crosses >> the pointer to outside the selected region like in the picture). > >I cannot answer this question because my mental model is the opposite: >that the code should temporarily set face_id to be equal to >extend_face_id when producing glyphs beyond EOL, then reset face_id >back to its previous value. But your code doesn't fit this mental >model of mine, so I'm probably missing something. > 5) This is actually what happens more or less. in exted_face_to_end... I set the face_id = extend_face_id and then I reset it back at the end (as usual). The issue in my code is probably that I am not calculating the extend_face_id at EOL correctly. (Mainly because I know I am missing something crucial about where and how to do that.) Actually extend_face_id; once it is set to an extensible face it only merges forth and forth... so even after the region finishes it never resets.... which is actually wrong (my bad)... but I don't know where this happen for the face_id; that's why I was reassigning everywhere to see if I could find it. >> I made all the updates of the extend_face_id in the same places where face_id was updated (even when >> uneeded for now.) > >This is another place for confusion: I don't understand why >extend_face_id should be updated in all those places. In my metal >model, extend_face_id is independent of many/most of the factors that >cause us update face_id. > I know. I just couldn't find a condition... sorry for that. >> But I don't see any special function that is called before >> display_line. > >face_id is initialized in init_iterator, which is always called once >before the first call to display_line. Thereafter, any subsequent >call to display_line "inherits" the value of face_id left in the >iterator object at the end of the previous call to display_line. > I understood this later actually. > > >Whether this fits the logic of using extend_face_id, I cannot say yet; >see the above questions that describe my confusion. > It actually does... but when the it->face_id changes (for example the region ends in the middle of a line) the extend_face_id should know. >Thanks for working on this. I am actually rethinking the whole code... but I need to understand better some details that are unclear for me. Like how to get the "extensible" face_id from a non extensible mixed merged face. Lets say e = (a + b + c + d) where only a and c were extensible. Because if I don't have a cache/face I will need to recalculate that every time and find a way to remember how a face was composed... (remember that e was composed by a; b; c; d and then iterate over those ids, get_face_from_id and do a loop that if EXTENSIBLE-P will merges in extend_face_id. This will be sub efficient. The other problems I see with this is that in general after several merges the resulting face_id could be the same for different sequences of a, b, c, d, f, g, r. So the relation face_id -> extend_face_id is not even injective; as we lost information in the middle. The simplest case: suppose that we have (h == b) but h is extensible and b is not. they both will have different face_id because the vectors are different. Merging (a + b + c + d) == (a + h + c + d) -> same face id but the extensible faces (a + c) != (a + h + c) -> different face_id So I don't know how to face this if I want to do it at the EOL only. Because of that I was somehow searching for a method that could give me (a + h + c) or (a + c) on the fly every time... but this seems to be wrong implemented; so I need MORE help here. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-06 10:30 ` Ergus @ 2019-09-06 13:28 ` Eli Zaretskii 2019-09-06 16:34 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-06 13:28 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Fri, 6 Sep 2019 12:30:23 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > the face should be extended after EOL means (somehow) that the > attributes specified in the face are merged with the ones in other > extensible faces to extend after EOL. So the face we use after EOL should be the result of merging only those faces which have their :extend attribute set to non-nil, is that right? > >face_id is initialized in init_iterator, which is always called once > >before the first call to display_line. Thereafter, any subsequent > >call to display_line "inherits" the value of face_id left in the > >iterator object at the end of the previous call to display_line. > > > I understood this later actually. > > > > > >Whether this fits the logic of using extend_face_id, I cannot say yet; > >see the above questions that describe my confusion. > > > It actually does... but when the it->face_id changes (for example the > region ends in the middle of a line) the extend_face_id should know. Should it? The way I see it, we don't need to care about extend_face_id until we actually come to EOL. > I am actually rethinking the whole code... but I need to understand > better some details that are unclear for me. Like how to get the > "extensible" face_id from a non extensible mixed merged face. Lets say > > e = (a + b + c + d) where only a and c were extensible. Because if I don't > have a cache/face I will need to recalculate that every time and find a > way to remember how a face was composed... (remember that e was composed > by a; b; c; d and then iterate over those ids, get_face_from_id and do a > loop that if EXTENSIBLE-P will merges in extend_face_id. This will be > sub efficient. I don't think you need to remember anything, because Emacs "remembers" for you. All of those faces (a, b, c, d) will still be in effect at EOL (i.e. at the position of the newline character); all you need is to merge them there while ignoring those of them whose :extend attribute is not set. IOW, I thing extend_face_id should only be computed at EOL, either in extend_face_to_end_of_line or in append_space_for_newline. Because you don't need that face ID before you come to EOL. > The simplest case: suppose that we have (h == b) but h is extensible and > b is not. they both will have different face_id because the vectors are > different. > > Merging (a + b + c + d) == (a + h + c + d) -> same face id > but the extensible faces (a + c) != (a + h + c) -> different face_id > > So I don't know how to face this if I want to do it at the EOL > only. Because of that I was somehow searching for a method that could > give me (a + h + c) or (a + c) on the fly every time... but this seems > to be wrong implemented; so I need MORE help here. I think the solution should be to have a variant of the code in handle_face_prop such that it computes the face at EOL. It would do that by modifying face_at_buffer_position and face_at_string_position to accept an additional argument EOL_P, which means merge only faces which have their :extend attribute set. Then the face ID computed for this specially merged face should be used as extend_face_id. Does this make sense? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-06 13:28 ` Eli Zaretskii @ 2019-09-06 16:34 ` Ergus 2019-09-06 18:12 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-06 16:34 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Fri, Sep 06, 2019 at 04:28:20PM +0300, Eli Zaretskii wrote: >> Date: Fri, 6 Sep 2019 12:30:23 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> the face should be extended after EOL means (somehow) that the >> attributes specified in the face are merged with the ones in other >> extensible faces to extend after EOL. > >So the face we use after EOL should be the result of merging only >those faces which have their :extend attribute set to non-nil, is that >right? > Yes. >> >face_id is initialized in init_iterator, which is always called once >> >before the first call to display_line. Thereafter, any subsequent >> >call to display_line "inherits" the value of face_id left in the >> >iterator object at the end of the previous call to display_line. >> > >> I understood this later actually. >> > >> > >> >Whether this fits the logic of using extend_face_id, I cannot say yet; >> >see the above questions that describe my confusion. >> > >> It actually does... but when the it->face_id changes (for example the >> region ends in the middle of a line) the extend_face_id should know. > >Should it? The way I see it, we don't need to care about >extend_face_id until we actually come to EOL. > You are right. >> I am actually rethinking the whole code... but I need to understand >> better some details that are unclear for me. Like how to get the >> "extensible" face_id from a non extensible mixed merged face. Lets say >> >> e = (a + b + c + d) where only a and c were extensible. Because if I don't >> have a cache/face I will need to recalculate that every time and find a >> way to remember how a face was composed... (remember that e was composed >> by a; b; c; d and then iterate over those ids, get_face_from_id and do a >> loop that if EXTENSIBLE-P will merges in extend_face_id. This will be >> sub efficient. > >I don't think you need to remember anything, because Emacs "remembers" >for you. All of those faces (a, b, c, d) will still be in effect at >EOL (i.e. at the position of the newline character); all you need is >to merge them there while ignoring those of them whose :extend >attribute is not set. > >IOW, I thing extend_face_id should only be computed at EOL, either in >extend_face_to_end_of_line or in append_space_for_newline. Because >you don't need that face ID before you come to EOL. > append_space_for_newline is not called in all the cases. and this has to do with the yesterdays question about what face should have the extra space (before extending). >> The simplest case: suppose that we have (h == b) but h is extensible and >> b is not. they both will have different face_id because the vectors are >> different. >> >> Merging (a + b + c + d) == (a + h + c + d) -> same face id >> but the extensible faces (a + c) != (a + h + c) -> different face_id >> >> So I don't know how to face this if I want to do it at the EOL >> only. Because of that I was somehow searching for a method that could >> give me (a + h + c) or (a + c) on the fly every time... but this seems >> to be wrong implemented; so I need MORE help here. > >I think the solution should be to have a variant of the code in >handle_face_prop such that it computes the face at EOL. It would do >that by modifying face_at_buffer_position and face_at_string_position >to accept an additional argument EOL_P, which means merge only faces >which have their :extend attribute set. Then the face ID computed for >this specially merged face should be used as extend_face_id. > >Does this make sense? > Probably yes but more questions :) Lets say that I actually don't understand very well what handle_face_prop does (when it is called and when not). When you say a variant you mean another function to call directly from extend_face_to_end_of_line? Sorry I still don't understand where is (a + b + c + d) computed or where emacs "remembers" that, or if it is computed all the time. But maybe the trick is actually in face_at_buffer_position, face_for_overlay_string or face_at_string_position? If so; then what we really need is a variant of face_at_buffer_position like extend_face_at_buffer_position? (or add to it a parameter to do what we want) does it makes any sense. handle_face_prop can't be modified as it should have a specific prototype. But we can make it a wrapper and create a generalized or use ITERATOR_AT_END_OF_LINE_P internally? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-06 16:34 ` Ergus @ 2019-09-06 18:12 ` Eli Zaretskii 2019-09-07 2:35 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-06 18:12 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Fri, 6 Sep 2019 18:34:56 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > When you say a variant you mean another function to call directly from > extend_face_to_end_of_line? Yes. > Sorry I still don't understand where is (a + > b + c + d) computed or where emacs "remembers" that, or if it is > computed all the time. But maybe the trick is actually in > face_at_buffer_position, face_for_overlay_string or > face_at_string_position? face_at_buffer_position and face_at_string_position collect all the faces that affect a given buffer/string position, and then they merge these faces to produce the face ID to be used by the iterator. By "remember" I meant that if you call face_at_buffer_position for any position between stop positions A and A+1, it will produce the same face ID, because the face properties don't change between stop positions. The data structures maintained by Emacs that determine the faces in effect for a particular position is what "remembers" these faces for you. > If so; then what we really need is a variant of face_at_buffer_position > like extend_face_at_buffer_position? (or add to it a parameter to do > what we want) does it makes any sense. > > handle_face_prop can't be modified as it should have a specific > prototype. But we can make it a wrapper and create a generalized or use > ITERATOR_AT_END_OF_LINE_P internally? What I meant is to write a function like handle_face_prop, but one that instructs face_at_buffer/string_position to merge the relevant faces in a special way, one that takes the :extend attribute into account. Whether the code will be similar enough to what handle_face_prop does now to make them use the same code, is a separate question; I wouldn't be bothered by that at this time. First let's have code that we understand and that works; we can bother about cleaning up and optimizing later. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-06 18:12 ` Eli Zaretskii @ 2019-09-07 2:35 ` Ergus 2019-09-07 6:41 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-07 2:35 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Fri, Sep 06, 2019 at 09:12:06PM +0300, Eli Zaretskii wrote: >> Date: Fri, 6 Sep 2019 18:34:56 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> When you say a variant you mean another function to call directly from >> extend_face_to_end_of_line? > >Yes. > >> Sorry I still don't understand where is (a + >> b + c + d) computed or where emacs "remembers" that, or if it is >> computed all the time. But maybe the trick is actually in >> face_at_buffer_position, face_for_overlay_string or >> face_at_string_position? > >face_at_buffer_position and face_at_string_position collect all the >faces that affect a given buffer/string position, and then they merge >these faces to produce the face ID to be used by the iterator. By >"remember" I meant that if you call face_at_buffer_position for any >position between stop positions A and A+1, it will produce the same >face ID, because the face properties don't change between stop >positions. The data structures maintained by Emacs that determine the >faces in effect for a particular position is what "remembers" these >faces for you. > >> If so; then what we really need is a variant of face_at_buffer_position >> like extend_face_at_buffer_position? (or add to it a parameter to do >> what we want) does it makes any sense. >> >> handle_face_prop can't be modified as it should have a specific >> prototype. But we can make it a wrapper and create a generalized or use >> ITERATOR_AT_END_OF_LINE_P internally? > >What I meant is to write a function like handle_face_prop, but one >that instructs face_at_buffer/string_position to merge the relevant >faces in a special way, one that takes the :extend attribute into >account. Whether the code will be similar enough to what >handle_face_prop does now to make them use the same code, is a >separate question; I wouldn't be bothered by that at this time. First >let's have code that we understand and that works; we can bother about >cleaning up and optimizing later. > Hi Eli: In your solution I am facing an issue that I am not sure how to solve: I added a function handle_face_prop_general; that I call in extend_face_to_end_of_line but I get an inf loop because in the call stack I have: extend_face_to_end_of_line handle_face_prop_general face_at_buffer_position Fget_text_property Ftext_properties_at validate_interval_range That has a condition: if (!(BUF_BEGV (b) <= XFIXNUM (*begin) && XFIXNUM (*begin) <= XFIXNUM (*end) && XFIXNUM (*end) <= BUF_ZV (b))) args_out_of_range (*begin, *end); And for some reason: XFIXNUM (*end) <= BUF_ZV (b) is false; so the function args_out_of_range emits a signal and never returns. It is possible that in the first calls to extend_face_to_end_of_line the BUF_ZV (b) is not initialized yet? Because it is always 1. when I print it. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-07 2:35 ` Ergus @ 2019-09-07 6:41 ` Eli Zaretskii 0 siblings, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-09-07 6:41 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sat, 7 Sep 2019 04:35:44 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > In your solution I am facing an issue that I am not sure how to solve: > > I added a function handle_face_prop_general; that I call in > extend_face_to_end_of_line but I get an inf loop because in the call > stack I have: > > extend_face_to_end_of_line > handle_face_prop_general > face_at_buffer_position > Fget_text_property > Ftext_properties_at > validate_interval_range > > That has a condition: > > if (!(BUF_BEGV (b) <= XFIXNUM (*begin) > && XFIXNUM (*begin) <= XFIXNUM (*end) > && XFIXNUM (*end) <= BUF_ZV (b))) > args_out_of_range (*begin, *end); > > And for some reason: > > XFIXNUM (*end) <= BUF_ZV (b) is false; so the function args_out_of_range > emits a signal and never returns. You need to understand how this happens. What are the values of *begin and *end in this case, and what is the position of the iterator you pass to handle_face_prop_general? > It is possible that in the first calls to extend_face_to_end_of_line the > BUF_ZV (b) is not initialized yet? No. But please tell more about "the first call to extend_face_to_end_of_line". Which code calls it, and for what buffer? > Because it is always 1. when I print it. If BUF_ZV is 1, it's an empty buffer. What is it->w->contents in your call? It should be the buffer whose text you are displaying. ^ permalink raw reply [flat|nested] 183+ messages in thread
[parent not found: <20191012222305.jpjinkd5y2lz6xiv@Ergus>]
[parent not found: <83mue5kmfx.fsf@gnu.org>]
* Re: Question about display engine [not found] ` <83mue5kmfx.fsf@gnu.org> @ 2019-10-13 15:40 ` Ergus 2019-10-13 16:06 ` Eli Zaretskii 2019-10-13 16:11 ` Eli Zaretskii 0 siblings, 2 replies; 183+ messages in thread From: Ergus @ 2019-10-13 15:40 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel Hi Eli: On Sun, Oct 13, 2019 at 12:46:10PM +0300, Eli Zaretskii wrote: >> Date: Sun, 13 Oct 2019 00:23:05 +0200 >> From: Ergus <spacibba@aol.com> >> >> >I don't understand why would we want to add a call to handle_face_prop >> >there. >> > >> >> The call there is to emulate the part in our branch that produced the >> issue. And isolate the source of the problem, independently of all the >> other changes. >> >> Remember we modified handle_face_prop to be called here with the extra >> parameter to filter. > >But handle_face_prop modifies some members of its IT argument, whereas >the function called from extend_face_to_end_of_line (face_at_pos) >should not do that, it should just return the face ID to use. > >I now see that face_at_pos modifies it->start_of_box_run_p and >it->face_box_p. This is wrong, you should do that outside of >face_at_pos, in handle_face_prop itself. Maybe this is the reason for >the infloop? If extend_face_to_end_of_line needs to manipulate these >members (does it?), it needs to save and restore the old values. > Fixed now, but that's not the solution for the issue. >> >Can you tell where it loops? That is, describe the sequence of calls >> >and the return values for a single iteration through the loop? >> >> It is a very long loop it jumps here and there in the code it is very >> difficult to explain. But basically it stays going and coming in >> display_line for ever. > >You don't have to explain it, just show me one iteration through the >loop as you step through the code in GDB. > In GDB I have this bt: #0 0x000055cb1453ac98 in redisplay_windows (window=0x55cb15e3bfb5) at ../../src/xdisp.c:16126 #1 0x000055cb1453ac6d in redisplay_windows (window=0x55cb163ffc55) at ../../src/xdisp.c:16120 #2 0x000055cb1455b35d in redisplay_internal () at ../../src/xdisp.c:15596 #3 0x000055cb145fff3f in read_char (commandflag=1, map=0x55cb16838f93, prev_event=0x0, used_mouse_menu=0x7ffc1a89f4eb, end_time=0x0) at ../../src/keyboard.c:2473 #4 0x000055cb1460278a in read_key_sequence (keybuf=<optimized out>, prompt=0x0, dont_downcase_last=<optimized out>, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=<optimized out>) at ../../src/keyboard.c:9527 #5 0x000055cb14603e2c in command_loop_1 () at ../../src/lisp.h:1032 #6 0x000055cb1466af87 in internal_condition_case (bfun=bfun@entry=0x55cb14603c30 <command_loop_1>, handlers=handlers@entry=0x90, hfun=hfun@entry=0x55cb145fadc0 <cmd_error>) at ../../src/eval.c:1355 #7 0x000055cb145f5b94 in command_loop_2 (ignore=ignore@entry=0x0) at ../../src/lisp.h:1032 #8 0x000055cb1466aee1 in internal_catch (tag=tag@entry=0xd4a0, func=func@entry=0x55cb145f5b70 <command_loop_2>, arg=arg@entry=0x0) at ../../src/eval.c:1116 #9 0x000055cb145f5b3b in command_loop () at ../../src/lisp.h:1032 #10 0x000055cb145fa9d6 in recursive_edit_1 () at ../../src/keyboard.c:714 #11 0x000055cb145fad02 in Frecursive_edit () at ../../src/keyboard.c:786 #12 0x000055cb1451c957 in main (argc=18, argv=<optimized out>) at ../../src/emacs.c:2055 After some other tests I just did; I found that: #0 seems to be the root of the loop. redisplay_windows never ends (inf loop) and I can't understand why. But at least this explains why in gui it works but not in tui, because there is the WINDOWP test. What I can't understand is how the code can be in #1 that should always filtered by the WINDOWP condition in tui right? In any case the inf loop is there, but the recursions levels does not grow... so after the first time it enters in #1, it goes in the other branch if the if. On the other hand I don't understand how is this related with the call of face_at_pos in the extend_face_to_end_of_line. Any idea? >> Maybe you look at it and you find the issue in 5 seconds, but there >> is still too much I ignore to get it. > >Unlikely. And it is not wise to lose all the information you have >already collected about this problem, it could help me quite a lot. >At the very least please show a backtrace from inside the infloop, and >tell whether we are iterating over a buffer or a string, and if the >latter, what kind of string is that (overlay string, display string?). > >> Magit is available in melpa. Installing and using it is trivial. > >I don't need to install it, I just need to load it. > Then the command I send before should be enough. >> Maybe Martin have something to say about this? > >You didn't CC Martin on this message. My bad ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 15:40 ` Ergus @ 2019-10-13 16:06 ` Eli Zaretskii 2019-10-13 16:44 ` Ergus 2019-10-13 16:11 ` Eli Zaretskii 1 sibling, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-10-13 16:06 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sun, 13 Oct 2019 17:40:52 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > #0 0x000055cb1453ac98 in redisplay_windows (window=0x55cb15e3bfb5) at ../../src/xdisp.c:16126 > #1 0x000055cb1453ac6d in redisplay_windows (window=0x55cb163ffc55) at ../../src/xdisp.c:16120 > #2 0x000055cb1455b35d in redisplay_internal () at ../../src/xdisp.c:15596 > #3 0x000055cb145fff3f in read_char (commandflag=1, map=0x55cb16838f93, prev_event=0x0, used_mouse_menu=0x7ffc1a89f4eb, end_time=0x0) at ../../src/keyboard.c:2473 > #4 0x000055cb1460278a in read_key_sequence > (keybuf=<optimized out>, prompt=0x0, dont_downcase_last=<optimized out>, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=<optimized out>) > at ../../src/keyboard.c:9527 > #5 0x000055cb14603e2c in command_loop_1 () at ../../src/lisp.h:1032 > #6 0x000055cb1466af87 in internal_condition_case > (bfun=bfun@entry=0x55cb14603c30 <command_loop_1>, handlers=handlers@entry=0x90, hfun=hfun@entry=0x55cb145fadc0 <cmd_error>) at ../../src/eval.c:1355 > #7 0x000055cb145f5b94 in command_loop_2 (ignore=ignore@entry=0x0) at ../../src/lisp.h:1032 > #8 0x000055cb1466aee1 in internal_catch (tag=tag@entry=0xd4a0, func=func@entry=0x55cb145f5b70 <command_loop_2>, arg=arg@entry=0x0) at ../../src/eval.c:1116 > #9 0x000055cb145f5b3b in command_loop () at ../../src/lisp.h:1032 > #10 0x000055cb145fa9d6 in recursive_edit_1 () at ../../src/keyboard.c:714 > #11 0x000055cb145fad02 in Frecursive_edit () at ../../src/keyboard.c:786 > #12 0x000055cb1451c957 in main (argc=18, argv=<optimized out>) at ../../src/emacs.c:2055 > > After some other tests I just did; I found that: > > #0 seems to be the root of the loop. redisplay_windows never ends (inf > loop) and I can't understand why. But at least this explains why in gui > it works but not in tui, because there is the WINDOWP test. The WINDOWP test has nothing to do with GUI vs TTY, it tests whether w->contents is a window or a buffer. > What I can't understand is how the code can be in #1 that should always > filtered by the WINDOWP condition in tui right? No, see above. This function is a simple depth-first tree traversal of the window tree, starting from the root window of a frame. Each leaf of the window tree has a buffer in its w->contents pointer, while intermediate nodes of the tree have windows in that pointer. > In any case the inf loop is there, but the recursions levels does not > grow... so after the first time it enters in #1, it goes in the other > branch if the if. If it goes to the other branch, it should descend the tree via the w->next pointer, and eventually get to a leaf node. Could it be that redisplay_window_0, or some function it calls, signals an error, which is caught by internal_condition_case_1? What happens if you put a breakpoint in signal_or_quit, does it get called from redisplay_window or some other function called by redisplay_windows? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 16:06 ` Eli Zaretskii @ 2019-10-13 16:44 ` Ergus 2019-10-13 17:04 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-10-13 16:44 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sun, Oct 13, 2019 at 07:06:18PM +0300, Eli Zaretskii wrote: >> Date: Sun, 13 Oct 2019 17:40:52 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> #0 0x000055cb1453ac98 in redisplay_windows (window=0x55cb15e3bfb5) at ../../src/xdisp.c:16126 >> #1 0x000055cb1453ac6d in redisplay_windows (window=0x55cb163ffc55) at ../../src/xdisp.c:16120 >> #2 0x000055cb1455b35d in redisplay_internal () at ../../src/xdisp.c:15596 >> #3 0x000055cb145fff3f in read_char (commandflag=1, map=0x55cb16838f93, prev_event=0x0, used_mouse_menu=0x7ffc1a89f4eb, end_time=0x0) at ../../src/keyboard.c:2473 >> #4 0x000055cb1460278a in read_key_sequence >> (keybuf=<optimized out>, prompt=0x0, dont_downcase_last=<optimized out>, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=<optimized out>) >> at ../../src/keyboard.c:9527 >> #5 0x000055cb14603e2c in command_loop_1 () at ../../src/lisp.h:1032 >> #6 0x000055cb1466af87 in internal_condition_case >> (bfun=bfun@entry=0x55cb14603c30 <command_loop_1>, handlers=handlers@entry=0x90, hfun=hfun@entry=0x55cb145fadc0 <cmd_error>) at ../../src/eval.c:1355 >> #7 0x000055cb145f5b94 in command_loop_2 (ignore=ignore@entry=0x0) at ../../src/lisp.h:1032 >> #8 0x000055cb1466aee1 in internal_catch (tag=tag@entry=0xd4a0, func=func@entry=0x55cb145f5b70 <command_loop_2>, arg=arg@entry=0x0) at ../../src/eval.c:1116 >> #9 0x000055cb145f5b3b in command_loop () at ../../src/lisp.h:1032 >> #10 0x000055cb145fa9d6 in recursive_edit_1 () at ../../src/keyboard.c:714 >> #11 0x000055cb145fad02 in Frecursive_edit () at ../../src/keyboard.c:786 >> #12 0x000055cb1451c957 in main (argc=18, argv=<optimized out>) at ../../src/emacs.c:2055 >> >> After some other tests I just did; I found that: >> >> #0 seems to be the root of the loop. redisplay_windows never ends (inf >> loop) and I can't understand why. But at least this explains why in gui >> it works but not in tui, because there is the WINDOWP test. > >The WINDOWP test has nothing to do with GUI vs TTY, it tests whether >w->contents is a window or a buffer. > >> What I can't understand is how the code can be in #1 that should always >> filtered by the WINDOWP condition in tui right? > >No, see above. > >This function is a simple depth-first tree traversal of the window >tree, starting from the root window of a frame. Each leaf of the >window tree has a buffer in its w->contents pointer, while >intermediate nodes of the tree have windows in that pointer. > >> In any case the inf loop is there, but the recursions levels does not >> grow... so after the first time it enters in #1, it goes in the other >> branch if the if. > >If it goes to the other branch, it should descend the tree via the >w->next pointer, and eventually get to a leaf node. > >Could it be that redisplay_window_0, or some function it calls, >signals an error, which is caught by internal_condition_case_1? What >happens if you put a breakpoint in signal_or_quit, does it get called >from redisplay_window or some other function called by >redisplay_windows? Yes, actually: #0 0x00005597732a0380 in signal_or_quit (error_symbol=0x2cd0, data=0x559775ee2633, keyboard_quit=false) at ../../src/eval.c:1586 #1 0x000055977314c308 in Fsignal (error_symbol=<optimized out>, error_symbol@entry=0x2cd0, data=<optimized out>) at ../../src/eval.c:1568 #2 0x000055977314c4c9 in xsignal (data=<optimized out>, error_symbol=0x2cd0) at ../../src/lisp.h:4139 #3 0x000055977314c4c9 in xsignal2 (error_symbol=error_symbol@entry=0x2cd0, arg1=<optimized out>, arg2=<optimized out>) at ../../src/eval.c:1713 #4 0x000055977314b76e in args_out_of_range (a1=<optimized out>, a2=<optimized out>) at ../../src/lisp.h:1032 #5 0x000055977314e97b in validate_interval_range (object=0x559775cee0d5, begin=0x7fff35ec34b8, end=0x7fff35ec34b8, force=<optimized out>) at ../../src/textprop.c:158 #6 0x00005597732f4050 in Ftext_properties_at (position=<optimized out>, object=<optimized out>) at ../../src/textprop.c:572 #7 0x00005597732f40bc in Fget_text_property (position=<optimized out>, prop=0x5d30, object=<optimized out>) at ../../src/textprop.c:592 #8 0x00005597731f8eec in face_at_buffer_position (w=0x5597758e7620, pos=0, endptr=endptr@entry=0x7fff35ec3650, limit=100, mouse=mouse@entry=false, base_face_id=1, attr_filter=LFACE_EXTEND_INDEX) at ../../src/xfaces.c:6090 #9 0x000055977316ab25 in face_at_pos (it=0x7fff35ec3710, attr_filter=LFACE_EXTEND_INDEX) at ../../src/xdisp.c:4167 #10 0x000055977317083d in extend_face_to_end_of_line (it=0x7fff35ec3710) at ../../src/xdisp.c:21584 #11 0x0000559773185891 in display_mode_line (w=w@entry=0x5597758e7620, face_id=<optimized out>, format=0x7efd5d2d9ed3) at ../../src/xdisp.c:24990 #12 0x0000559773185afe in display_mode_lines (w=w@entry=0x5597758e7620) at ../../src/lisp.h:730 #13 0x000055977319ebbc in redisplay_window (window=0x5597758e7625, just_this_one_p=<optimized out>) at ../../src/xdisp.c:18803 #14 0x00005597731a327b in redisplay_window_0 (window=window@entry=0x5597758e7625) at ../../src/xdisp.c:16146 #15 0x000055977329f014 in internal_condition_case_1 (bfun=bfun@entry=0x5597731a3250 <redisplay_window_0>, arg=arg@entry=0x5597758e7625, handlers=<optimized out>, hfun=hfun@entry=0x559773165800 <redisplay_window_error>) at ../../src/eval.c:1379 #16 0x000055977316ec98 in redisplay_windows (window=0x5597758e7625) at ../../src/xdisp.c:16126 #17 0x000055977316ec6d in redisplay_windows (window=0x5597758e7415) at ../../src/xdisp.c:16120 #18 0x000055977318f35d in redisplay_internal () at ../../src/xdisp.c:15596 #19 0x0000559773233f3f in read_char (commandflag=1, map=0x559775ee36d3, prev_event=0x0, used_mouse_menu=0x7fff35ec8cbb, end_time=0x0) at ../../src/keyboard.c:2473 #20 0x000055977323678a in read_key_sequence (keybuf=<optimized out>, prompt=0x0, dont_downcase_last=<optimized out>, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=<optimized out>) at ../../src/keyboard.c:9527 #21 0x0000559773237e2c in command_loop_1 () at ../../src/lisp.h:1032 #22 0x000055977329ef87 in internal_condition_case (bfun=bfun@entry=0x559773237c30 <command_loop_1>, handlers=handlers@entry=0x90, hfun=hfun@entry=0x55977322edc0 <cmd_error>) at ../../src/eval.c:1355 #23 0x0000559773229b94 in command_loop_2 (ignore=ignore@entry=0x0) at ../../src/lisp.h:1032 #24 0x000055977329eee1 in internal_catch (tag=tag@entry=0xd4a0, func=func@entry=0x559773229b70 <command_loop_2>, arg=arg@entry=0x0) at ../../src/eval.c:1116 #25 0x0000559773229b3b in command_loop () at ../../src/lisp.h:1032 #26 0x000055977322e9d6 in recursive_edit_1 () at ../../src/keyboard.c:714 #27 0x000055977322ed02 in Frecursive_edit () at ../../src/keyboard.c:786 #28 0x0000559773150957 in main (argc=18, argv=<optimized out>) at #../../src/emacs.c:2055 This makes more sense now. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 16:44 ` Ergus @ 2019-10-13 17:04 ` Eli Zaretskii 2019-10-13 18:11 ` Ergus 2019-10-13 18:25 ` Ergus 0 siblings, 2 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-10-13 17:04 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sun, 13 Oct 2019 18:44:24 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >Could it be that redisplay_window_0, or some function it calls, > >signals an error, which is caught by internal_condition_case_1? What > >happens if you put a breakpoint in signal_or_quit, does it get called > >from redisplay_window or some other function called by > >redisplay_windows? > > Yes, actually: > > #0 0x00005597732a0380 in signal_or_quit (error_symbol=0x2cd0, data=0x559775ee2633, keyboard_quit=false) at ../../src/eval.c:1586 > #1 0x000055977314c308 in Fsignal (error_symbol=<optimized out>, error_symbol@entry=0x2cd0, data=<optimized out>) at ../../src/eval.c:1568 > #2 0x000055977314c4c9 in xsignal (data=<optimized out>, error_symbol=0x2cd0) at ../../src/lisp.h:4139 > #3 0x000055977314c4c9 in xsignal2 (error_symbol=error_symbol@entry=0x2cd0, arg1=<optimized out>, arg2=<optimized out>) at ../../src/eval.c:1713 > #4 0x000055977314b76e in args_out_of_range (a1=<optimized out>, a2=<optimized out>) at ../../src/lisp.h:1032 > #5 0x000055977314e97b in validate_interval_range (object=0x559775cee0d5, begin=0x7fff35ec34b8, end=0x7fff35ec34b8, force=<optimized out>) at ../../src/textprop.c:158 > #6 0x00005597732f4050 in Ftext_properties_at (position=<optimized out>, object=<optimized out>) at ../../src/textprop.c:572 > #7 0x00005597732f40bc in Fget_text_property (position=<optimized out>, prop=0x5d30, object=<optimized out>) at ../../src/textprop.c:592 > #8 0x00005597731f8eec in face_at_buffer_position > (w=0x5597758e7620, pos=0, endptr=endptr@entry=0x7fff35ec3650, limit=100, mouse=mouse@entry=false, base_face_id=1, attr_filter=LFACE_EXTEND_INDEX) > at ../../src/xfaces.c:6090 Then looking at the position that causes the error will probably tell you what's wrong. (Is OBJECT passed to Fget_text_property a string? if not, position of zero is invalid.) ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 17:04 ` Eli Zaretskii @ 2019-10-13 18:11 ` Ergus 2019-10-13 18:25 ` Ergus 1 sibling, 0 replies; 183+ messages in thread From: Ergus @ 2019-10-13 18:11 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sun, Oct 13, 2019 at 08:04:02PM +0300, Eli Zaretskii wrote: >> Date: Sun, 13 Oct 2019 18:44:24 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >Could it be that redisplay_window_0, or some function it calls, >> >signals an error, which is caught by internal_condition_case_1? What >> >happens if you put a breakpoint in signal_or_quit, does it get called >> >from redisplay_window or some other function called by >> >redisplay_windows? >> >> Yes, actually: >> >> #0 0x00005597732a0380 in signal_or_quit (error_symbol=0x2cd0, data=0x559775ee2633, keyboard_quit=false) at ../../src/eval.c:1586 >> #1 0x000055977314c308 in Fsignal (error_symbol=<optimized out>, error_symbol@entry=0x2cd0, data=<optimized out>) at ../../src/eval.c:1568 >> #2 0x000055977314c4c9 in xsignal (data=<optimized out>, error_symbol=0x2cd0) at ../../src/lisp.h:4139 >> #3 0x000055977314c4c9 in xsignal2 (error_symbol=error_symbol@entry=0x2cd0, arg1=<optimized out>, arg2=<optimized out>) at ../../src/eval.c:1713 >> #4 0x000055977314b76e in args_out_of_range (a1=<optimized out>, a2=<optimized out>) at ../../src/lisp.h:1032 >> #5 0x000055977314e97b in validate_interval_range (object=0x559775cee0d5, begin=0x7fff35ec34b8, end=0x7fff35ec34b8, force=<optimized out>) at ../../src/textprop.c:158 >> #6 0x00005597732f4050 in Ftext_properties_at (position=<optimized out>, object=<optimized out>) at ../../src/textprop.c:572 >> #7 0x00005597732f40bc in Fget_text_property (position=<optimized out>, prop=0x5d30, object=<optimized out>) at ../../src/textprop.c:592 >> #8 0x00005597731f8eec in face_at_buffer_position >> (w=0x5597758e7620, pos=0, endptr=endptr@entry=0x7fff35ec3650, limit=100, mouse=mouse@entry=false, base_face_id=1, attr_filter=LFACE_EXTEND_INDEX) >> at ../../src/xfaces.c:6090 > >Then looking at the position that causes the error will probably tell >you what's wrong. (Is OBJECT passed to Fget_text_property a string? >if not, position of zero is invalid.) > That's exactly the problem. IT_CHARPOS (*it), is returning zero in face_at_pos and !STRINGP (it->string). Could you tell me whats going on please. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 17:04 ` Eli Zaretskii 2019-10-13 18:11 ` Ergus @ 2019-10-13 18:25 ` Ergus 2019-10-13 18:53 ` Eli Zaretskii 1 sibling, 1 reply; 183+ messages in thread From: Ergus @ 2019-10-13 18:25 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sun, Oct 13, 2019 at 08:04:02PM +0300, Eli Zaretskii wrote: >> Date: Sun, 13 Oct 2019 18:44:24 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >Could it be that redisplay_window_0, or some function it calls, >> >signals an error, which is caught by internal_condition_case_1? What >> >happens if you put a breakpoint in signal_or_quit, does it get called >> >from redisplay_window or some other function called by >> >redisplay_windows? >> >> Yes, actually: >> >> #0 0x00005597732a0380 in signal_or_quit (error_symbol=0x2cd0, data=0x559775ee2633, keyboard_quit=false) at ../../src/eval.c:1586 >> #1 0x000055977314c308 in Fsignal (error_symbol=<optimized out>, error_symbol@entry=0x2cd0, data=<optimized out>) at ../../src/eval.c:1568 >> #2 0x000055977314c4c9 in xsignal (data=<optimized out>, error_symbol=0x2cd0) at ../../src/lisp.h:4139 >> #3 0x000055977314c4c9 in xsignal2 (error_symbol=error_symbol@entry=0x2cd0, arg1=<optimized out>, arg2=<optimized out>) at ../../src/eval.c:1713 >> #4 0x000055977314b76e in args_out_of_range (a1=<optimized out>, a2=<optimized out>) at ../../src/lisp.h:1032 >> #5 0x000055977314e97b in validate_interval_range (object=0x559775cee0d5, begin=0x7fff35ec34b8, end=0x7fff35ec34b8, force=<optimized out>) at ../../src/textprop.c:158 >> #6 0x00005597732f4050 in Ftext_properties_at (position=<optimized out>, object=<optimized out>) at ../../src/textprop.c:572 >> #7 0x00005597732f40bc in Fget_text_property (position=<optimized out>, prop=0x5d30, object=<optimized out>) at ../../src/textprop.c:592 >> #8 0x00005597731f8eec in face_at_buffer_position >> (w=0x5597758e7620, pos=0, endptr=endptr@entry=0x7fff35ec3650, limit=100, mouse=mouse@entry=false, base_face_id=1, attr_filter=LFACE_EXTEND_INDEX) >> at ../../src/xfaces.c:6090 > >Then looking at the position that causes the error will probably tell >you what's wrong. (Is OBJECT passed to Fget_text_property a string? >if not, position of zero is invalid.) > Actually conditioning the call to face_at_pos to when IT_CHARPOS (*it) != 0 seems to fix the issue with magit... but maybe we are just hiding something under the carpet here. Can you imagine something more general than that just this condition? Or what could be doing magit to expose this and not the other packages? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 18:25 ` Ergus @ 2019-10-13 18:53 ` Eli Zaretskii 2019-10-13 19:38 ` Ergus 2019-10-13 19:41 ` Ergus 0 siblings, 2 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-10-13 18:53 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sun, 13 Oct 2019 20:25:42 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >Then looking at the position that causes the error will probably tell > >you what's wrong. (Is OBJECT passed to Fget_text_property a string? > >if not, position of zero is invalid.) > > > > Actually conditioning the call to face_at_pos to when IT_CHARPOS (*it) > != 0 seems to fix the issue with magit... but maybe we are just hiding > something under the carpet here. Can you imagine something more general > than that just this condition? How did it happen that IT_CHARPOS(*it) is zero? If we are iterating over a buffer, that cannot happen, because we begin from 1 and go forward. Is it->sp zero or higher? If it's higher, then we are not iterating over a buffer, but something else (a string, an image, or something similar). What are the values of it->method and it->what? Can you show the result of (gdb) pgrowx it->glyph_row ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 18:53 ` Eli Zaretskii @ 2019-10-13 19:38 ` Ergus 2019-10-13 21:01 ` Eli Zaretskii 2019-10-13 19:41 ` Ergus 1 sibling, 1 reply; 183+ messages in thread From: Ergus @ 2019-10-13 19:38 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sun, Oct 13, 2019 at 09:53:13PM +0300, Eli Zaretskii wrote: >> Date: Sun, 13 Oct 2019 20:25:42 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >Then looking at the position that causes the error will probably tell >> >you what's wrong. (Is OBJECT passed to Fget_text_property a string? >> >if not, position of zero is invalid.) >> > >> >> Actually conditioning the call to face_at_pos to when IT_CHARPOS (*it) >> != 0 seems to fix the issue with magit... but maybe we are just hiding >> something under the carpet here. Can you imagine something more general >> than that just this condition? > >How did it happen that IT_CHARPOS(*it) is zero? If we are iterating >over a buffer, that cannot happen, because we begin from 1 and go >forward. > >Is it->sp zero or higher? If it's higher, then we are not iterating >over a buffer, but something else (a string, an image, or something >similar). What are the values of it->method and it->what? Can you >show the result of > > (gdb) pgrowx it->glyph_row > (gdb) p it->sp $1 = 0 (gdb) p it->method $2 = GET_FROM_C_STRING (gdb) p it->what $3 = IT_CHARACTER (gdb) pgrowx it->glyph_row TEXT: 85 glyphs 0 0: CHAR[-] str=0x4fab1a8f[0] blev=0,btyp=L w=1 a+d=0+0 face=1 1 1: CHAR[U] str=0x4fab18f0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 2 2: CHAR[U] str=0x4fab18f0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 3 3: CHAR[U] str=0x4fab18f0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 4 4: CHAR[:] str=0xf2787f0[0] blev=0,btyp=L w=1 a+d=0+0 face=1 5 5: CHAR[%] str=0x4faaee54[1] blev=0,btyp=L w=1 a+d=0+0 face=1 6 6: CHAR[%] str=0x4faaede4[1] blev=0,btyp=L w=1 a+d=0+0 face=1 7 7: CHAR[-] str=0x4fab1721[1] blev=0,btyp=L w=1 a+d=0+0 face=1 8 8: CHAR[-] str=0x4fa9d9a8[0] blev=0,btyp=L w=1 a+d=0+0 face=1 9 9: CHAR[F] str=0x4fa9d9a8[2] blev=0,btyp=L w=1 a+d=0+0 face=1 10 10: CHAR[1] str=0x4fa9d9a8[2] blev=0,btyp=L w=1 a+d=0+0 face=1 11 11: CHAR[ ] str=0x4fa9d9a8[3] blev=0,btyp=L w=1 a+d=0+0 face=1 12 12: CHAR[ ] str=0x4fa9d9a8[4] blev=0,btyp=L w=1 a+d=0+0 face=1 13 13: CHAR[m] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 14 14: CHAR[a] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 15 15: CHAR[g] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 16 16: CHAR[i] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 17 17: CHAR[t] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 18 18: CHAR[-] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 19 19: CHAR[l] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 20 20: CHAR[o] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 21 21: CHAR[g] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 22 22: CHAR[:] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 23 23: CHAR[ ] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 24 24: CHAR[e] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 25 25: CHAR[m] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 26 26: CHAR[a] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 27 27: CHAR[c] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 28 28: CHAR[s] str=0x4fab16fc[1] blev=0,btyp=L w=1 a+d=0+0 face=20 MB 29 29: CHAR[ ] str=0x4fab16f8[0] blev=0,btyp=L w=1 a+d=0+0 face=1 30 30: CHAR[ ] str=0x4fab16f8[1] blev=0,btyp=L w=1 a+d=0+0 face=1 31 31: CHAR[ ] str=0x4fab16f8[2] blev=0,btyp=L w=1 a+d=0+0 face=1 32 32: CHAR[T] str=0xf278800[1] blev=0,btyp=L w=1 a+d=0+0 face=1 33 33: CHAR[o] str=0xf278800[1] blev=0,btyp=L w=1 a+d=0+0 face=1 34 34: CHAR[p] str=0xf278800[1] blev=0,btyp=L w=1 a+d=0+0 face=1 35 35: CHAR[ ] str=0x4fa602e6[0] blev=0,btyp=L w=1 a+d=0+0 face=1 36 36: CHAR[L] str=0x4fa602e6[1] blev=0,btyp=L w=1 a+d=0+0 face=1 37 37: CHAR[1] str=0x4fa602e6[3] blev=0,btyp=L w=1 a+d=0+0 face=1 38 38: CHAR[ ] pos=-1 blev=0,btyp=B w=1 a+d=0+0 face=1 39 39: CHAR[ ] pos=-1 blev=0,btyp=B w=1 a+d=0+0 face=1 40 40: CHAR[ ] pos=-1 blev=0,btyp=B w=1 a+d=0+0 face=1 41 41: CHAR[ ] str=0x4fab16f5[0] blev=0,btyp=L w=1 a+d=0+0 face=1 42 42: CHAR[ ] str=0x4fab16f5[1] blev=0,btyp=L w=1 a+d=0+0 face=1 43 43: CHAR[(] str=0x4fab16e0[0] blev=0,btyp=L w=1 a+d=0+0 face=1 44 44: CHAR[M] str=0xf95dcc0[0] blev=0,btyp=L w=1 a+d=0+0 face=1 45 45: CHAR[a] str=0xf95dcc0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 46 46: CHAR[g] str=0xf95dcc0[2] blev=0,btyp=L w=1 a+d=0+0 face=1 47 47: CHAR[i] str=0xf95dcc0[3] blev=0,btyp=L w=1 a+d=0+0 face=1 48 48: CHAR[t] str=0xf95dcc0[4] blev=0,btyp=L w=1 a+d=0+0 face=1 49 49: CHAR[ ] str=0xf95dcc0[5] blev=0,btyp=L w=1 a+d=0+0 face=1 50 50: CHAR[L] str=0xf95dcc0[6] blev=0,btyp=L w=1 a+d=0+0 face=1 51 51: CHAR[o] str=0xf95dcc0[7] blev=0,btyp=L w=1 a+d=0+0 face=1 52 52: CHAR[g] str=0xf95dcc0[8] blev=0,btyp=L w=1 a+d=0+0 face=1 53 53: CHAR[)] str=0x4fa729d9[0] blev=0,btyp=L w=1 a+d=0+0 face=1 54 54: CHAR[ ] str=0x4fa729ae[0] blev=0,btyp=L w=1 a+d=0+0 face=1 55 55: CHAR[-] str=0x4fa71e84[0] blev=0,btyp=L w=1 a+d=0+0 face=1 56 56: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 57 57: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 58 58: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 59 59: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 60 60: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 61 61: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 62 62: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 63 63: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 64 64: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 65 65: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 66 66: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 67 67: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 68 68: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 69 69: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 70 70: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 71 71: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 72 72: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 73 73: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 74 74: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 75 75: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 76 76: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 77 77: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 78 78: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 79 79: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 80 80: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 81 81: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 82 82: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 83 83: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 84 84: CHAR[-] str=0x4fa71e84[2] blev=0,btyp=L w=1 a+d=0+0 face=1 ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 19:38 ` Ergus @ 2019-10-13 21:01 ` Eli Zaretskii 2019-10-13 22:27 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-10-13 21:01 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sun, 13 Oct 2019 21:38:36 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > (gdb) p it->sp > $1 = 0 > (gdb) p it->method > $2 = GET_FROM_C_STRING If we are producing glyphs from a C string, then faces should not be used at all, because C strings cannot have faces. So you should to condition the call to face_at_pos on something like it->s == NULL because there can not be any face on any position of a C string. > (gdb) pgrowx it->glyph_row > TEXT: 85 glyphs > 0 0: CHAR[-] str=0x4fab1a8f[0] blev=0,btyp=L w=1 a+d=0+0 face=1 > 1 1: CHAR[U] str=0x4fab18f0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 > 2 2: CHAR[U] str=0x4fab18f0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 > 3 3: CHAR[U] str=0x4fab18f0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 > 4 4: CHAR[:] str=0xf2787f0[0] blev=0,btyp=L w=1 a+d=0+0 face=1 > 5 5: CHAR[%] str=0x4faaee54[1] blev=0,btyp=L w=1 a+d=0+0 face=1 > 6 6: CHAR[%] str=0x4faaede4[1] blev=0,btyp=L w=1 a+d=0+0 face=1 > 7 7: CHAR[-] str=0x4fab1721[1] blev=0,btyp=L w=1 a+d=0+0 face=1 > 8 8: CHAR[-] str=0x4fa9d9a8[0] blev=0,btyp=L w=1 a+d=0+0 face=1 > 9 9: CHAR[F] str=0x4fa9d9a8[2] blev=0,btyp=L w=1 a+d=0+0 face=1 > 10 10: CHAR[1] str=0x4fa9d9a8[2] blev=0,btyp=L w=1 a+d=0+0 face=1 This is a mode line, so it figures out: extend_face_to_end_of_line was called when the iterator was processing the final blanks of the mode line, see display_mode_line. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 21:01 ` Eli Zaretskii @ 2019-10-13 22:27 ` Ergus 2019-10-14 8:26 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-10-13 22:27 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Mon, Oct 14, 2019 at 12:01:46AM +0300, Eli Zaretskii wrote: >> Date: Sun, 13 Oct 2019 21:38:36 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> (gdb) p it->sp >> $1 = 0 >> (gdb) p it->method >> $2 = GET_FROM_C_STRING > >If we are producing glyphs from a C string, then faces should not be >used at all, because C strings cannot have faces. > >So you should to condition the call to face_at_pos on something like > > it->s == NULL > Hi: This have fixed the issue, I understand now what was happening. Should I merge into master now? maybe you should close the related issues then right?. >because there can not be any face on any position of a C string. > >> (gdb) pgrowx it->glyph_row >> TEXT: 85 glyphs >> 0 0: CHAR[-] str=0x4fab1a8f[0] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 1 1: CHAR[U] str=0x4fab18f0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 2 2: CHAR[U] str=0x4fab18f0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 3 3: CHAR[U] str=0x4fab18f0[1] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 4 4: CHAR[:] str=0xf2787f0[0] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 5 5: CHAR[%] str=0x4faaee54[1] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 6 6: CHAR[%] str=0x4faaede4[1] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 7 7: CHAR[-] str=0x4fab1721[1] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 8 8: CHAR[-] str=0x4fa9d9a8[0] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 9 9: CHAR[F] str=0x4fa9d9a8[2] blev=0,btyp=L w=1 a+d=0+0 face=1 >> 10 10: CHAR[1] str=0x4fa9d9a8[2] blev=0,btyp=L w=1 a+d=0+0 face=1 > >This is a mode line, so it figures out: extend_face_to_end_of_line was >called when the iterator was processing the final blanks of the mode >line, see display_mode_line. > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 22:27 ` Ergus @ 2019-10-14 8:26 ` Eli Zaretskii 2019-10-20 22:20 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-10-14 8:26 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 14 Oct 2019 00:27:52 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > This have fixed the issue, I understand now what was happening. Should I > merge into master now? If there are no more outstanding issues, please go ahead and merge. > maybe you should close the related issues then right?. Which issues? If you are talking about bug reports on debbugs, feel free to close them once you merge the branch. Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-14 8:26 ` Eli Zaretskii @ 2019-10-20 22:20 ` Ergus 2019-10-21 6:38 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-10-20 22:20 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Mon, Oct 14, 2019 at 11:26:03AM +0300, Eli Zaretskii wrote: >> Date: Mon, 14 Oct 2019 00:27:52 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> This have fixed the issue, I understand now what was happening. Should I >> merge into master now? > >If there are no more outstanding issues, please go ahead and merge. > >> maybe you should close the related issues then right?. > >Which issues? If you are talking about bug reports on debbugs, feel >free to close them once you merge the branch. > >Thanks. Hi: I closed #36858, but I am not sure if the feature also fixes #23574? As Martin referred to it during the discussion. Does it? Or it was a more general issue not completed yet? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-20 22:20 ` Ergus @ 2019-10-21 6:38 ` Eli Zaretskii 0 siblings, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-10-21 6:38 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 21 Oct 2019 00:20:22 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > I closed #36858, but I am not sure if the feature also fixes #23574? As > Martin referred to it during the discussion. Does it? Or it was a more > general issue not completed yet? I think bug#23574 should also be closed. But if you want to be sure 110%, please ping the original submitter of the bug, asking him to try the latest master. Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 18:53 ` Eli Zaretskii 2019-10-13 19:38 ` Ergus @ 2019-10-13 19:41 ` Ergus 1 sibling, 0 replies; 183+ messages in thread From: Ergus @ 2019-10-13 19:41 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sun, Oct 13, 2019 at 09:53:13PM +0300, Eli Zaretskii wrote: >> Date: Sun, 13 Oct 2019 20:25:42 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >Then looking at the position that causes the error will probably tell >> >you what's wrong. (Is OBJECT passed to Fget_text_property a string? >> >if not, position of zero is invalid.) >> > >> >> Actually conditioning the call to face_at_pos to when IT_CHARPOS (*it) >> != 0 seems to fix the issue with magit... but maybe we are just hiding >> something under the carpet here. Can you imagine something more general >> than that just this condition? > >How did it happen that IT_CHARPOS(*it) is zero? If we are iterating >over a buffer, that cannot happen, because we begin from 1 and go >forward. > If you see the bt I sent before the problem is in display_mode_line. >Is it->sp zero or higher? If it's higher, then we are not iterating >over a buffer, but something else (a string, an image, or something >similar). What are the values of it->method and it->what? Can you >show the result of > > (gdb) pgrowx it->glyph_row > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-10-13 15:40 ` Ergus 2019-10-13 16:06 ` Eli Zaretskii @ 2019-10-13 16:11 ` Eli Zaretskii 1 sibling, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-10-13 16:11 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel I wrote: > Could it be that redisplay_window_0, or some function it calls, > signals an error, which is caught by internal_condition_case_1? What > happens if you put a breakpoint in signal_or_quit, does it get called > from redisplay_window or some other function called by > redisplay_windows? Actually, it is better to put a breakpoint in redisplay_window_error. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine @ 2019-08-27 16:01 Keith David Bershatsky 0 siblings, 0 replies; 183+ messages in thread From: Keith David Bershatsky @ 2019-08-27 16:01 UTC (permalink / raw) To: Ergus, Eli Zaretskii, Martin Rudalics; +Cc: Emacs Devel Inasmuch as Ergus has recently expressed a desire to work on face extensions, I thought it would be helpful to bring to everyone's attention a couple of recent threads where a user is attempting to workaround (using Lisp) a background face that gets extended when folding source code blocks in org-mode: https://www.reddit.com/r/emacs/comments/cw0499/prevent_folded_headings_from_bleeding_out/?ref=share&ref_source=link https://emacs.stackexchange.com/q/52324/2287 Thanks, Keith ^ permalink raw reply [flat|nested] 183+ messages in thread
* Question about display engine @ 2019-08-07 0:54 Ergus 2019-08-07 15:01 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-07 0:54 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Hi: Sorry to bother with this. Fixing the issue 36858 in text mode I found that the extend_face_to_end_of_line uses the same face for the last char in the line. This is useful to extend selection face the whole line, but this created a difference with gui emacs when the last face was underlined or overlined because in tui the underline is extended for the entire line. To fix this I need to create a new face to extend until the end of the line that has the same properties than it->face_id except that the underline and overline properties will be disabled. I can produce the desired effect doing: ```Lisp (defface my_new_face '((t :weight normal :slant normal :underline nil :overline nil :strike-through nil :box nil :inverse-video nil :stipple nil))) ``` ```C DEFSYM (my_new_face, "my-new-face"); it->face_id = merge_faces (it->w, my-new-face, 0, it->face_id) ``` But this seems very dirty. How can I produce the same effect in the right way? (I mean create a new face_id based on it->face_id but with :underline nil :overline nil... etc?) And only with C code. Any help, suggestion? Thanks in advance, Ergus ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-07 0:54 Ergus @ 2019-08-07 15:01 ` Eli Zaretskii 2019-08-07 15:32 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-07 15:01 UTC (permalink / raw) To: Ergus; +Cc: emacs-devel > Date: Wed, 7 Aug 2019 02:54:11 +0200 > From: Ergus <spacibba@aol.com> > Cc: emacs-devel@gnu.org > > Sorry to bother with this. Sorry for not answering sooner: I needed to find time to re-read the relevant code and recollect the consequences. > Fixing the issue 36858 in text mode I found that the > extend_face_to_end_of_line uses the same face for the last char in the > line. Yes. > This is useful to extend selection face the whole line, but this created > a difference with gui emacs when the last face was underlined or > overlined because in tui the underline is extended for the entire line. The issue is more general, and not limited to the underline attribute. See below. > To fix this I need to create a new face to extend until the end of the > line that has the same properties than it->face_id except that the > underline and overline properties will be disabled. Why only underline and overline? And why do you think you can reset these attributes at will in this case? Suppose someone defines the 'region' face to use underline -- we definitely cannot reset this attribute in that case, because then the region will appear non-contiguous, right? > I can produce the desired effect doing: > > ```Lisp > (defface my_new_face > '((t :weight normal :slant normal > :underline nil :overline nil :strike-through nil > :box nil :inverse-video nil :stipple nil))) > ``` > > ```C > DEFSYM (my_new_face, "my-new-face"); > > it->face_id = merge_faces (it->w, my-new-face, 0, it->face_id) > ``` > > But this seems very dirty. > > How can I produce the same effect in the right way? (I mean create a new > face_id based on it->face_id but with :underline nil :overline > nil... etc?) And only with C code. You need to call realize_face after copying the attributes of the default face and resetting some of the attributes to Qunspecified. But this is the mechanical part of the issue; I think the conceptual part is more problematic. First, we indeed behave inconsistently in GUI and TTY frames regarding faces that straddle the newline. On GUI frames, some attributes, such as colors and the box attribute, extend all the way to the window's edge; others, like underline, overline, and strike-through only affect the single glyph that stands for the newline (which the display engine adds so it will have a place to display the cursor). By contrast, on TTY frames, every attribute we support in text mode extends to the window's edge. Emacs behaved like that since v21. The question is: which of the 2 is the correct display, if there is a correct one? When trying to answer this question, please keep in mind two special use cases: the use case with the region, and the use case where the same attribute continues on the next screen line. Maybe there are other relevant use cases as well. I myself don't have a definitive answer. The TTY behavior makes more sense to me, but people frequently complain about it saying it's ugly, so I guess "makes sense" doesn't necessarily cut it. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-07 15:01 ` Eli Zaretskii @ 2019-08-07 15:32 ` Ergus 2019-08-07 15:45 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-07 15:32 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel On Wed, Aug 07, 2019 at 06:01:12PM +0300, Eli Zaretskii wrote: >> Date: Wed, 7 Aug 2019 02:54:11 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: emacs-devel@gnu.org >> >> Sorry to bother with this. > >Sorry for not answering sooner: I needed to find time to re-read the >relevant code and recollect the consequences. > >> Fixing the issue 36858 in text mode I found that the >> extend_face_to_end_of_line uses the same face for the last char in the >> line. > >Yes. > >> This is useful to extend selection face the whole line, but this created >> a difference with gui emacs when the last face was underlined or >> overlined because in tui the underline is extended for the entire line. > >The issue is more general, and not limited to the underline >attribute. See below. > >> To fix this I need to create a new face to extend until the end of the >> line that has the same properties than it->face_id except that the >> underline and overline properties will be disabled. > >Why only underline and overline? And why do you think you can reset >these attributes at will in this case? Suppose someone defines the >'region' face to use underline -- we definitely cannot reset this >attribute in that case, because then the region will appear >non-contiguous, right? > >> I can produce the desired effect doing: >> >> ```Lisp >> (defface my_new_face >> '((t :weight normal :slant normal >> :underline nil :overline nil :strike-through nil >> :box nil :inverse-video nil :stipple nil))) >> ``` >> >> ```C >> DEFSYM (my_new_face, "my-new-face"); >> >> it->face_id = merge_faces (it->w, my-new-face, 0, it->face_id) >> ``` >> >> But this seems very dirty. >> >> How can I produce the same effect in the right way? (I mean create a new >> face_id based on it->face_id but with :underline nil :overline >> nil... etc?) And only with C code. > >You need to call realize_face after copying the attributes of the >default face and resetting some of the attributes to Qunspecified. >But this is the mechanical part of the issue; I think the conceptual >part is more problematic. > >First, we indeed behave inconsistently in GUI and TTY frames regarding >faces that straddle the newline. On GUI frames, some attributes, such >as colors and the box attribute, extend all the way to the window's >edge; others, like underline, overline, and strike-through only affect >the single glyph that stands for the newline (which the display engine >adds so it will have a place to display the cursor). By contrast, on >TTY frames, every attribute we support in text mode extends to the >window's edge. > >Emacs behaved like that since v21. > >The question is: which of the 2 is the correct display, if there is a >correct one? When trying to answer this question, please keep in mind >two special use cases: the use case with the region, and the use case >where the same attribute continues on the next screen line. Maybe >there are other relevant use cases as well. > >I myself don't have a definitive answer. The TTY behavior makes more >sense to me, but people frequently complain about it saying it's ugly, >so I guess "makes sense" doesn't necessarily cut it. > Hi: I am not sure about what will be the community opinion; so I'll wait for some comments (and the usual complains) before implementing anything. Maybe it makes some sense to consider the region as a corner case here. So a possible solution is just to add a condition to reset the underline (and other attributes) when the last glyph was not in the active region. The actual TUI behavior is annoying in some modes; so maybe the best is to reproduce the gui behavior as it is now in TUI too. But: After thinking on that a little bit more since yesterday; maybe it is possible to add another basic face for the rest of the line. That face will be merged with the previous face as in the example code, so if it specifies :underline then merging should work as specified; else, it will just use the :underline from the latest glyph. So the user could potentially customize the desired behavior. The arguments will come about what the defaults should be, but at least we don't limit that. Does it makes sense? Best, Ergus ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-07 15:32 ` Ergus @ 2019-08-07 15:45 ` Eli Zaretskii 2019-08-07 15:57 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-07 15:45 UTC (permalink / raw) To: Ergus; +Cc: emacs-devel > Date: Wed, 7 Aug 2019 17:32:20 +0200 > From: Ergus <spacibba@aol.com> > Cc: emacs-devel@gnu.org > > After thinking on that a little bit more since yesterday; maybe it is > possible to add another basic face for the rest of the line. That face > will be merged with the previous face as in the example code, so if it > specifies :underline then merging should work as specified; else, it > will just use the :underline from the latest glyph. Such a face will not be a fixed face, it will have to be recomputed whenever the face of the text changes, right? E.g., if the face of the text specifies some color, you'd want this additional face to have the same colors, right? So it doesn't seem to be a face that can be customized in the usual sense. We could let the users specify face attributes they don't want to see in face extension, though. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-07 15:45 ` Eli Zaretskii @ 2019-08-07 15:57 ` Ergus 2019-08-07 16:12 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-07 15:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 1153 bytes --] On Wed, Aug 07, 2019 at 06:45:47PM +0300, Eli Zaretskii wrote: >> Date: Wed, 7 Aug 2019 17:32:20 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: emacs-devel@gnu.org >> >> After thinking on that a little bit more since yesterday; maybe it is >> possible to add another basic face for the rest of the line. That face >> will be merged with the previous face as in the example code, so if it >> specifies :underline then merging should work as specified; else, it >> will just use the :underline from the latest glyph. > >Such a face will not be a fixed face, it will have to be recomputed >whenever the face of the text changes, right? E.g., if the face of >the text specifies some color, you'd want this additional face to have >the same colors, right? > We don't use the face itself, just to merge with the previous glyph. >So it doesn't seem to be a face that can be customized in the usual >sense. We could let the users specify face attributes they don't want >to see in face extension, though. Please look the proposed patch. It may need some improvements, but at least the functional part is a decent solution for all the issues in my opinion. [-- Attachment #2: fix_36858.patch --] [-- Type: text/plain, Size: 8407 bytes --] diff --git a/lisp/faces.el b/lisp/faces.el index 5193c216d0..9c3eba0fff 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2510,7 +2510,7 @@ unwanted effects." ;; Definition stolen from display-line-numbers. (defface fill-column-indicator - '((t :inherit shadow :weight normal :slant normal + '((t :inherit extend-to-end-of-line :weight normal :slant normal :underline nil :overline nil :strike-through nil :box nil :inverse-video nil :stipple nil)) "Face for displaying fill column indicator. @@ -2694,12 +2694,20 @@ the same as `window-divider' face." :group 'basic-faces) (defface internal-border - '((t nil)) + '((t nil)) "Basic face for the internal border." :version "26.1" :group 'frames :group 'basic-faces) +(defface extend-to-end-of-line + '((t :weight normal :slant normal + :underline nil :overline nil :strike-through nil + :box nil :inverse-video nil :stipple nil)) + "Basic face to extend to end if line." + :version "27.1" + :group 'basic-faces) + (defface minibuffer-prompt '((((background dark)) :foreground "cyan") ;; Don't use blue because many users of the MS-DOS port customize diff --git a/src/dispextern.h b/src/dispextern.h index 4e947daa25..9a8bad6d08 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1780,6 +1780,7 @@ enum face_id WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID, INTERNAL_BORDER_FACE_ID, + EXTEND_TO_END_OF_LINE_FACE_ID, BASIC_FACE_ID_SENTINEL }; diff --git a/src/xdisp.c b/src/xdisp.c index 7338d2b7d4..738a6ca129 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -386,6 +386,7 @@ fill_column_indicator_column (struct it *it) { if (Vdisplay_fill_column_indicator && it->continuation_lines_width == 0 + && IT_CHARPOS (*it) < ZV && CHARACTERP (Vdisplay_fill_column_indicator_character)) { Lisp_Object col = (EQ (Vdisplay_fill_column_indicator_column, Qt) @@ -20468,6 +20469,9 @@ extend_face_to_end_of_line (struct it *it) it->face_id = FACE_FOR_CHAR (f, face, 0, -1, Qnil); } + const int extend_face_merged_id = + merge_faces (it->w, Qextend_to_end_of_line, 0, it->face_id); + #ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (f)) { @@ -20519,12 +20523,14 @@ extend_face_to_end_of_line (struct it *it) const int char_width = (font->average_width ? font->average_width : font->space_width); - int column_x; - - if (!INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) - && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) - && column_x >= it->current_x - && column_x <= it->last_visible_x) + int indicator_column_x; + + if (!INT_MULTIPLY_WRAPV (indicator_column, + char_width, &indicator_column_x) + && !INT_ADD_WRAPV (it->lnum_pixel_width, + indicator_column_x, &indicator_column_x) + && indicator_column_x >= it->current_x + && indicator_column_x <= it->last_visible_x) { const char saved_char = it->char_to_display; const struct text_pos saved_pos = it->position; @@ -20533,14 +20539,15 @@ extend_face_to_end_of_line (struct it *it) const bool saved_box_start = it->start_of_box_run_p; Lisp_Object save_object = it->object; - /* The stretch width needs to considet the latter + /* The stretch width needs to consider the latter added glyph. */ const int stretch_width - = column_x - it->current_x - char_width; + = indicator_column_x - it->current_x - char_width; memset (&it->position, 0, sizeof it->position); it->avoid_cursor_p = true; it->object = Qnil; + it->face_id = extend_face_merged_id; /* Only generate a stretch glyph if there is distance between current_x and and the indicator position. */ @@ -20548,6 +20555,7 @@ extend_face_to_end_of_line (struct it *it) { int stretch_ascent = (((it->ascent + it->descent) * FONT_BASE (font)) / FONT_HEIGHT (font)); + append_stretch_glyph (it, Qnil, stretch_width, it->ascent + it->descent, stretch_ascent); @@ -20555,24 +20563,29 @@ extend_face_to_end_of_line (struct it *it) /* Generate the glyph indicator only if append_space_for_newline didn't already. */ - if (it->current_x < column_x) + if (it->current_x < indicator_column_x) { + it->face_id + = merge_faces (it->w, Qextend_to_end_of_line, + 0, extend_face_merged_id); + it->char_to_display = XFIXNAT (Vdisplay_fill_column_indicator_character); - it->face_id - = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); PRODUCE_GLYPHS (it); - } - /* Restore the face after the indicator was generated. */ - it->face_id = saved_face_id; + it->face_id = extend_face_merged_id; + } /* If there is space after the indicator generate an extra empty glyph to restore the face. Issue was observed in X systems. */ - it->char_to_display = ' '; - PRODUCE_GLYPHS (it); + if (it->current_x < it->last_visible_x) { + it->char_to_display = ' '; + PRODUCE_GLYPHS (it); + } + + /* Restore the face after the indicator was generated. */ + it->face_id = saved_face_id; it->char_to_display = saved_char; it->position = saved_pos; @@ -20697,26 +20710,27 @@ extend_face_to_end_of_line (struct it *it) /* The last row's blank glyphs should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ + if (it->glyph_row->ends_at_zv_p) it->face_id = default_face->id; else - it->face_id = face->id; + it->face_id = extend_face_merged_id; /* Display fill-column indicator if needed. */ int indicator_column = fill_column_indicator_column (it); if (indicator_column >= 0 - && INT_ADD_WRAPV (it->lnum_pixel_width, indicator_column, + && INT_ADD_WRAPV (it->lnum_pixel_width, indicator_column, &indicator_column)) indicator_column = -1; do { int saved_face_id; - bool indicate = it->current_x == indicator_column; + const bool indicate = it->current_x == indicator_column; if (indicate) { saved_face_id = it->face_id; it->face_id - = merge_faces (it->w, Qfill_column_indicator, 0, saved_face_id); + = merge_faces (it->w, Qfill_column_indicator, 0, extend_face_merged_id); it->c = it->char_to_display = XFIXNAT (Vdisplay_fill_column_indicator_character); } diff --git a/src/xfaces.c b/src/xfaces.c index c3cae7e2a6..a0b0d9c6f8 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -4598,6 +4598,7 @@ lookup_basic_face (struct window *w, struct frame *f, int face_id) case WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID: name = Qwindow_divider_first_pixel; break; case WINDOW_DIVIDER_LAST_PIXEL_FACE_ID: name = Qwindow_divider_last_pixel; break; case INTERNAL_BORDER_FACE_ID: name = Qinternal_border; break; + case EXTEND_TO_END_OF_LINE_FACE_ID: name = Qextend_to_end_of_line; break; default: emacs_abort (); /* the caller is supposed to pass us a basic face id */ @@ -5293,6 +5294,7 @@ realize_basic_faces (struct frame *f) realize_named_face (f, Qwindow_divider_last_pixel, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); realize_named_face (f, Qinternal_border, INTERNAL_BORDER_FACE_ID); + realize_named_face (f, Qextend_to_end_of_line, EXTEND_TO_END_OF_LINE_FACE_ID); /* Reflect changes in the `menu' face in menu bars. */ if (FRAME_FACE_CACHE (f)->menu_face_changed_p) @@ -6592,6 +6594,7 @@ syms_of_xfaces (void) DEFSYM (Qwindow_divider_first_pixel, "window-divider-first-pixel"); DEFSYM (Qwindow_divider_last_pixel, "window-divider-last-pixel"); DEFSYM (Qinternal_border, "internal-border"); + DEFSYM (Qextend_to_end_of_line, "extend-to-end-of-line"); /* TTY color-related functions (defined in tty-colors.el). */ DEFSYM (Qtty_color_desc, "tty-color-desc"); ^ permalink raw reply related [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-07 15:57 ` Ergus @ 2019-08-07 16:12 ` Eli Zaretskii 2019-08-07 16:25 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-07 16:12 UTC (permalink / raw) To: Ergus; +Cc: emacs-devel > Date: Wed, 7 Aug 2019 17:57:38 +0200 > From: Ergus <spacibba@aol.com> > Cc: emacs-devel@gnu.org > > >Such a face will not be a fixed face, it will have to be recomputed > >whenever the face of the text changes, right? E.g., if the face of > >the text specifies some color, you'd want this additional face to have > >the same colors, right? > > > We don't use the face itself, just to merge with the previous glyph. > > >So it doesn't seem to be a face that can be customized in the usual > >sense. We could let the users specify face attributes they don't want > >to see in face extension, though. > > Please look the proposed patch. It may need some improvements, but at > least the functional part is a decent solution for all the issues in my > opinion. First, let's not mix this with the display-fill-column-indicator-mode, let's keep the changes for these two separate, OK? And second, I don't think I understand what we expect users to do with this face's customization. Suppose the user customizes this face to set the :underline attribute, will the effect be reasonable? I thought we wanted to let users determine which attributes will be _reset_, not _set_. But faces, as we use them normally, don't allow resetting attributes. And, of course, this leaves the more general problem I described in my message: what is the right behavior for extending the face that crosses a newline. (Note that the display engine in general doesn't know whether a face that doesn't end before a newline will or won't continue on the next screen line.) Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-07 16:12 ` Eli Zaretskii @ 2019-08-07 16:25 ` martin rudalics 2019-08-07 16:41 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-07 16:25 UTC (permalink / raw) To: Eli Zaretskii, Ergus; +Cc: emacs-devel > And, of course, this leaves the more general problem I described in my > message: what is the right behavior for extending the face that > crosses a newline. (Note that the display engine in general doesn't > know whether a face that doesn't end before a newline will or won't > continue on the next screen line.) Recalling your proposal (defcustom face-extend-to-window-edge t "Non-nil means extend face of last character on line to window edge. Certain face attributes, if present in the face of the last character of a line and different from those of the default face, cause the empty space following the end of text on the line to be drawn with those attributes, to give the empty space appearance similar to that of the preceding text. These attributes are those which affect the background of a face: `:background', `:stipple', `:box', `:underline', `:overline', and `:strike-through'. By default, if the face of a line's last character has any of these attributes, and the value is different from that of the default face, the empty space following the line's text will be drawn in the face of the last character. This variable allows fine-tuning which attributes trigger the face extension. The default value of t means any of the mentioned attributes will cause face extension. The value of nil means face extension is turned off. A value that is a list of attributes will extend the face only if any of the attributes from the list are present in the last character's face. Note that only attributes from the above list are meaningful in list values of this variable.") in the discussion of Bug#23574. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-07 16:25 ` martin rudalics @ 2019-08-07 16:41 ` Eli Zaretskii 2019-08-08 7:25 ` martin rudalics 2019-08-08 8:15 ` Ergus 0 siblings, 2 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-07 16:41 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Wed, 7 Aug 2019 18:25:37 +0200 > > > And, of course, this leaves the more general problem I described in my > > message: what is the right behavior for extending the face that > > crosses a newline. (Note that the display engine in general doesn't > > know whether a face that doesn't end before a newline will or won't > > continue on the next screen line.) > > Recalling your proposal > > (defcustom face-extend-to-window-edge t > "Non-nil means extend face of last character on line to window edge. Thanks for the reminder. > Certain face attributes, if present in the face of the last character > of a line and different from those of the default face, cause the > empty space following the end of text on the line to be drawn with > those attributes, to give the empty space appearance similar to that > of the preceding text. These attributes are those which affect the > background of a face: `:background', `:stipple', `:box', `:underline', > `:overline', and `:strike-through'. By default, if the face of a > line's last character has any of these attributes, and the value is > different from that of the default face, the empty space following the > line's text will be drawn in the face of the last character. This is inaccurate, I think: on GUI frames only :background and :box are extended all the way, the rest only "infect" the glyph we add for displaying the newline. > This variable allows fine-tuning which attributes trigger the face > extension. The default value of t means any of the mentioned > attributes will cause face extension. The value of nil means face > extension is turned off. A value that is a list of attributes will > extend the face only if any of the attributes from the list are > present in the last character's face. Note that only attributes from > the above list are meaningful in list values of this variable.") > > in the discussion of Bug#23574. And I think we need to consider the case of the region using one of the attributes that are not in the list. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-07 16:41 ` Eli Zaretskii @ 2019-08-08 7:25 ` martin rudalics 2019-08-08 8:38 ` Ergus 2019-08-08 8:15 ` Ergus 1 sibling, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-08 7:25 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel > And I think we need to consider the case of the region using one of > the attributes that are not in the list. I now think it would make more sense to add an 'extend-to-window-edge' attribute in the face definition itself. Also, when looking at what applications like Thunderbird or Firefox do, I nowhere see their "region faces" extend to the right edges of their "windows" in "normal text". Admittedly, these two applications do not highlight an empty space at the left edge of a window either and I'm fully aware of the fact that I'm comparing apples and oranges here. Still I think that our users should be given the possibility to customize their regions in a similar way as they do. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 7:25 ` martin rudalics @ 2019-08-08 8:38 ` Ergus 2019-08-08 8:45 ` martin rudalics ` (2 more replies) 0 siblings, 3 replies; 183+ messages in thread From: Ergus @ 2019-08-08 8:38 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Thu, Aug 08, 2019 at 09:25:45AM +0200, martin rudalics wrote: >> And I think we need to consider the case of the region using one of >> the attributes that are not in the list. > >I now think it would make more sense to add an 'extend-to-window-edge' >attribute in the face definition itself. I like that option as a concept, but it adds a new flag to a general struct like the face for something that only affects the region face now. But it is very general, so maybe could be useful in the future; but it worth to make the face even more complex?. BTW: Looking at the merge_face function could anyone please explain better what means: realized face and lface_id and please direct me to where is documented how emacs uses the faces internally; the functionalities available and specially the merge rules? >Also, when looking at what >applications like Thunderbird or Firefox do, I nowhere see their >"region faces" extend to the right edges of their "windows" in "normal >text". Admittedly, these two applications do not highlight an empty >space at the left edge of a window either and I'm fully aware of the >fact that I'm comparing apples and oranges here. Still I think that >our users should be given the possibility to customize their regions >in a similar way as they do. > >martin > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 8:38 ` Ergus @ 2019-08-08 8:45 ` martin rudalics 2019-08-08 9:29 ` Ergus 2019-08-08 17:37 ` Eli Zaretskii 2019-08-08 17:38 ` Eli Zaretskii 2 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-08 8:45 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel >> I now think it would make more sense to add an 'extend-to-window-edge' >> attribute in the face definition itself. > > I like that option as a concept, but it adds a new flag to a general > struct like the face for something that only affects the region face > now. But it is very general, so maybe could be useful in the future; but > it worth to make the face even more complex?. Here I'm not interested in the region at all. What bothers me are doc-strings and comments which I distinguish by setting their background color. And having that color extend to the end of the line is annoying so I had to invent some resource consuming workarounds. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 8:45 ` martin rudalics @ 2019-08-08 9:29 ` Ergus 2019-08-08 13:05 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-08 9:29 UTC (permalink / raw) To: emacs-devel, martin rudalics; +Cc: Eli Zaretskii On August 8, 2019 10:45:53 AM GMT+02:00, martin rudalics <rudalics@gmx.at> wrote: >>> I now think it would make more sense to add an >'extend-to-window-edge' > >> attribute in the face definition itself. > > > > I like that option as a concept, but it adds a new flag to a general > > struct like the face for something that only affects the region face >> now. But it is very general, so maybe could be useful in the future; >but > > it worth to make the face even more complex?. > >Here I'm not interested in the region at all. What bothers me are >doc-strings and comments which I distinguish by setting their >background color. And having that color extend to the end of the line >is annoying so I had to invent some resource consuming workarounds. > >martin Yes, that's exactly the point. The only face I see that needs to be extended so far is the region. If only the region is extended (assuming we won't stop extending that one too) you won't need your workarounds, extra settings, another flag in the face structure, or call extend face to end of line most of the time. -- Sent from my Android device with K-9 Mail. Please excuse my brevity. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 9:29 ` Ergus @ 2019-08-08 13:05 ` martin rudalics 2019-08-08 13:59 ` Eli Zaretskii 2019-08-08 14:50 ` Ergus 0 siblings, 2 replies; 183+ messages in thread From: martin rudalics @ 2019-08-08 13:05 UTC (permalink / raw) To: Ergus, emacs-devel; +Cc: Eli Zaretskii > Yes, that's exactly the point. The only face I see that needs to be > extended so far is the region. If only the region is extended > (assuming we won't stop extending that one too) you won't need your > workarounds, extra settings, another flag in the face structure, or > call extend face to end of line most of the time. I'm afraid things are not that simple. We have at least the secondary selection and 'hl-line-mode' to take care of. Moreover, there might be users who do prefer the current way of extending (and not extending) faces to window edges. And I have no idea whether image or rectangular regions require special treatment too. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 13:05 ` martin rudalics @ 2019-08-08 13:59 ` Eli Zaretskii 2019-08-08 16:43 ` Ergus 2019-08-09 8:59 ` martin rudalics 2019-08-08 14:50 ` Ergus 1 sibling, 2 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-08 13:59 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: Eli Zaretskii <eliz@gnu.org> > From: martin rudalics <rudalics@gmx.at> > Date: Thu, 8 Aug 2019 15:05:37 +0200 > > > Yes, that's exactly the point. The only face I see that needs to be > > extended so far is the region. If only the region is extended > > (assuming we won't stop extending that one too) you won't need your > > workarounds, extra settings, another flag in the face structure, or > > call extend face to end of line most of the time. > > I'm afraid things are not that simple. We have at least the secondary > selection and 'hl-line-mode' to take care of. Indeed, nothing is ever as simple in the display code, due to the sheer amount of different use cases. I think at least one other face attribute that's special in this regard is :box, in particular (but not only) because extend_face_to_end_of_line is called from the function which redisplays the mode line and the header line. > Moreover, there might be users who do prefer the current way of > extending (and not extending) faces to window edges. And I have no > idea whether image or rectangular regions require special treatment > too. Yes, I think we will have to provide some backward compatibility shims for these and other use cases. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 13:59 ` Eli Zaretskii @ 2019-08-08 16:43 ` Ergus 2019-08-08 17:50 ` Eli Zaretskii ` (2 more replies) 2019-08-09 8:59 ` martin rudalics 1 sibling, 3 replies; 183+ messages in thread From: Ergus @ 2019-08-08 16:43 UTC (permalink / raw) To: Eli Zaretskii; +Cc: martin rudalics, emacs-devel On Thu, Aug 08, 2019 at 04:59:54PM +0300, Eli Zaretskii wrote: >> Cc: Eli Zaretskii <eliz@gnu.org> >> From: martin rudalics <rudalics@gmx.at> >> Date: Thu, 8 Aug 2019 15:05:37 +0200 >> >> > Yes, that's exactly the point. The only face I see that needs to be >> > extended so far is the region. If only the region is extended >> > (assuming we won't stop extending that one too) you won't need your >> > workarounds, extra settings, another flag in the face structure, or >> > call extend face to end of line most of the time. >> >> I'm afraid things are not that simple. We have at least the secondary >> selection and 'hl-line-mode' to take care of. > >Indeed, nothing is ever as simple in the display code, due to the >sheer amount of different use cases. I think at least one other face >attribute that's special in this regard is :box, in particular (but >not only) because extend_face_to_end_of_line is called from the >function which redisplays the mode line and the header line. > Yes I have seen :p. That's why I will vote for simplicity+efficiency over more complex customization that 99% of the users won't need/know/use. I only want a uniform behavior between gui and tui. Because bigger changes I have understand that are close to impossible. >> Moreover, there might be users who do prefer the current way of >> extending (and not extending) faces to window edges. And I have no >> idea whether image or rectangular regions require special treatment >> too. > >Yes, I think we will have to provide some backward compatibility shims >for these and other use cases. > So finally what's the agreement about this? Does Eli (or anyone) have the time to implement it?? (else I can try with some hints of course). Can we add maybe a deadline to decide? I'm just wondering that this can be forgotten like the discussion in Bug#23574 if nobody starts working on it. When and who decides/approves the changes to do? I vote for: Reproduce in TUI the gui behavior as is now by default but: 1) With a not-extend-by-default policy 2.0) With some condition checks to extend the mentioned exceptions (secondary, region, hl_line_mode etc) maybe this last can be set in a customizable variable as there will be relatively few elements. xor 2.1) Add the "extensible" flag to the face. 3) Add an extra face to extend (like in my previous code) that needs to be merged with the last face in the line conditionally and can be used in case the user wants extend but removing the underline and keeping the background color (for example). This seems to be the most general solution in my opinion. I am specially concerned about this because org-mode behavior in terminal affects many users. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 16:43 ` Ergus @ 2019-08-08 17:50 ` Eli Zaretskii 2019-08-08 22:37 ` Ergus 2019-08-09 8:59 ` martin rudalics 2019-08-10 11:42 ` Eli Zaretskii 2 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-08 17:50 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Thu, 8 Aug 2019 18:43:19 +0200 > From: Ergus <spacibba@aol.com> > Cc: martin rudalics <rudalics@gmx.at>, emacs-devel@gnu.org > > So finally what's the agreement about this? Does Eli (or anyone) have > the time to implement it?? (else I can try with some hints of > course). Can we add maybe a deadline to decide? I'm just wondering that > this can be forgotten like the discussion in Bug#23574 if nobody starts > working on it. We were talking about it for only a single day. We should let others chime in, so let's wait for a few days. > I am specially concerned about this because org-mode behavior in > terminal affects many users. How is Org mode relevant to this issue? I think this is the first time Org mode is mentioned in this context. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 17:50 ` Eli Zaretskii @ 2019-08-08 22:37 ` Ergus 2019-08-09 6:28 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-08 22:37 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Thu, Aug 08, 2019 at 08:50:38PM +0300, Eli Zaretskii wrote: >> Date: Thu, 8 Aug 2019 18:43:19 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: martin rudalics <rudalics@gmx.at>, emacs-devel@gnu.org >> >> So finally what's the agreement about this? Does Eli (or anyone) have >> the time to implement it?? (else I can try with some hints of >> course). Can we add maybe a deadline to decide? I'm just wondering that >> this can be forgotten like the discussion in Bug#23574 if nobody starts >> working on it. > >We were talking about it for only a single day. We should let others >chime in, so let's wait for a few days. > >> I am specially concerned about this because org-mode behavior in >> terminal affects many users. > >How is Org mode relevant to this issue? I think this is the first >time Org mode is mentioned in this context. > In org-mode, many faces by default are underlined to indicate a section limit or just to highlight a section's header (I just started to use org-mode). So inserting the dfci functionality will expose the issue with this underlines too much. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 22:37 ` Ergus @ 2019-08-09 6:28 ` Eli Zaretskii 2019-08-09 9:08 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-09 6:28 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Fri, 9 Aug 2019 00:37:51 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >How is Org mode relevant to this issue? I think this is the first > >time Org mode is mentioned in this context. > > > In org-mode, many faces by default are underlined to indicate a section > limit or just to highlight a section's header (I just started to use > org-mode). So inserting the dfci functionality will expose the issue > with this underlines too much. I expect Org mode to underline only the headers, excluding the following newline, in which case the issue we are discussing shouldn't matter. Isn't this the case? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-09 6:28 ` Eli Zaretskii @ 2019-08-09 9:08 ` Ergus 2019-08-09 9:40 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-09 9:08 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Fri, Aug 09, 2019 at 09:28:51AM +0300, Eli Zaretskii wrote: >> Date: Fri, 9 Aug 2019 00:37:51 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >How is Org mode relevant to this issue? I think this is the first >> >time Org mode is mentioned in this context. >> > >> In org-mode, many faces by default are underlined to indicate a section >> limit or just to highlight a section's header (I just started to use >> org-mode). So inserting the dfci functionality will expose the issue >> with this underlines too much. > >I expect Org mode to underline only the headers, excluding the >following newline, in which case the issue we are discussing shouldn't >matter. Isn't this the case? No. In gui it is if no dfci mode is enabled. But in tui the underline extends until the end of the line always. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-09 9:08 ` Ergus @ 2019-08-09 9:40 ` Eli Zaretskii 2019-08-09 11:31 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-09 9:40 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Fri, 9 Aug 2019 11:08:25 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >> In org-mode, many faces by default are underlined to indicate a section > >> limit or just to highlight a section's header (I just started to use > >> org-mode). So inserting the dfci functionality will expose the issue > >> with this underlines too much. > > > >I expect Org mode to underline only the headers, excluding the > >following newline, in which case the issue we are discussing shouldn't > >matter. Isn't this the case? > > No. > > In gui it is if no dfci mode is enabled. > > But in tui the underline extends until the end of the line always. Sorry, I don't understand. It sounds like you are answering not the question I asked, but some other question. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-09 9:40 ` Eli Zaretskii @ 2019-08-09 11:31 ` Ergus 2019-08-09 14:04 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-09 11:31 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Fri, Aug 09, 2019 at 12:40:19PM +0300, Eli Zaretskii wrote: >> Date: Fri, 9 Aug 2019 11:08:25 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >> In org-mode, many faces by default are underlined to indicate a section >> >> limit or just to highlight a section's header (I just started to use >> >> org-mode). So inserting the dfci functionality will expose the issue >> >> with this underlines too much. >> > >> >I expect Org mode to underline only the headers, excluding the >> >following newline, in which case the issue we are discussing shouldn't >> >matter. Isn't this the case? >> >> No. >> >> In gui it is if no dfci mode is enabled. >> >> But in tui the underline extends until the end of the line always. > >Sorry, I don't understand. It sounds like you are answering not the >question I asked, but some other question. > Hi: The dfci mode exposes the issue 36858 in org-mode because: Org mode underlines only the headers in gui if no dfci mode is enabled, else the underline is extended until the indicator+1 character. But in tui the underline extends until the end of the line always, so the indicator looks pretty bad. That's what started this thread actually. The incoherence between both interfaces. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-09 11:31 ` Ergus @ 2019-08-09 14:04 ` Eli Zaretskii 2019-08-09 15:09 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-09 14:04 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Fri, 9 Aug 2019 13:31:34 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > The dfci mode exposes the issue 36858 in org-mode because: > > Org mode underlines only the headers in gui if no dfci mode is > enabled, else the underline is extended until the indicator+1 character. > > But in tui the underline extends until the end of the line always, so > the indicator looks pretty bad. That's what started this thread > actually. The incoherence between both interfaces. But this is unrelated to the issue of extending a face that straddles a newline, right? The issue being discussed in this thread is about faces that cover the newline; those cases that don't cover the newline are simply bugs in display-fill-column-indicator-mode, and should be fixed regardless of what we are talking here. It is possible that some solutions for the issue we are discussing here would also fix bug#36858 as side effect, but we should not delay solving that bug until the issue in this thread is resolved, because this issue is much more general and has much wider implications. So it might be that we decide not to change the more general behavior, or change it in a way that doesn't solve bug#36858. Or am I missing something? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-09 14:04 ` Eli Zaretskii @ 2019-08-09 15:09 ` Ergus 0 siblings, 0 replies; 183+ messages in thread From: Ergus @ 2019-08-09 15:09 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Fri, Aug 09, 2019 at 05:04:14PM +0300, Eli Zaretskii wrote: >> Date: Fri, 9 Aug 2019 13:31:34 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> The dfci mode exposes the issue 36858 in org-mode because: >> >> Org mode underlines only the headers in gui if no dfci mode is >> enabled, else the underline is extended until the indicator+1 character. >> >> But in tui the underline extends until the end of the line always, so >> the indicator looks pretty bad. That's what started this thread >> actually. The incoherence between both interfaces. > >But this is unrelated to the issue of extending a face that straddles >a newline, right? The issue being discussed in this thread is about >faces that cover the newline; those cases that don't cover the newline >are simply bugs in display-fill-column-indicator-mode, and should be >fixed regardless of what we are talking here. > >It is possible that some solutions for the issue we are discussing >here would also fix bug#36858 as side effect, but we should not delay >solving that bug until the issue in this thread is resolved, because >this issue is much more general and has much wider implications. So >it might be that we decide not to change the more general behavior, or >change it in a way that doesn't solve bug#36858. > >Or am I missing something? > Hi Eli: The problem is the incoherence, so the solution will be very different depending of If we keep the tui behavior then there will be needed a design choice about what to do with the indicator, if we keep the GUI I have already a fix patch for that. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 16:43 ` Ergus 2019-08-08 17:50 ` Eli Zaretskii @ 2019-08-09 8:59 ` martin rudalics 2019-08-09 9:31 ` Ergus 2019-08-09 9:38 ` Ergus 2019-08-10 11:42 ` Eli Zaretskii 2 siblings, 2 replies; 183+ messages in thread From: martin rudalics @ 2019-08-09 8:59 UTC (permalink / raw) To: Ergus, Eli Zaretskii; +Cc: emacs-devel > I only want a uniform behavior between gui and tui. Because bigger > changes I have understand that are close to impossible. Such uniform behavior should be a major goal. > Reproduce in TUI the gui behavior as is now by default but: > > 1) With a not-extend-by-default policy I'm not sure what you mean here: not-extend-by-default in TUI only or not-extend-by-default everywhere? > 3) Add an extra face to extend (like in my previous code) that needs to > be merged with the last face in the line conditionally and can be used > in case the user wants extend but removing the underline and keeping > the background color (for example). I suppose this extra face would be suppressed for the region or for tooltips. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-09 8:59 ` martin rudalics @ 2019-08-09 9:31 ` Ergus 2019-08-09 9:38 ` Ergus 1 sibling, 0 replies; 183+ messages in thread From: Ergus @ 2019-08-09 9:31 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Fri, Aug 09, 2019 at 10:59:47AM +0200, martin rudalics wrote: >> I only want a uniform behavior between gui and tui. Because bigger >> changes I have understand that are close to impossible. > >Such uniform behavior should be a major goal. > >> Reproduce in TUI the gui behavior as is now by default but: >> >> 1) With a not-extend-by-default policy > >I'm not sure what you mean here: not-extend-by-default in TUI only or >not-extend-by-default everywhere? > not-extend-by-default everywhere except in some conditions. Opposite to the actual policy which is to extend always. The behavior must be the same in both cases from the user point of view. That's my main concern on this; I will actually be fine enough with any decision that unifies behaviors. >> 3) Add an extra face to extend (like in my previous code) that needs to >> be merged with the last face in the line conditionally and can be used >> in case the user wants extend but removing the underline and keeping >> the background color (for example). > >I suppose this extra face would be suppressed for the region or >for tooltips. > Yes, the merge step needs to be suppressed in this and many other scenarios. >martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-09 8:59 ` martin rudalics 2019-08-09 9:31 ` Ergus @ 2019-08-09 9:38 ` Ergus 1 sibling, 0 replies; 183+ messages in thread From: Ergus @ 2019-08-09 9:38 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Fri, Aug 09, 2019 at 10:59:47AM +0200, martin rudalics wrote: >> I only want a uniform behavior between gui and tui. Because bigger >> changes I have understand that are close to impossible. > >Such uniform behavior should be a major goal. > >> Reproduce in TUI the gui behavior as is now by default but: >> >> 1) With a not-extend-by-default policy > >I'm not sure what you mean here: not-extend-by-default in TUI only or >not-extend-by-default everywhere? > >> 3) Add an extra face to extend (like in my previous code) that needs to >> be merged with the last face in the line conditionally and can be used >> in case the user wants extend but removing the underline and keeping >> the background color (for example). > >I suppose this extra face would be suppressed for the region or >for tooltips. > tooltips yes, not needed for the region. Actually the region is it's main use case to enable a simple customization when the user wants to extend only the color but not underlined. (To have an idea about this extra face give a look how I use it in my initial row patch.) >martin > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 16:43 ` Ergus 2019-08-08 17:50 ` Eli Zaretskii 2019-08-09 8:59 ` martin rudalics @ 2019-08-10 11:42 ` Eli Zaretskii 2019-08-11 8:14 ` martin rudalics 2 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-10 11:42 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Thu, 8 Aug 2019 18:43:19 +0200 > From: Ergus <spacibba@aol.com> > Cc: martin rudalics <rudalics@gmx.at>, emacs-devel@gnu.org > > >Indeed, nothing is ever as simple in the display code, due to the > >sheer amount of different use cases. I think at least one other face > >attribute that's special in this regard is :box, in particular (but > >not only) because extend_face_to_end_of_line is called from the > >function which redisplays the mode line and the header line. > > > Yes I have seen :p. That's why I will vote for simplicity+efficiency > over more complex customization that 99% of the users won't > need/know/use. We cannot take the simplicity+efficiency escape if it will cause inconsistent behavior in valid use cases. > I only want a uniform behavior between gui and tui. Because bigger > changes I have understand that are close to impossible. Making the behavior of TTY and GUI frames consistent should be easy once we decide which one we want to keep, provided we also decide not to extend the background color on GUI (and TTY) frames. But if we decide to keep the TTY behavior, it will make GUI display slightly less efficient, especially in wide windows. > I vote for: > > Reproduce in TUI the gui behavior as is now by default but: > > 1) With a not-extend-by-default policy Including non-extension of background color? Because if you still want to extend the color, I don't see how to make TTY and GUI consistent, at least not easily. > 2.0) With some condition checks to extend the mentioned exceptions > (secondary, region, hl_line_mode etc) maybe this last can be set in a > customizable variable as there will be relatively few elements. > > xor > > 2.1) Add the "extensible" flag to the face. I think both of these possibilities aren't workable due to face merging. > 3) Add an extra face to extend (like in my previous code) that needs to > be merged with the last face in the line conditionally and can be used > in case the user wants extend but removing the underline and keeping > the background color (for example). This can only work if we assume users will want the same attribute be extended or not irrespective of the face. Such an assumption is not necessarily valid: users could want the hl-line face, for example, be always extended, regardless of its attributes, but would like at the same time not see other faces' :underline attribute extended. IOW, such a solution (and similar ones proposed here) look like kludgey workarounds, something that IMO is not really appropriate for a major feature such as faces. > I am specially concerned about this because org-mode behavior in > terminal affects many users. We could claim this to be a bug in Org. No? Why does Org insist on covering the newline with the face? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-10 11:42 ` Eli Zaretskii @ 2019-08-11 8:14 ` martin rudalics 0 siblings, 0 replies; 183+ messages in thread From: martin rudalics @ 2019-08-11 8:14 UTC (permalink / raw) To: Eli Zaretskii, Ergus; +Cc: emacs-devel > This can only work if we assume users will want the same attribute be > extended or not irrespective of the face. Such an assumption is not > necessarily valid: users could want the hl-line face, for example, be > always extended, regardless of its attributes, but would like at the > same time not see other faces' :underline attribute extended. Reiterating what I said elsewhere (and hoping not to bore anyone with my ideas): With the face-based approach the user would have to set background, underline and extend for the highlight face to get that behavior. With the attributes-based approach, a user would have to include highlight both in 'extend-background' and 'extend-underline'. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 13:59 ` Eli Zaretskii 2019-08-08 16:43 ` Ergus @ 2019-08-09 8:59 ` martin rudalics 1 sibling, 0 replies; 183+ messages in thread From: martin rudalics @ 2019-08-09 8:59 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel > Indeed, nothing is ever as simple in the display code, due to the > sheer amount of different use cases. I think at least one other face > attribute that's special in this regard is :box, in particular (but > not only) because extend_face_to_end_of_line is called from the > function which redisplays the mode line and the header line. Newlines within boxes are a pain. Ideally, the entire text should be enclosed within one single box. Which obviously fails when the text does not form a rectangular region on screen. This is also evident with buttons - you cannot draw a button with multiple lines of text. As for the mode-/header-line or tooltip faces we'd probably have these always extend to the end of line, overriding any extension property specified for the underlying face. There's also the case of remapped backgrounds that IIRC cannot extend to the bottom edge of a window - they stop with the last text line displayed (I have to look into this matter again to say more). martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 13:05 ` martin rudalics 2019-08-08 13:59 ` Eli Zaretskii @ 2019-08-08 14:50 ` Ergus 2019-08-09 8:59 ` martin rudalics 1 sibling, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-08 14:50 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Thu, Aug 08, 2019 at 03:05:37PM +0200, martin rudalics wrote: >> Yes, that's exactly the point. The only face I see that needs to be >> extended so far is the region. If only the region is extended >> (assuming we won't stop extending that one too) you won't need your >> workarounds, extra settings, another flag in the face structure, or >> call extend face to end of line most of the time. > >I'm afraid things are not that simple. We have at least the secondary >selection and 'hl-line-mode' to take care of. Moreover, there might >be users who do prefer the current way of extending (and not >extending) faces to window edges. And I have no idea whether image or >rectangular regions require special treatment too. > >martin > You are right, I ignored those use cases, but I still don't think that the faces are the right place to flag that. The line extension maybe needs to be decided based on another text property. Maybe there are already some conditions we can check dynamically. Because adding a flag is a bit error prone when there are already some conditions. There is also the case when the face to use comes from FACE_FOR_CHAR or another is merged over that. Or when there is a highlight inside the region at the end of the line text... That, in the display engine, I am not clear yet how are handled. About the user preferences I think it needs to be accepted the Eli's choice (I will favor the uniformity+simplicity over over-specification, but I am not very "emacsy" in that point). Because we won't make happy everyone in any case. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 14:50 ` Ergus @ 2019-08-09 8:59 ` martin rudalics 2019-08-10 11:30 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-09 8:59 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel > You are right, I ignored those use cases, but I still don't think that > the faces are the right place to flag that. The line extension maybe > needs to be decided based on another text property. Maybe there are > already some conditions we can check dynamically. Because adding a flag > is a bit error prone when there are already some conditions. > > There is also the case when the face to use comes from FACE_FOR_CHAR or > another is merged over that. Or when there is a highlight inside the > region at the end of the line text... That, in the display engine, I am > not clear yet how are handled. OTOH, the display engine could simply delegate some design decisions to the face specification apparatus and attribute any faults to the latter. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-09 8:59 ` martin rudalics @ 2019-08-10 11:30 ` Eli Zaretskii 2019-08-11 8:14 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-10 11:30 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Fri, 9 Aug 2019 10:59:33 +0200 > > > You are right, I ignored those use cases, but I still don't think that > > the faces are the right place to flag that. The line extension maybe > > needs to be decided based on another text property. Maybe there are > > already some conditions we can check dynamically. Because adding a flag > > is a bit error prone when there are already some conditions. > > > > There is also the case when the face to use comes from FACE_FOR_CHAR or > > another is merged over that. Or when there is a highlight inside the > > region at the end of the line text... That, in the display engine, I am > > not clear yet how are handled. > > OTOH, the display engine could simply delegate some design decisions > to the face specification apparatus and attribute any faults to the > latter. I don't think this is workable, because of face merging. The actual face used to display the last character on a screen line can (and frequently does) come from merging several faces, and there's no meaningful answer to the question: which face did this attribute come from? For a face merged from 2 or more faces defined via defface, how do you tell whether or not to extend it? Thus, such delegation can only yield inconsistent behavior and more bug reports. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-10 11:30 ` Eli Zaretskii @ 2019-08-11 8:14 ` martin rudalics 2019-08-11 14:13 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-11 8:14 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel >> OTOH, the display engine could simply delegate some design decisions >> to the face specification apparatus and attribute any faults to the >> latter. > > I don't think this is workable, because of face merging. The actual > face used to display the last character on a screen line can (and > frequently does) come from merging several faces, and there's no > meaningful answer to the question: which face did this attribute come > from? Answering this question should not be the task of a (face agnostic) display engine. The face merging algorithm would have to decide whether the :extend attribute of the winning face should cause an extension of any attribute specified by that face. Which means that if the region is specified as both underlining and background, _both_ would extend if the extend attribute of the region face is set. It's the user's responsibility to either not set underline or not request extension of the region if such behavior is unwanted. > For a face merged from 2 or more faces defined via defface, how > do you tell whether or not to extend it? Thus, such delegation can > only yield inconsistent behavior and more bug reports. But there's only one face that decides whether and how the background shall be set and there's only face that decides that for underlining. Those faces' :extend attribute would specify how to extend the background and how to extend the underline. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-11 8:14 ` martin rudalics @ 2019-08-11 14:13 ` Eli Zaretskii 2019-08-12 8:59 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-11 14:13 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sun, 11 Aug 2019 10:14:33 +0200 > > > I don't think this is workable, because of face merging. The actual > > face used to display the last character on a screen line can (and > > frequently does) come from merging several faces, and there's no > > meaningful answer to the question: which face did this attribute come > > from? > > Answering this question should not be the task of a (face agnostic) > display engine. The face merging algorithm would have to decide > whether the :extend attribute of the winning face should cause an > extension of any attribute specified by that face. What is the "winning face" in this context? > > For a face merged from 2 or more faces defined via defface, how > > do you tell whether or not to extend it? Thus, such delegation can > > only yield inconsistent behavior and more bug reports. > > But there's only one face that decides whether and how the background > shall be set and there's only face that decides that for underlining. Not necessarily true: two or more faces could specify the same value of a particular attribute, including background and underlining. The :extend attribute could be different in some of these faces. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-11 14:13 ` Eli Zaretskii @ 2019-08-12 8:59 ` martin rudalics 2019-08-12 15:29 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-12 8:59 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel >> Answering this question should not be the task of a (face agnostic) >> display engine. The face merging algorithm would have to decide >> whether the :extend attribute of the winning face should cause an >> extension of any attribute specified by that face. > > What is the "winning face" in this context? IIUC the last one found by face_at_buffer_position that explicitly specified a value for the attribute in question. That is, the face whose attribute is actually used by the display engine. > Not necessarily true: two or more faces could specify the same value > of a particular attribute, including background and underlining. The > :extend attribute could be different in some of these faces. Suppose the iterator is at a newline character within some highlighted text within the region and wants to know the :background attribute at that position. With a face-based solution, face_at_buffer_position will have looked for a :background value provided by the default face, the highlight face and the region face, in this order. The value of the :extend attribute provided by the last face found that way is passed (in some extend_background variable I presume) to the display engine so the latter can determine whether the background shall be extended to the window edge or not. With an attribute-based solution, face_at_buffer_position will have provided an appropriate value when the last face "found that way" is a member of the 'extend-background' Lisp variable. A similar approach would be used to decide whether the rest of the line should be underlined, overlined, boxed, appear in inverse-video or whatever someone considers important (I suppose that none of these should ever extend). As stated earlier, the face-based solution will intuitively not DTRT when we allow underline to extend and a user sets, for example, all :underline, :background and :extend for the region face. In that case, both background and underline of the region will extend. With an attribute-based solution, a user would just have added 'region' to the 'extend-background' variable and this "problem" would be avoided. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-12 8:59 ` martin rudalics @ 2019-08-12 15:29 ` Eli Zaretskii 2019-08-12 22:18 ` Stefan Monnier 2019-08-13 8:17 ` martin rudalics 0 siblings, 2 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-12 15:29 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Mon, 12 Aug 2019 10:59:52 +0200 > > >> Answering this question should not be the task of a (face agnostic) > >> display engine. The face merging algorithm would have to decide > >> whether the :extend attribute of the winning face should cause an > >> extension of any attribute specified by that face. > > > > What is the "winning face" in this context? > > IIUC the last one found by face_at_buffer_position that explicitly > specified a value for the attribute in question. That is, the face > whose attribute is actually used by the display engine. Nitpicking: the display engine has no idea whose attributes it is using, see below. > > Not necessarily true: two or more faces could specify the same value > > of a particular attribute, including background and underlining. The > > :extend attribute could be different in some of these faces. > > Suppose the iterator is at a newline character within some highlighted > text within the region and wants to know the :background attribute at > that position. > > With a face-based solution, face_at_buffer_position will have looked > for a :background value provided by the default face, the highlight > face and the region face, in this order. The value of the :extend > attribute provided by the last face found that way is passed (in some > extend_background variable I presume) to the display engine so the > latter can determine whether the background shall be extended to the > window edge or not. If two or more faces of those merged specify :underline, and only one of them has a non-nil :extend, will extending the underline do what the users expect? (And shouldn't we simply disregard entirely a face whose :extend attribute is nil? What can such a face possibly contribute in this case?) > With an attribute-based solution, face_at_buffer_position will have > provided an appropriate value when the last face "found that way" is a > member of the 'extend-background' Lisp variable. > > A similar approach would be used to decide whether the rest of the > line should be underlined, overlined, boxed, appear in inverse-video > or whatever someone considers important (I suppose that none of these > should ever extend). You seem to assume that the iterator examines faces at every buffer position it passes, and in particular on the newline at EOL. But that's not what happens, because examining and merging faces is expensive, so Emacs avoids doing that unless necessary. We only examine faces where they change, and use next-single-property-change to find the next position where we should again examine the faces. In addition, face_at_buffer_position doesn't look for face attributes one by one. Instead, it finds all the source of the 'face' property that are in effect at the given position -- the default face, the face from text properties, and from all the overlays at that position -- and merges these attributes into a single attribute vector. Then it looks up a realized face with identical attributes, or realizes a new face if no such face exists. Thereafter, the iterator just uses that face until the next checkpoint. IOW, face_at_buffer_position returns an ID of a realized (i.e. fully specified) face created by merging several relevant sources of face information, and that realized face has no references to the names of the individual faces from which it was created, nor any memory of which non-unspecified attributes came from which face source. So to implement something like above, we will have to: . force face merging when we get to a newline (btw, what about continuation lines in this context? do we apply the extension logic to them as well?) . modify face_at_buffer_position and its subroutines to behave specially when called on a newline, and decide whether to merge or not merge attributes based on whatever data structures describe the preferences for extending those attributes; this would go at least two levels below face_at_buffer_position . do something similar in face_at_string_position, for display and overlay strings with embedded newlines Sounds like fun project. Volunteers are welcome. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-12 15:29 ` Eli Zaretskii @ 2019-08-12 22:18 ` Stefan Monnier 2019-08-13 8:17 ` martin rudalics 2019-08-13 8:17 ` martin rudalics 1 sibling, 1 reply; 183+ messages in thread From: Stefan Monnier @ 2019-08-12 22:18 UTC (permalink / raw) To: Eli Zaretskii; +Cc: martin rudalics, spacibba, emacs-devel >> IIUC the last one found by face_at_buffer_position that explicitly >> specified a value for the attribute in question. That is, the face >> whose attribute is actually used by the display engine. > > Nitpicking: the display engine has no idea whose attributes it is > using, see below. I don't know enough of the display engine to say something intelligent, I'm afraid, but my naive understanding is that the way "it should" work is that the face used on the "rest of the line" should be computed by merging the various faces that apply to the corresponding LF character but where the new `extend-to-end-of-line` property is obeyed (i.e. a face is skipped if that property is nil). IOW the extend-to-end-of-line property is applied *during* merging rather than after it. Most likely this can't be mapped to the way things are done, tho. Stefan ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-12 22:18 ` Stefan Monnier @ 2019-08-13 8:17 ` martin rudalics 2019-08-13 15:32 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-13 8:17 UTC (permalink / raw) To: Stefan Monnier, Eli Zaretskii; +Cc: spacibba, emacs-devel > ... the face used on the "rest of the line" should be computed by > merging the various faces that apply to the corresponding LF character > but where the new `extend-to-end-of-line` property is obeyed > (i.e. a face is skipped if that property is nil). IOW the > extend-to-end-of-line property is applied *during* merging rather than > after it. That's the idea. The display engine would then simply have to look at a single bit to tell whether to extend a specific attribute to the end of the line or not. > Most likely this can't be mapped to the way things are done, tho. Most likely the solution will be disappointingly simple, once Eli found it. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-13 8:17 ` martin rudalics @ 2019-08-13 15:32 ` Eli Zaretskii 2019-08-13 22:33 ` Stefan Monnier 2019-08-14 8:58 ` martin rudalics 0 siblings, 2 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-13 15:32 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, monnier, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Tue, 13 Aug 2019 10:17:52 +0200 > > > ... the face used on the "rest of the line" should be computed by > > merging the various faces that apply to the corresponding LF character > > but where the new `extend-to-end-of-line` property is obeyed > > (i.e. a face is skipped if that property is nil). IOW the > > extend-to-end-of-line property is applied *during* merging rather than > > after it. > > That's the idea. Are you sure? It sounds like Stefan was saying the same thing I was saying: that the decision whether to use or not to use an attribute is made when we merge the faces, not when we apply the face attributes to produce the display on the glass. Or maybe it's me who misunderstood what Stefan meant... ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-13 15:32 ` Eli Zaretskii @ 2019-08-13 22:33 ` Stefan Monnier 2019-08-14 8:58 ` martin rudalics 1 sibling, 0 replies; 183+ messages in thread From: Stefan Monnier @ 2019-08-13 22:33 UTC (permalink / raw) To: Eli Zaretskii; +Cc: martin rudalics, spacibba, emacs-devel > Are you sure? It sounds like Stefan was saying the same thing I was > saying: that the decision whether to use or not to use an attribute is > made when we merge the faces, not when we apply the face attributes to > produce the display on the glass. Sounds about right, yes. Stefan ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-13 15:32 ` Eli Zaretskii 2019-08-13 22:33 ` Stefan Monnier @ 2019-08-14 8:58 ` martin rudalics 1 sibling, 0 replies; 183+ messages in thread From: martin rudalics @ 2019-08-14 8:58 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, monnier, emacs-devel > Are you sure? It sounds like Stefan was saying the same thing I was > saying: that the decision whether to use or not to use an attribute is > made when we merge the faces, not when we apply the face attributes to > produce the display on the glass. If I ever gave you the impression that I meant something to the contrary, that impression was wrong and I apologize for it. > Or maybe it's me who misunderstood what Stefan meant... I think you misunderstood what I meant... martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-12 15:29 ` Eli Zaretskii 2019-08-12 22:18 ` Stefan Monnier @ 2019-08-13 8:17 ` martin rudalics 2019-08-13 15:31 ` Eli Zaretskii 1 sibling, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-13 8:17 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel >> IIUC the last one found by face_at_buffer_position that explicitly >> specified a value for the attribute in question. That is, the face >> whose attribute is actually used by the display engine. > > Nitpicking: the display engine has no idea whose attributes it is > using, see below. In an earlier mail I labelled the display engine as "face agnostic" so I am very well aware of that. What I tried to point out (and failed) so far is precisely how to work around that issue. > If two or more faces of those merged specify :underline, and only one > of them has a non-nil :extend, will extending the underline do what > the users expect? It's the last face whose (1) :underline attribute is merged in _and_ whose (2) :extend attribute is set (nil or non-nil) that determines whether the underline extends or not. Whether that is what the users expect is beyond my knowledge. We can only try to provide a fairly consistent way of specifying it. > (And shouldn't we simply disregard entirely a face whose :extend > attribute is nil? What can such a face possibly contribute in this > case?) Consider a user who sets the :extend attribute to non-nil for the 'default' face and wants a 'link' background to not extend to the end of line. Such a user would want to set the :extend attribute of the 'link' face to nil to get the desired effect. > You seem to assume that the iterator examines faces at every buffer > position it passes, and in particular on the newline at EOL. I certainly do not assume such a thing. But when trying to find out how face attributes are merged and realized, face_at_buffer_position was the first point of reference where I found that (and I still don't know a better one). > But > that's not what happens, because examining and merging faces is > expensive, so Emacs avoids doing that unless necessary. We only > examine faces where they change, and use next-single-property-change > to find the next position where we should again examine the faces. That's exactly what I expected but did not find immediately. If you tell me where to look for that (Fnext_single_property_change _is_ called by face_at_buffer_position) "examine faces where they change" and in particular where a :background change is found and applied, I probably could tell you more. > In addition, face_at_buffer_position doesn't look for face attributes > one by one. Instead, it finds all the source of the 'face' property > that are in effect at the given position -- the default face, the face > from text properties, and from all the overlays at that position -- > and merges these attributes into a single attribute vector. Then it > looks up a realized face with identical attributes, or realizes a new > face if no such face exists. Thereafter, the iterator just uses that > face until the next checkpoint. IOW, face_at_buffer_position returns > an ID of a realized (i.e. fully specified) face created by merging > several relevant sources of face information, and that realized face > has no references to the names of the individual faces from which it > was created, nor any memory of which non-unspecified attributes came > from which face source. When face_at_buffer_position puts some 'background' value into that single attribute vector, it can simply set an 'extend_background' bit in that vector which tells the display engine whether the background specified by that vector shall be extended or not. Note that that 'extend_background' bit would be left alone when the face specifying :background does not also specify :extend. In that case the value of :extend of the last face merged in that specified both would persist. > So to implement something like above, we will have to: > > . force face merging when we get to a newline (btw, what about > continuation lines in this context? do we apply the extension logic > to them as well?) I never show continuation lines (with exception of the minibuffer where I have no choice) but I suppose we should apply the extension there as well. Think of the region spanning several continued lines. > . modify face_at_buffer_position and its subroutines to behave > specially when called on a newline, I strongly doubt that this "called on a newline" is needed. Setting the 'extend_background' indicator is strongly tied to the last setting of the 'background' indicator in the attribute vector as done by the face merging algorithm. > and decide whether to merge or > not merge attributes based on whatever data structures describe the > preferences for extending those attributes; this would go at least > two levels below face_at_buffer_position > . do something similar in face_at_string_position, for display and > overlay strings with embedded newlines > > Sounds like fun project. Volunteers are welcome. If all these were really necessary, I'd never vote for such a change. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-13 8:17 ` martin rudalics @ 2019-08-13 15:31 ` Eli Zaretskii 2019-08-14 8:58 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-13 15:31 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Tue, 13 Aug 2019 10:17:32 +0200 > > > (And shouldn't we simply disregard entirely a face whose :extend > > attribute is nil? What can such a face possibly contribute in this > > case?) > > Consider a user who sets the :extend attribute to non-nil for the > 'default' face and wants a 'link' background to not extend to the end > of line. Such a user would want to set the :extend attribute of the > 'link' face to nil to get the desired effect. Yes, and my point is that in that case we can simply ignore the 'link' face when extending the face of the last character of a line. > > You seem to assume that the iterator examines faces at every buffer > > position it passes, and in particular on the newline at EOL. > > I certainly do not assume such a thing. But when trying to find out > how face attributes are merged and realized, face_at_buffer_position > was the first point of reference where I found that (and I still don't > know a better one). face_at_buffer_position is the right place, but it isn't called for every buffer position. And your description seemed to hint that you thought it was called for every buffer position. > > But > > that's not what happens, because examining and merging faces is > > expensive, so Emacs avoids doing that unless necessary. We only > > examine faces where they change, and use next-single-property-change > > to find the next position where we should again examine the faces. > > That's exactly what I expected but did not find immediately. If you > tell me where to look for that (Fnext_single_property_change _is_ > called by face_at_buffer_position) "examine faces where they change" This has to do with how the display iterator works in general. It starts by determining where the next "stop position" is. A "stop position" (stored in it->stop_charpos) is the position where iteration must stop and examine all the possible sources of affecting what and how should be displayed next. This includes faces, on-the-fly fontification, invisible text, display properties, overlays, switching from iteration over a buffer to iteration of a string and back, etc. At that stop position, the iterator examines all these potential game-changers, and computes and stores the results in its fields. That is where face_at_buffer_position is called, and the result is it->face_id, a numerical index into the frame's face cache which defines the realized face to be used from now on for displaying characters. The iterator will not call face_at_buffer_position and won't consider faces until it gets to the next stop position. The next stop position is computed in compute_stop_pos. You will see that it doesn't call Fnext_single_property_change, but instead accesses the interval tree directly, because that's more efficient: you find changes in _any_ text properties that way. It also considers overlay changes and changes in character composition. The next stop position is the closest one of those provided by any of these sources. When we get to the stop position, we invoke a series of known handlers, each one responsible to handle the relevant Lisp data structures that might affect the display. See handle_stop. In particular, the handler of face properties is handle_face_prop, which calls face_at_buffer_position or face_at_string_position. Each handler updates the relevant fields of the iterator structure as necessary. Having handled everything that needs to be handled at a particular stop position, we call compute_stop_pos to compute the next stop position, and then proceed producing glyphs using the updated iterator information until we get to that next stop position, never examining any of the above factors again until we get to that place. > and in particular where a :background change is found and applied, I > probably could tell you more. Neither :background nor any other face attribute is "found and applied" in the main iterator loop. The iterator simply records in each glyph the face ID to be used for displaying that glyph. That face ID is the value returned by the last call to face_at_buffer_position. The code which examines these attributes is in the terminal-specific backends: xterm.c, w32term.c, nsterm.m, etc. Only there we extract the colors, the underline, the strike-through, etc. attributes, and use them to produce the corresponding visual appearance. For example, for the background color, that is where we instruct the GUI system to "clear to EOL" with that color. (The last paragraph is slightly over-simplified: you will see in a couple of places that we do look at face->background in xdisp.c, notably in extend_face_to_end_of_line, but only in order to compare it with the frame's default background.) > > In addition, face_at_buffer_position doesn't look for face attributes > > one by one. Instead, it finds all the source of the 'face' property > > that are in effect at the given position -- the default face, the face > > from text properties, and from all the overlays at that position -- > > and merges these attributes into a single attribute vector. Then it > > looks up a realized face with identical attributes, or realizes a new > > face if no such face exists. Thereafter, the iterator just uses that > > face until the next checkpoint. IOW, face_at_buffer_position returns > > an ID of a realized (i.e. fully specified) face created by merging > > several relevant sources of face information, and that realized face > > has no references to the names of the individual faces from which it > > was created, nor any memory of which non-unspecified attributes came > > from which face source. > > When face_at_buffer_position puts some 'background' value into that > single attribute vector, it can simply set an 'extend_background' bit > in that vector which tells the display engine whether the background > specified by that vector shall be extended or not. So you propose to have an "extend" bit for every face attribute? There are 18 of them. (Maybe some of the attributes won't need that bit, but quite a few will.) Moreover, given the description above of where the attributes are acted upon, you are saying that xterm.c, w32term.c etc. will have to consider whether the glyphs they display are at the end of a line or not, and act accordingly, i.e. ignore some of the face attributes under certain conditions, right? > > . modify face_at_buffer_position and its subroutines to behave > > specially when called on a newline, > > I strongly doubt that this "called on a newline" is needed. Setting > the 'extend_background' indicator is strongly tied to the last setting > of the 'background' indicator in the attribute vector as done by the > face merging algorithm. But the merged face will be used for displaying both the "extension" part of the line and "normal" characters. When displaying "normal" characters, the background color should be used unconditionally, whereas while displaying the "extension" part it should be used only if its 'extend' bit is set. Right? What I wrote above assumed that we make these decisions at face merge time, and will actually have 2 different realized faces; what you are suggesting is that we use a single realized face and make those decisions when we use the faces to write to the glass. That doesn't strike me as a simpler implementation. > > Sounds like fun project. Volunteers are welcome. > > If all these were really necessary, I'd never vote for such a change. I'm afraid I still don't see a simple solution. Hopefully someone will show me the light. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-13 15:31 ` Eli Zaretskii @ 2019-08-14 8:58 ` martin rudalics 2019-08-14 15:14 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-14 8:58 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel >> Consider a user who sets the :extend attribute to non-nil for the >> 'default' face and wants a 'link' background to not extend to the end >> of line. Such a user would want to set the :extend attribute of the >> 'link' face to nil to get the desired effect. > > Yes, and my point is that in that case we can simply ignore the 'link' > face when extending the face of the last character of a line. How would the display engine then know that it can "simply ignore" the background of that face for the rest of the line? > face_at_buffer_position is the right place, but it isn't called for > every buffer position. And your description seemed to hint that you > thought it was called for every buffer position. My bad. But understanding face implementatin _without_ the text you wrote below would take a couple of days at least for a humble reader like me. > This has to do with how the display iterator works in general. It > starts by determining where the next "stop position" is. A "stop > position" (stored in it->stop_charpos) is the position where iteration > must stop and examine all the possible sources of affecting what and > how should be displayed next. This includes faces, on-the-fly > fontification, invisible text, display properties, overlays, switching > from iteration over a buffer to iteration of a string and back, etc. > At that stop position, the iterator examines all these potential > game-changers, and computes and stores the results in its fields. > That is where face_at_buffer_position is called, and the result is > it->face_id, a numerical index into the frame's face cache which > defines the realized face to be used from now on for displaying > characters. The iterator will not call face_at_buffer_position and > won't consider faces until it gets to the next stop position. > > The next stop position is computed in compute_stop_pos. You will see > that it doesn't call Fnext_single_property_change, but instead > accesses the interval tree directly, because that's more efficient: > you find changes in _any_ text properties that way. It also considers > overlay changes and changes in character composition. The next stop > position is the closest one of those provided by any of these sources. > > When we get to the stop position, we invoke a series of known > handlers, each one responsible to handle the relevant Lisp data > structures that might affect the display. See handle_stop. In > particular, the handler of face properties is handle_face_prop, which > calls face_at_buffer_position or face_at_string_position. Each > handler updates the relevant fields of the iterator structure as > necessary. Having handled everything that needs to be handled at a > particular stop position, we call compute_stop_pos to compute the next > stop position, and then proceed producing glyphs using the updated > iterator information until we get to that next stop position, never > examining any of the above factors again until we get to that place. Thanks for the lucid description. This is hopefully clear to me now. >> and in particular where a :background change is found and applied, I >> probably could tell you more. > > Neither :background nor any other face attribute is "found and > applied" in the main iterator loop. The iterator simply records in > each glyph the face ID to be used for displaying that glyph. That > face ID is the value returned by the last call to > face_at_buffer_position. IIUC the latter will (unless the face was cached already) end up calling merge_face_ref and somewhere there I find the lines else if (EQ (keyword, QCbackground)) { if (STRINGP (value)) to[LFACE_BACKGROUND_INDEX] = value; else err = true; } Hence IIUC in the while (CONSP (face_ref) && CONSP (XCDR (face_ref))) loop we could manage three booleans background, extend and extend_value and instead of the above write else if (EQ (keyword, QCbackground)) { if (STRINGP (value)) { to[LFACE_BACKGROUND_INDEX] = value; if (extend) to[LFACE_EXTEND_BACKGROUND] = extend_value; background = true; } else err = true; } else if (EQ (keyword, QCextend_background)) { extend = true; extend_value = !NILP (value); if (background) to[LFACE_EXTEND_BACKGROUND] = extend_value; } > The code which examines these attributes is > in the terminal-specific backends: xterm.c, w32term.c, nsterm.m, etc. > Only there we extract the colors, the underline, the strike-through, > etc. attributes, and use them to produce the corresponding visual > appearance. For example, for the background color, that is where we > instruct the GUI system to "clear to EOL" with that color. > > (The last paragraph is slightly over-simplified: you will see in a > couple of places that we do look at face->background in xdisp.c, > notably in extend_face_to_end_of_line, but only in order to compare it > with the frame's default background.) All these (the platform specific parts and the xdisp code) are already too late for what I have in mind. >> When face_at_buffer_position puts some 'background' value into that >> single attribute vector, it can simply set an 'extend_background' bit >> in that vector which tells the display engine whether the background >> specified by that vector shall be extended or not. > > So you propose to have an "extend" bit for every face attribute? > There are 18 of them. (Maybe some of the attributes won't need that > bit, but quite a few will.) I'd propose to add these lazily if there is any need. AFAIAC :background is the only attribute where an extend bit sounds useful. Some people here have explictily stated that they do not consider it useful to extend the :underline attribute and I agree. So if you think that other attributes will need an extend bit, please tell me which ones you have in mind. > Moreover, given the description above of where the attributes are > acted upon, you are saying that xterm.c, w32term.c etc. will have to > consider whether the glyphs they display are at the end of a line or > not, and act accordingly, i.e. ignore some of the face attributes > under certain conditions, right? By no means. The extend_background bit would be set in merge_face_ref as sketched above (because this is the one that can read the :background and :extend attributes of any face) and examined in extend_face_to_end_of_line wherever face->background is involved (because this is the one that knows that we want to display a newline). > But the merged face will be used for displaying both the "extension" > part of the line and "normal" characters. When displaying "normal" > characters, the background color should be used unconditionally, Definitely so. > whereas while displaying the "extension" part it should be used only > if its 'extend' bit is set. Right? The extend_background bit, more precisely (the :extend face attribute conceptually applies to all attributes so we can eventually handle :underline and :box as well if somone wants that). > What I wrote above assumed that > we make these decisions at face merge time, and will actually have 2 > different realized faces; We should have only one realized face. > what you are suggesting is that we use a > single realized face and make those decisions when we use the faces to > write to the glass. That doesn't strike me as a simpler > implementation. But that decision should have become simpler now that all we need is to examine that extend_background bit to tell whether the background shall extend to EOL or not. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-14 8:58 ` martin rudalics @ 2019-08-14 15:14 ` Eli Zaretskii 2019-08-15 8:13 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-14 15:14 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Wed, 14 Aug 2019 10:58:13 +0200 > > >> Consider a user who sets the :extend attribute to non-nil for the > >> 'default' face and wants a 'link' background to not extend to the end > >> of line. Such a user would want to set the :extend attribute of the > >> 'link' face to nil to get the desired effect. > > > > Yes, and my point is that in that case we can simply ignore the 'link' > > face when extending the face of the last character of a line. > > How would the display engine then know that it can "simply ignore" > the background of that face for the rest of the line? By seeing that it has the :extend attribute set to nil. > understanding face implementatin _without_ the text you wrote below > would take a couple of days at least for a humble reader like me. And I didn't even mention the complications related to bidi ;-) > > Neither :background nor any other face attribute is "found and > > applied" in the main iterator loop. The iterator simply records in > > each glyph the face ID to be used for displaying that glyph. That > > face ID is the value returned by the last call to > > face_at_buffer_position. > > IIUC the latter will (unless the face was cached already) end up > calling merge_face_ref and somewhere there I find the lines > > else if (EQ (keyword, QCbackground)) > { > if (STRINGP (value)) > to[LFACE_BACKGROUND_INDEX] = value; > else > err = true; > } > > Hence IIUC in the > > while (CONSP (face_ref) && CONSP (XCDR (face_ref))) > > loop we could manage three booleans background, extend and > extend_value and instead of the above write > > else if (EQ (keyword, QCbackground)) > { > if (STRINGP (value)) > { > to[LFACE_BACKGROUND_INDEX] = value; > > if (extend) > to[LFACE_EXTEND_BACKGROUND] = extend_value; > > background = true; > } > else > err = true; > } > else if (EQ (keyword, QCextend_background)) > { > extend = true; > extend_value = !NILP (value); > > if (background) > to[LFACE_EXTEND_BACKGROUND] = extend_value; > } This just copies the :extend flag to the merged face. It sill copies the :background attribute itself, and so the merged face will have a non-default background color. > > So you propose to have an "extend" bit for every face attribute? > > There are 18 of them. (Maybe some of the attributes won't need that > > bit, but quite a few will.) > > I'd propose to add these lazily if there is any need. AFAIAC > :background is the only attribute where an extend bit sounds useful. IMO, it makes very little sense to allow this only for the background color. For starters, please keep in mind that this whole discussion started because we were considering to make TTY frames behave like GUI frames wrt face extension, and TTY frames currently extend also the other attributes, notably the :underline. Some people also complain about :underline being ugly on GUI frames when it crosses the newline and continues on the next line. I think we need to support this for :background, :underline, :overline, :strike-through, :box, and :stipple. > The extend_background bit would be set in merge_face_ref as sketched > above (because this is the one that can read the :background and > :extend attributes of any face) and examined in > extend_face_to_end_of_line wherever face->background is involved > (because this is the one that knows that we want to display a > newline). What do you want extend_face_to_end_of_line to do with the extend_background bit? extend_face_to_end_of_line doesn't apply the background, it just produces glyphs, and has only face IDs to work with. So if the face ID of the last character specifies a face with a background color, and the extend_background bit says not to extend the background color, how would extend_face_to_end_of_line "remove" the background color attribute from the face for which it only has the ID? The only way to do that is to make a new face, by merging all the attributes except the background color, and then use that new face's ID for producing glyphs that extend the face. This is why I said earlier that I assumed we make the extension decisions at face merge time, and will have 2 different realized faces, not one. But you disagreed with that conclusion: > > What I wrote above assumed that > > we make these decisions at face merge time, and will actually have 2 > > different realized faces; > > We should have only one realized face. AFAIU, that's impossible, not on the level on which extend_face_to_end_of_line (or any code in xdisp.c, really) works. It cannot "apply a face sans some attributes", there are no such capabilities on this level. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-14 15:14 ` Eli Zaretskii @ 2019-08-15 8:13 ` martin rudalics 2019-08-15 15:18 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-15 8:13 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel >> understanding face implementatin _without_ the text you wrote below >> would take a couple of days at least for a humble reader like me. > > And I didn't even mention the complications related to bidi ;-) Are there any bidi complications related to that particular text? No need for you to point anything out in detail: I suppose it's that finding the next "stop" position gets complicated when the display direction changes. Now in my naive imagination buffer text per se is one-directional so Fnext_single_property_change progresses always in one direction. Does the inteval tree gets botched in some sense? > This just copies the :extend flag to the merged face. Yes. > It sill copies > the :background attribute itself, and so the merged face will have a > non-default background color. But isn't that the whole idea of that step? Or do you mean that since the display engine can't cope with the extend bit and thus suppress the background by demand, doing that just won't have any effect? > I'd propose to add these lazily if there is any need. AFAIAC >> :background is the only attribute where an extend bit sounds useful. > > IMO, it makes very little sense to allow this only for the background > color. For starters, please keep in mind that this whole discussion > started because we were considering to make TTY frames behave like GUI > frames wrt face extension, and TTY frames currently extend also the > other attributes, notably the :underline. Some people also complain > about :underline being ugly on GUI frames when it crosses the newline > and continues on the next line. That's why in a first step I would disregard the others and by default not extend them. Then we would see what is missing and fill in the remaining attributes of this list ... > I think we need to support this for :background, :underline, > :overline, :strike-through, :box, and :stipple. ... to possibly extend to end of line as well. > What do you want extend_face_to_end_of_line to do with the > extend_background bit? extend_face_to_end_of_line doesn't apply the > background, it just produces glyphs, and has only face IDs to work > with. Since I wasn't aware of that fact ("I'm learning something new about Emacs almost every day") ... > So if the face ID of the last character specifies a face with a > background color, and the extend_background bit says not to extend the > background color, how would extend_face_to_end_of_line "remove" the > background color attribute from the face for which it only has the ID? > > The only way to do that is to make a new face, by merging all the > attributes except the background color, and then use that new face's > ID for producing glyphs that extend the face. This is why I said > earlier that I assumed we make the extension decisions at face merge > time, and will have 2 different realized faces, not one. But you > disagreed with that conclusion: ... I obviously have to discontinue disagreeing with that conclusion. But wouldn't that significantly increase the size of the face cache? I have no idea about the typical size of that cache with a moderately customized Emacs ... >> > What I wrote above assumed that >> > we make these decisions at face merge time, and will actually have 2 >> > different realized faces; >> >> We should have only one realized face. > > AFAIU, that's impossible, not on the level on which > extend_face_to_end_of_line (or any code in xdisp.c, really) works. It > cannot "apply a face sans some attributes", there are no such > capabilities on this level. Since extend_face_to_end_of_line already switches to the default face when no extension of the region is wanted, it could also switch to the default face when the extend_background bit is false. Right? martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-15 8:13 ` martin rudalics @ 2019-08-15 15:18 ` Eli Zaretskii 2019-08-16 7:29 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-15 15:18 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Thu, 15 Aug 2019 10:13:21 +0200 > > >> understanding face implementatin _without_ the text you wrote below > >> would take a couple of days at least for a humble reader like me. > > > > And I didn't even mention the complications related to bidi ;-) > > Are there any bidi complications related to that particular text? No > need for you to point anything out in detail: I suppose it's that > finding the next "stop" position gets complicated when the display > direction changes. Exactly. More accurately, we have 2 problems: (1) how do you know you hit the stop point while going back; and (2) where do you go to compute the "next" stop point. You don't want to know the answers... > Now in my naive imagination buffer text per se is > one-directional so Fnext_single_property_change progresses always in > one direction. Does the inteval tree gets botched in some sense? No, nothing terrible like that. It's just those 2 problems mentioned above. > > It sill copies > > the :background attribute itself, and so the merged face will have a > > non-default background color. > > But isn't that the whole idea of that step? Or do you mean that since > the display engine can't cope with the extend bit and thus suppress > the background by demand, doing that just won't have any effect? The latter, yes. IOW, doing that will simply defer the decision for later. > > So if the face ID of the last character specifies a face with a > > background color, and the extend_background bit says not to extend the > > background color, how would extend_face_to_end_of_line "remove" the > > background color attribute from the face for which it only has the ID? > > > > The only way to do that is to make a new face, by merging all the > > attributes except the background color, and then use that new face's > > ID for producing glyphs that extend the face. This is why I said > > earlier that I assumed we make the extension decisions at face merge > > time, and will have 2 different realized faces, not one. But you > > disagreed with that conclusion: > > ... I obviously have to discontinue disagreeing with that conclusion. > But wouldn't that significantly increase the size of the face cache? It will increase the cache, yes. Whether it will be significant is another question; I'm not sure. > >> We should have only one realized face. > > > > AFAIU, that's impossible, not on the level on which > > extend_face_to_end_of_line (or any code in xdisp.c, really) works. It > > cannot "apply a face sans some attributes", there are no such > > capabilities on this level. > > Since extend_face_to_end_of_line already switches to the default face > when no extension of the region is wanted It does? where? > it could also switch to the default face when the extend_background > bit is false. Right? No. A face is not just its background color, it's quite a few other things. You only want to reset the background color. For example, if the face of the last character used a larger font, you still want the extension to use that larger font, e.g. for the fill-column indicator character. So switching to the default face in this case is wrong, we really need to make a face exactly like the one we used, but without the attribute that should not be extended. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-15 15:18 ` Eli Zaretskii @ 2019-08-16 7:29 ` martin rudalics 2019-08-16 8:34 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-16 7:29 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel > Exactly. More accurately, we have 2 problems: (1) how do you know you > hit the stop point while going back; and (2) where do you go to > compute the "next" stop point. You don't want to know the answers... I'm not sure. If that algorithm is newline agnostic, it will have to be changed if an eager (see below) solution is implemented. >> ... I obviously have to discontinue disagreeing with that conclusion. >> But wouldn't that significantly increase the size of the face cache? > > It will increase the cache, yes. Whether it will be significant is > another question; I'm not sure. In the worst case it would double the size of the cache for implementing the background extension alone. This looks like a veritable ordeal to me. IIUC we do all this to keep the display optimizations (where we compare the glyph matrices) simple and efficient. Or is there an additional twist to it? One could argue that if, in the current implementation, the display element stops right before a newline character and that newline is, presumably, a separate display element, the overhead remains unchanged. But AFAICT, font locking does not necessarily pay immense attention to newlines (Lisp comments and C strings excluded) so at least for displaying programming languages the overhead increase might be significant. >> Since extend_face_to_end_of_line already switches to the default face >> when no extension of the region is wanted > > It does? where? I thought it did so here /* The last row's blank glyphs should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ if (it->glyph_row->ends_at_zv_p) it->face_id = default_face->id; else it->face_id = face->id; but apparently that's only a red herring. >> it could also switch to the default face when the extend_background >> bit is false. Right? > > No. A face is not just its background color, it's quite a few other > things. You only want to reset the background color. For example, if > the face of the last character used a larger font, you still want the > extension to use that larger font, e.g. for the fill-column indicator > character. > > So switching to the default face in this case is wrong, we really need > to make a face exactly like the one we used, but without the attribute > that should not be extended. I currently see two ways to accomplish that: Eagerly, during face merging, we would have to search for and possibly create the extend face variation whenever the next stop point finding algorithm encounters a newline character within the object it examines. This means that any display element that contains a newline character also ends before that character and the entire logic of finding display elements changes. A lazy variant would have the display engine itself create the extend face by demand whenever it encounters a newline character within the current display element. This would strike me as more elegant but also means that the display engine has to scan the face cache and potentially realize a new face here. The worst aspect of all this is that there is no simpler solution even if we attempted a different implementation of the extend logic. Suppose I used just one single, global variable to turn off/on any face extensions. For turning it off, I'd still have to, at the end of every line, assure that a separate realized face does implement the "off" interpretation while the "on" interpretation is already provided by the last face on that line. Right? martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-16 7:29 ` martin rudalics @ 2019-08-16 8:34 ` Eli Zaretskii 2019-08-17 8:25 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-16 8:34 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Fri, 16 Aug 2019 09:29:02 +0200 > > > Exactly. More accurately, we have 2 problems: (1) how do you know you > > hit the stop point while going back; and (2) where do you go to > > compute the "next" stop point. You don't want to know the answers... > > I'm not sure. If that algorithm is newline agnostic, it will have to > be changed if an eager (see below) solution is implemented. Thankfully and mercifully, all the bidi calculations and hidden state variables are reset at newlines. > > It will increase the cache, yes. Whether it will be significant is > > another question; I'm not sure. > > In the worst case it would double the size of the cache for > implementing the background extension alone. This looks like a > veritable ordeal to me. IIUC we do all this to keep the display > optimizations (where we compare the glyph matrices) simple and > efficient. Or is there an additional twist to it? Well, a face cache is rarely too large, it mostly holds a few dozen faces. We also clear it from time to time, so I don't think this would be a catastrophe. > One could argue that if, in the current implementation, the display > element stops right before a newline character and that newline is, > presumably, a separate display element, the overhead remains > unchanged. But AFAICT, font locking does not necessarily pay immense > attention to newlines (Lisp comments and C strings excluded) so at > least for displaying programming languages the overhead increase might > be significant. Actually, IME the situation where a face crosses a newline is somewhat rare. > >> Since extend_face_to_end_of_line already switches to the default face > >> when no extension of the region is wanted > > > > It does? where? > > I thought it did so here > > /* The last row's blank glyphs should get the default face, to > avoid painting the rest of the window with the region face, > if the region ends at ZV. */ > if (it->glyph_row->ends_at_zv_p) > it->face_id = default_face->id; > else > it->face_id = face->id; > > but apparently that's only a red herring. This is a corner case, for the screen lines beyond EOB. It is none of our business for the purposes of this discussion. > I currently see two ways to accomplish that: Eagerly, during face > merging, we would have to search for and possibly create the extend > face variation whenever the next stop point finding algorithm > encounters a newline character within the object it examines. Not my preference. It will disrupt the neat algorithm of walking the interval tree, or at least will force us to also search for a newline (which is very fast, but still a complication). > This means that any display element that contains a newline > character also ends before that character and the entire logic of > finding display elements changes. What you call "display element" is actually called a "glyph string": a sequence of glyphs that have the same face. The division of glyphs into glyph strings happens as part of preparing glyphs for display, and will automatically pay attention to changes in the face ID. So no logic changes here. The changes are as I described above: where we compute the next stop position. there' we will have to see whether the stretch of text till the next stop includes a newline. > A lazy variant would have the display engine itself create the extend > face by demand whenever it encounters a newline character within the > current display element. I'd prefer this method. Two reasons: (1) it is localized to the code which may need such a face; and (2) it scales better, because the display code is frequently invoked on short portions of the text, so there's no guarantee that it will actually get to producing glyphs with the "extension" variant of the face, so realizing that face in advance might well be waste of unneeded effort, because the additional face will never be used. > The worst aspect of all this is that there is no simpler solution even > if we attempted a different implementation of the extend logic. > Suppose I used just one single, global variable to turn off/on any > face extensions. For turning it off, I'd still have to, at the end of > every line, assure that a separate realized face does implement the > "off" interpretation while the "on" interpretation is already provided > by the last face on that line. Right? Yes, we will typically need that "on" face for the next screen line. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-16 8:34 ` Eli Zaretskii @ 2019-08-17 8:25 ` martin rudalics 2019-08-19 16:13 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-17 8:25 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel > I'd prefer this method. Two reasons: (1) it is localized to the code > which may need such a face; and (2) it scales better, because the > display code is frequently invoked on short portions of the text, so > there's no guarantee that it will actually get to producing glyphs > with the "extension" variant of the face, so realizing that face in > advance might well be waste of unneeded effort, because the additional > face will never be used. The following should capture what emerged from this discussion so far: (1) Provide an :extend face attribute with the semantics to extend, if set, any "background-related" attributes like :background, :underline, :box ... specified by this face. (2) When merging faces, set an extend-background, extend-underline, extend-box ... bit for all background-related attributes whenever the face merged in has both the :extend attribute non-nil and the corresponding background-related attribute set. (3) When the display engine encounters a newline character and the current face has one of the extend-* bits set, either reuse or create a new realized face based on the current face, removing from a new realized face any background-related information for which the current face that has the corresponding extend-* bit set. For example, if the current face specifies a background, remove that in the new face if the extend-background bit is unset. (4) Use the face found or made in (3) for glyphs on the rest of the current line. Conversely, we could use a :no-extend attribute and/or no-extend-background bits in the realized faces if that's simpler or more intuitive. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-17 8:25 ` martin rudalics @ 2019-08-19 16:13 ` Ergus 2019-08-19 16:50 ` Eli Zaretskii 2019-08-21 7:37 ` martin rudalics 0 siblings, 2 replies; 183+ messages in thread From: Ergus @ 2019-08-19 16:13 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel Hi: After a couple of weeks with this discussion I am back to see if there is finally an agreement or more people interested. But I see there are mainly only Eli and Martin involved. The proposed solutions I see here seems to be a bit complex (to implements and to execute for the display engine). It seems that no applications or developers are interested on this detail enough to comment or propose solutions here. I understand that the proposed are the most general solutions, but does it worth the complexity, overhead, and customization vs the benefit? Do we really need all these functionalities and control in detail? Are we really expecting that the users will be allowed||interested in customizing all this in such granular level? Extending the face is a detail that most users won't even notice a change while it works somehow. Actually we have had different behaviors between gui and tui for years and nobody complained up to now. Extending the underline|overline to the right of the line in the region is a fancy detail, but I don't find it useful at all (underlining empty long spaces is conceptually an error), and in the actual gui it is not happening (not even extend_face_to_end_of_line in gui is executed as the background color is extended automatically somewhere else) and there haven't been complains either, so there is not people using that, so why do we provide a complex solution implementation for a problem nobody really cares and that potentially will produce overheads, code complexity and more issues? I am wondering about over-specifications and over-engineering for such a detail, when most of the users only need to extend the background color. On Sat, Aug 17, 2019 at 10:25:13AM +0200, martin rudalics wrote: >> I'd prefer this method. Two reasons: (1) it is localized to the code >> which may need such a face; and (2) it scales better, because the >> display code is frequently invoked on short portions of the text, so >> there's no guarantee that it will actually get to producing glyphs >> with the "extension" variant of the face, so realizing that face in >> advance might well be waste of unneeded effort, because the additional >> face will never be used. > >The following should capture what emerged from this discussion so far: > >(1) Provide an :extend face attribute with the semantics to extend, if > set, any "background-related" attributes like :background, > :underline, :box ... specified by this face. > >(2) When merging faces, set an extend-background, extend-underline, > extend-box ... bit for all background-related attributes whenever > the face merged in has both the :extend attribute non-nil and the > corresponding background-related attribute set. > >(3) When the display engine encounters a newline character and the > current face has one of the extend-* bits set, either reuse or > create a new realized face based on the current face, removing > from a new realized face any background-related information for > which the current face that has the corresponding extend-* bit > set. For example, if the current face specifies a background, > remove that in the new face if the extend-background bit is unset. > >(4) Use the face found or made in (3) for glyphs on the rest of the > current line. > >Conversely, we could use a :no-extend attribute and/or >no-extend-background bits in the realized faces if that's simpler or >more intuitive. > >martin > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-19 16:13 ` Ergus @ 2019-08-19 16:50 ` Eli Zaretskii 2019-08-19 21:30 ` Ergus 2019-08-21 7:37 ` martin rudalics 1 sibling, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-19 16:50 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 19 Aug 2019 18:13:05 +0200 > From: Ergus <spacibba@aol.com> > Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org > > Extending the face is a detail that most users won't even notice a > change while it works somehow. Actually we have had different behaviors > between gui and tui for years and nobody complained up to now. I think you over-simplify the situation. First, both GUI and TTY frames behave the same when extension of face background color is concerned, they only differ in how they handle extension of other attributes (of which only the underline is relevant to TTY frames). (And I did hear over the years a couple of complaints about how TTY frames extend the underline attribute.) And second, I refer you to the renewed discussion of bug#15934 a day or two ago, from which my take is that users will notice and do care about such changes in at least a couple of important use cases, as a soon-to-be-pushed changes will prove. So I don't think we can change this behavior at will on the assumption that "no one will notice". > I am wondering about over-specifications and over-engineering for such a > detail, when most of the users only need to extend the background color. This discussion established that even supporting just the background color non-extension as a user option will require to have almost all of the machinery in place: the extend bit, the generation of a special face without the background color, etc. And once we have that, adding other face attributes to the soup is relatively easy and won't require any design changes. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-19 16:50 ` Eli Zaretskii @ 2019-08-19 21:30 ` Ergus 2019-08-20 14:09 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-19 21:30 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Mon, Aug 19, 2019 at 07:50:36PM +0300, Eli Zaretskii wrote: >> Date: Mon, 19 Aug 2019 18:13:05 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org >> >> Extending the face is a detail that most users won't even notice a >> change while it works somehow. Actually we have had different behaviors >> between gui and tui for years and nobody complained up to now. > >I think you over-simplify the situation. First, both GUI and TTY >frames behave the same when extension of face background color is >concerned, they only differ in how they handle extension of other >attributes (of which only the underline is relevant to TTY frames). >(And I did hear over the years a couple of complaints about how TTY >frames extend the underline attribute.) > >And second, I refer you to the renewed discussion of bug#15934 a day >or two ago, from which my take is that users will notice and do care >about such changes in at least a couple of important use cases, as a >soon-to-be-pushed changes will prove. So I don't think we can change >this behavior at will on the assumption that "no one will notice". > Hi Eli: If soon-to-be-pushed means that you have had already some time to work on this and it will be fixed before emacs 27 then I'll be happy with that (I'll be allowed to fix the dfci issue). I was actually wondering if the discussion was not going anywhere as I didn't see any comment in a couple of days. Unrelated with this I wanted to ask you if you think we should continue with the indentation highlight implementation... because that discussion never ended. Or you think it does not worth the effort. I have seen that elpy already have something like what we want to implement in the lisp level. So they will actually switch for sure to ours if available. What do you think? >> I am wondering about over-specifications and over-engineering for such a >> detail, when most of the users only need to extend the background color. > >This discussion established that even supporting just the background >color non-extension as a user option will require to have almost all >of the machinery in place: the extend bit, the generation of a special >face without the background color, etc. And once we have that, adding >other face attributes to the soup is relatively easy and won't require >any design changes. > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-19 21:30 ` Ergus @ 2019-08-20 14:09 ` Eli Zaretskii 2019-08-25 10:22 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-20 14:09 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 19 Aug 2019 23:30:24 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >And second, I refer you to the renewed discussion of bug#15934 a day > >or two ago, from which my take is that users will notice and do care > >about such changes in at least a couple of important use cases, as a > >soon-to-be-pushed changes will prove. So I don't think we can change > >this behavior at will on the assumption that "no one will notice". > > > Hi Eli: > > If soon-to-be-pushed means that you have had already some time to work on > this and it will be fixed before emacs 27 then I'll be happy with that > (I'll be allowed to fix the dfci issue). No, that was about bug#15934, where a change will be soon pushed that forces extension of a face to the edge of the window. > I was actually wondering if the discussion was not going anywhere as > I didn't see any comment in a couple of days. We've arrived to a good understanding of what needs to be done, and we have no issues left to discuss. What's left is to implement the thing. Volunteers are welcome. > Unrelated with this I wanted to ask you if you think we should continue > with the indentation highlight implementation... because that discussion > never ended. Or you think it does not worth the effort. I'm not sure. A few people said that what we wanted to leave out cannot be left out. > I have seen that elpy already have something like what we want to > implement in the lisp level. So they will actually switch for sure to > ours if available. Where can I see what they have? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-20 14:09 ` Eli Zaretskii @ 2019-08-25 10:22 ` Ergus 2019-08-25 10:44 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-25 10:22 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Tue, Aug 20, 2019 at 05:09:00PM +0300, Eli Zaretskii wrote: > >We've arrived to a good understanding of what needs to be done, and we >have no issues left to discuss. What's left is to implement the >thing. Volunteers are welcome. > Hi Eli I could be interested in this but I don't even understand clearly what you agreed; so it may take me a long time without some extra hints. (When things are related with the lisp part I just get lost.) >> I have seen that elpy already have something like what we want to >> implement in the lisp level. So they will actually switch for sure to >> ours if available. > >Where can I see what they have? > They just rely on: https://github.com/antonj/Highlight-Indentation-for-Emacs/blob/master/highlight-indentation.el with some modifications. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-25 10:22 ` Ergus @ 2019-08-25 10:44 ` Eli Zaretskii 2019-08-26 4:31 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-25 10:44 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Sun, 25 Aug 2019 12:22:05 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > On Tue, Aug 20, 2019 at 05:09:00PM +0300, Eli Zaretskii wrote: > > > >We've arrived to a good understanding of what needs to be done, and we > >have no issues left to discuss. What's left is to implement the > >thing. Volunteers are welcome. > > > Hi Eli I could be interested in this but I don't even understand clearly what > you agreed; so it may take me a long time without some extra > hints. (When things are related with the lisp part I just get lost.) Feel free to ask questions. (I don't think anything in the summary was related to Lisp, but maybe I'm wrong.) > >> I have seen that elpy already have something like what we want to > >> implement in the lisp level. So they will actually switch for sure to > >> ours if available. > > > >Where can I see what they have? > > > > They just rely on: > > https://github.com/antonj/Highlight-Indentation-for-Emacs/blob/master/highlight-indentation.el > > with some modifications. The question is will many/enough users agree to such a limited implementation. I was under the impression that quite a few responders said it would not be good enough. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-25 10:44 ` Eli Zaretskii @ 2019-08-26 4:31 ` Ergus 2019-08-26 7:45 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-26 4:31 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Sun, Aug 25, 2019 at 01:44:04PM +0300, Eli Zaretskii wrote: > >Feel free to ask questions. (I don't think anything in the summary >was related to Lisp, but maybe I'm wrong.) > Hi: Could you please finally explain what are all the points needed in the implementation? And more or less the changes needed/expected? >The question is will many/enough users agree to such a limited >implementation. I was under the impression that quite a few >responders said it would not be good enough. > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-26 4:31 ` Ergus @ 2019-08-26 7:45 ` Eli Zaretskii 2019-08-26 8:18 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-26 7:45 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 26 Aug 2019 06:31:45 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > On Sun, Aug 25, 2019 at 01:44:04PM +0300, Eli Zaretskii wrote: > > > > >Feel free to ask questions. (I don't think anything in the summary > >was related to Lisp, but maybe I'm wrong.) > > > > Hi: > > Could you please finally explain what are all the points needed in the > implementation? And more or less the changes needed/expected? Regarding face extension, or regarding highlight-indentation? These were 2 separate discussions, but you somehow conflated them together in your last email. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-26 7:45 ` Eli Zaretskii @ 2019-08-26 8:18 ` Ergus 2019-08-26 9:49 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-26 8:18 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Mon, Aug 26, 2019 at 10:45:11AM +0300, Eli Zaretskii wrote: >> Date: Mon, 26 Aug 2019 06:31:45 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> On Sun, Aug 25, 2019 at 01:44:04PM +0300, Eli Zaretskii wrote: >> >> > >> >Feel free to ask questions. (I don't think anything in the summary >> >was related to Lisp, but maybe I'm wrong.) >> > >> >> Hi: >> >> Could you please finally explain what are all the points needed in the >> implementation? And more or less the changes needed/expected? > >Regarding face extension, or regarding highlight-indentation? These >were 2 separate discussions, but you somehow conflated them together >in your last email. Regarding face extension ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-26 8:18 ` Ergus @ 2019-08-26 9:49 ` Eli Zaretskii 2019-08-27 22:20 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-26 9:49 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 26 Aug 2019 10:18:19 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >> Could you please finally explain what are all the points needed in the > >> implementation? And more or less the changes needed/expected? > > > >Regarding face extension, or regarding highlight-indentation? These > >were 2 separate discussions, but you somehow conflated them together > >in your last email. > > Regarding face extension The summary was posted by Martin here: https://lists.gnu.org/archive/html/emacs-devel/2019-08/msg00324.html If something there is unclear, please ask specific questions. Thanks. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-26 9:49 ` Eli Zaretskii @ 2019-08-27 22:20 ` Ergus 2019-08-28 8:35 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-27 22:20 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Mon, Aug 26, 2019 at 12:49:27PM +0300, Eli Zaretskii wrote: >> Date: Mon, 26 Aug 2019 10:18:19 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >> Could you please finally explain what are all the points needed in the >> >> implementation? And more or less the changes needed/expected? >> > >> >Regarding face extension, or regarding highlight-indentation? These >> >were 2 separate discussions, but you somehow conflated them together >> >in your last email. >> >> Regarding face extension > >The summary was posted by Martin here: > > https://lists.gnu.org/archive/html/emacs-devel/2019-08/msg00324.html > >If something there is unclear, please ask specific questions. > >Thanks. > Hi Eli: Starting with this I just need a couple of details to clarify if I understand everything: (1) Provide an :extend face attribute with the semantics to extend, if set, any "background-related" attributes like :background, :underline, :box ... specified by this face. The extend attribute here must be just a boolean to extend everything set in this class or something to specify what to extend from within this face? (2) When merging faces, set an extend-background, extend-underline, extend-box ... bit for all background-related attributes whenever the face merged in has both the :extend attribute non-nil and the corresponding background-related attribute set. (3) When the display engine encounters a newline character and the current face has one of the extend-* bits set, either reuse or create a new realized face based on the current face, removing from a new realized face any background-related information for which the current face that has the corresponding extend-* bit set. For example, if the current face specifies a background, remove that in the new face if the extend-background bit is unset. (4) Use the face found or made in (3) for glyphs on the rest of the current line. 1- Are the bits stored in the class or they are supposed to be like a display engine state variable? Check this true table please: merge_faces (struct window *w, Lisp_Object face_name, int face_id, int base_face_id) struct face = {extend_flag; bg, extend_bg_flag} base_face -> face = merged {true, nil, false} -> {false, y, false} -> {false, y, true} // ???? {false, x, false} -> {true, nil, false} -> {true, x, true} // Is this fine? When in 3 it says "remove", what does it means? set it to x, to default or to nil? In case we don't extend, the extra space we add after the line should have the default, face or the last in the line?? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-27 22:20 ` Ergus @ 2019-08-28 8:35 ` martin rudalics 2019-08-28 9:07 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-28 8:35 UTC (permalink / raw) To: Ergus, Eli Zaretskii; +Cc: emacs-devel > (1) Provide an :extend face attribute with the semantics to extend, if > set, any "background-related" attributes like :background, > :underline, :box ... specified by this face. > > The extend attribute here must be just a boolean to extend everything > set in this class or something to specify what to extend from within > this face? The former, conceptually. Only if we detect a corner case which tells us that inevitably "more" is needed, it might become necessary to implement the latter. So it might be a good idea to have the values unspecified, t, nil and a list where the semantics of a list would be currently undefined. > (2) When merging faces, set an extend-background, extend-underline, > extend-box ... bit for all background-related attributes whenever > the face merged in has both the :extend attribute non-nil and the > corresponding background-related attribute set. > > (3) When the display engine encounters a newline character and the > current face has one of the extend-* bits set, either reuse or > create a new realized face based on the current face, removing > from a new realized face any background-related information for > which the current face that has the corresponding extend-* bit > set. For example, if the current face specifies a background, > remove that in the new face if the extend-background bit is unset. > > (4) Use the face found or made in (3) for glyphs on the rest of the > current line. > > > 1- Are the bits stored in the class or they are supposed to be like a > display engine state variable? In the class, IIUC. That is, when merge_face_vectors merges in "an attribute we care about" it sets, for example, the extend_background bit of the TO face when both the :extend and :background values of the FROM vector are set. > Check this true table please: > > merge_faces (struct window *w, Lisp_Object face_name, int face_id, > int base_face_id) > > struct face = {extend_flag; bg, extend_bg_flag} > > base_face -> face = merged > > {true, nil, false} -> {false, y, false} -> {false, y, true} // ???? > {false, x, false} -> {true, nil, false} -> {true, x, true} // Is this fine? I'm too silly to understand these, please elaborate. > When in 3 it says "remove", what does it means? set it to x, to default or > to nil? > > In case we don't extend, the extra space we add after the line should > have the default, face or the last in the line?? The term "remove" was meant wrt the current face used by the iterator. If, for example, the current face of the iterator is the one specified by the region face, then it probably specifies some background used for "normal" text. When the display engine arrives at the newline character it checks whether the current face has the extend_background bit set and either reuses an existing or realizes a new face based on the background of the current face and that bit. What realizing has to do when extend_background is false is not entirely clear to me either. Suppose we have a newline character that is contained both in the region and a multiline comment and the region face results in an extend_background false bit while the comment face results in an extend_background true bit for the corresponding realized faces. Conceptually, this means that the spaces at the end of the line should have the comment background but unless we expand the extend_background bits into full pointers to other realized faces (and have face merging set up these pointers and the display engine resolve them) I see no way how this could be realized. So the rest of the line would be shown with the default face's background instead (or do whatever we do now when we don't expand) which obviously won't look good. Personally, I consider a setting like the above a misspecification: A "lower priority extend" face should never result in being covered by a "higher priority no-extend" face but others might obviously disagree. Maybe the display engine could consult, with the stop position privilege triggered by the newline character in mind, whether the extend_background false setting of the current face could result in applying another, lower-priority face specified by font-locking and consult the extend_background bit of the corresponding realized face. But I doubt that this would be easy to code. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-28 8:35 ` martin rudalics @ 2019-08-28 9:07 ` Eli Zaretskii 2019-08-28 12:19 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-28 9:07 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Wed, 28 Aug 2019 10:35:11 +0200 > > > When in 3 it says "remove", what does it means? set it to x, to default or > > to nil? > > > > In case we don't extend, the extra space we add after the line should > > have the default, face or the last in the line?? > > The term "remove" was meant wrt the current face used by the iterator. > If, for example, the current face of the iterator is the one specified > by the region face, then it probably specifies some background used > for "normal" text. When the display engine arrives at the newline > character it checks whether the current face has the extend_background > bit set and either reuses an existing or realizes a new face based on > the background of the current face and that bit. I think we should simply not merge the background color of the region face when its extend bit is reset. Then the merged face will not have that background color. > What realizing has to do when extend_background is false is not > entirely clear to me either. Suppose we have a newline character that > is contained both in the region and a multiline comment and the region > face results in an extend_background false bit while the comment face > results in an extend_background true bit for the corresponding > realized faces. > > Conceptually, this means that the spaces at the end of the line should > have the comment background but unless we expand the extend_background > bits into full pointers to other realized faces (and have face merging > set up these pointers and the display engine resolve them) I see no > way how this could be realized. So the rest of the line would be > shown with the default face's background instead (or do whatever we do > now when we don't expand) which obviously won't look good. I don't see a problem here. A user who doesn't want the region face's background extend to the end of line wants only text (as opposed to whitespace after the newline) to have the region's background, and that's true both to regions that cross line boundaries and regions that end at a newline. > Maybe the display engine could consult, with the stop position > privilege triggered by the newline character in mind, whether the > extend_background false setting of the current face could result in > applying another, lower-priority face specified by font-locking and > consult the extend_background bit of the corresponding realized face. I don't think I understand this proposal. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-28 9:07 ` Eli Zaretskii @ 2019-08-28 12:19 ` martin rudalics 2019-08-28 16:31 ` Ergus 2019-08-28 17:21 ` Eli Zaretskii 0 siblings, 2 replies; 183+ messages in thread From: martin rudalics @ 2019-08-28 12:19 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel > I think we should simply not merge the background color of the region > face when its extend bit is reset. Then the merged face will not have > that background color. Then which background color would we use? That of the comment was lost when setting up the current face for the iterator. > I don't see a problem here. A user who doesn't want the region face's > background extend to the end of line wants only text (as opposed to > whitespace after the newline) to have the region's background, and > that's true both to regions that cross line boundaries and regions that > end at a newline. I agree that we don't want to extend the region's background. But the question I raised above still stands. We could make :extend sticky in the sense that once an :extend for the background has been defined, it will apply to all higher priority faces as well. This would make specifying a nil :extend value idempotent to not specifying a value at all as you (IIRC) proposed earlier. But the mechanism then becomes considerably less powerful. >> Maybe the display engine could consult, with the stop position >> privilege triggered by the newline character in mind, whether the >> extend_background false setting of the current face could result in >> applying another, lower-priority face specified by font-locking and >> consult the extend_background bit of the corresponding realized face. > > I don't think I understand this proposal. Let's talk about it when we both see a problem here. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-28 12:19 ` martin rudalics @ 2019-08-28 16:31 ` Ergus 2019-08-28 17:24 ` Eli Zaretskii 2019-08-29 7:45 ` martin rudalics 2019-08-28 17:21 ` Eli Zaretskii 1 sibling, 2 replies; 183+ messages in thread From: Ergus @ 2019-08-28 16:31 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Wed, Aug 28, 2019 at 02:19:03PM +0200, martin rudalics wrote: >> I think we should simply not merge the background color of the region >> face when its extend bit is reset. Then the merged face will not have >> that background color. > >Then which background color would we use? That of the comment was >lost when setting up the current face for the iterator. > >> I don't see a problem here. A user who doesn't want the region face's >> background extend to the end of line wants only text (as opposed to >> whitespace after the newline) to have the region's background, and >> that's true both to regions that cross line boundaries and regions that >> end at a newline. > >I agree that we don't want to extend the region's background. But the >question I raised above still stands. > >We could make :extend sticky in the sense that once an :extend for the >background has been defined, it will apply to all higher priority faces >as well. This would make specifying a nil :extend value idempotent to >not specifying a value at all as you (IIRC) proposed earlier. But the >mechanism then becomes considerably less powerful. > Any way my question comes from 2 frequent use cases I don't know what's the expected behavior: 1) Base face sets background and extend; and face sets only background. 2) Base face sets extend but not background; and face sets both. in what condition the :extend attribute goes to the merged face? Always? when in base_face? When in face? in what condition the extend_element bits are reset after a merge? >>> Maybe the display engine could consult, with the stop position >>> privilege triggered by the newline character in mind, whether the >>> extend_background false setting of the current face could result in >>> applying another, lower-priority face specified by font-locking and >>> consult the extend_background bit of the corresponding realized face. >> >> I don't think I understand this proposal. > >Let's talk about it when we both see a problem here. > >martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-28 16:31 ` Ergus @ 2019-08-28 17:24 ` Eli Zaretskii 2019-08-28 18:19 ` Ergus 2019-08-29 7:45 ` martin rudalics 1 sibling, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-28 17:24 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Wed, 28 Aug 2019 18:31:42 +0200 > From: Ergus <spacibba@aol.com> > Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org > > Any way my question comes from 2 frequent use cases I don't know what's > the expected behavior: > > 1) Base face sets background and extend; and face sets only background. The background of the base face will be extended. > 2) Base face sets extend but not background; and face sets both. The background of the face will be extended. > in what condition the :extend attribute goes to the merged face? Always? > when in base_face? When in face? The :extend attribute determines whether the background color of the face with that attribute does or doesn't get merged into the "merged face" to be used by the iterator. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-28 17:24 ` Eli Zaretskii @ 2019-08-28 18:19 ` Ergus 2019-08-29 18:28 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-08-28 18:19 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel On Wed, Aug 28, 2019 at 08:24:26PM +0300, Eli Zaretskii wrote: >> Date: Wed, 28 Aug 2019 18:31:42 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org >> >> Any way my question comes from 2 frequent use cases I don't know what's >> the expected behavior: >> >> 1) Base face sets background and extend; and face sets only background. > >The background of the base face will be extended. > But AFAIU the actual merging rules now will create a new face (if not there already) that will have the new background; so this means that then we need a way to remember the last background color where background and extend where set at the same time; so the extend flag will be not a bool flag, but a pointer (or a copy) to a previous point (value) in the faces stack?? Then at the last step of the merge we could potentially have N exact equal faces that only have difference in those points. >> 2) Base face sets extend but not background; and face sets both. > >The background of the face will be extended. > >> in what condition the :extend attribute goes to the merged face? Always? >> when in base_face? When in face? > >The :extend attribute determines whether the background color of the >face with that attribute does or doesn't get merged into the "merged >face" to be used by the iterator. > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-28 18:19 ` Ergus @ 2019-08-29 18:28 ` Eli Zaretskii 2019-08-30 7:02 ` martin rudalics 2019-08-30 9:34 ` Ergus 0 siblings, 2 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-29 18:28 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Wed, 28 Aug 2019 20:19:58 +0200 > From: Ergus <spacibba@aol.com> > Cc: rudalics@gmx.at, emacs-devel@gnu.org > > >> 1) Base face sets background and extend; and face sets only background. > > > >The background of the base face will be extended. > > > > But AFAIU the actual merging rules now will create a new face (if not > there already) that will have the new background No. At the point which we are discussing, only background of faces which have the :extend bit set get merged. So the background of a face without that bit will simply not get merged. You will probably need to write a variant of merge_face_ref (or add an extra argument to the existing function) such that background color attribute of a face is not merged unless the :extend bit of the face is set; and similar for underline and other relevant attributes we discussed. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-29 18:28 ` Eli Zaretskii @ 2019-08-30 7:02 ` martin rudalics 2019-08-30 7:26 ` Eli Zaretskii 2019-08-30 9:34 ` Ergus 1 sibling, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-30 7:02 UTC (permalink / raw) To: Eli Zaretskii, Ergus; +Cc: emacs-devel >> But AFAIU the actual merging rules now will create a new face (if not >> there already) that will have the new background > > No. At the point which we are discussing, only background of faces > which have the :extend bit set get merged. So the background of a > face without that bit will simply not get merged. It will have to get merged for text that appears _before_ the newline character. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-30 7:02 ` martin rudalics @ 2019-08-30 7:26 ` Eli Zaretskii 0 siblings, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-30 7:26 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Fri, 30 Aug 2019 09:02:54 +0200 > > >> But AFAIU the actual merging rules now will create a new face (if not > >> there already) that will have the new background > > > > No. At the point which we are discussing, only background of faces > > which have the :extend bit set get merged. So the background of a > > face without that bit will simply not get merged. > > It will have to get merged for text that appears _before_ the newline > character. For the text before the newline, the :extend bit is ignored when merging faces. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-29 18:28 ` Eli Zaretskii 2019-08-30 7:02 ` martin rudalics @ 2019-08-30 9:34 ` Ergus 1 sibling, 0 replies; 183+ messages in thread From: Ergus @ 2019-08-30 9:34 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel Sorry Eli I still don't see anything clear. It seems that only you have enough knowledge to understand how this solution may work. Because I am missing a lot of details. I will actually stop trying, because I can't implement something I don't understand how it works and I am wasting a precious amount of time. On Thu, Aug 29, 2019 at 09:28:55PM +0300, Eli Zaretskii wrote: >> Date: Wed, 28 Aug 2019 20:19:58 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: rudalics@gmx.at, emacs-devel@gnu.org >> >> >> 1) Base face sets background and extend; and face sets only background. >> > >> >The background of the base face will be extended. >> > >> >> But AFAIU the actual merging rules now will create a new face (if not >> there already) that will have the new background > >No. At the point which we are discussing, only background of faces >which have the :extend bit set get merged. So the background of a >face without that bit will simply not get merged. > >You will probably need to write a variant of merge_face_ref (or add an >extra argument to the existing function) such that background color >attribute of a face is not merged unless the :extend bit of the face >is set; and similar for underline and other relevant attributes we >discussed. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-28 16:31 ` Ergus 2019-08-28 17:24 ` Eli Zaretskii @ 2019-08-29 7:45 ` martin rudalics 1 sibling, 0 replies; 183+ messages in thread From: martin rudalics @ 2019-08-29 7:45 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel > Any way my question comes from 2 frequent use cases I don't know what's > the expected behavior: > > 1) Base face sets background and extend; and face sets only background. > > 2) Base face sets extend but not background; and face sets both. > > in what condition the :extend attribute goes to the merged face? Always? > when in base_face? When in face? Assuming that "base face" is merged in before "face", both should conceptually expand face. The problematic case is Base face sets background and extend to t; and face sets background to t and extend to nil. In this case merge should provide to show normal text with face but extend the background of the basic face. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-28 12:19 ` martin rudalics 2019-08-28 16:31 ` Ergus @ 2019-08-28 17:21 ` Eli Zaretskii 2019-08-29 7:45 ` martin rudalics 1 sibling, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-28 17:21 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Wed, 28 Aug 2019 14:19:03 +0200 > > > I think we should simply not merge the background color of the region > > face when its extend bit is reset. Then the merged face will not have > > that background color. > > Then which background color would we use? That of the comment was > lost when setting up the current face for the iterator. The one that was there before the region was activated. Which one is that will be determined by the order in which the merging process merges the faces, and by the faces themselves -- whether they do or don't define a background color, and whether they do or don't have the :extend bit set. > > I don't see a problem here. A user who doesn't want the region face's > > background extend to the end of line wants only text (as opposed to > > whitespace after the newline) to have the region's background, and > > that's true both to regions that cross line boundaries and regions that > > end at a newline. > > I agree that we don't want to extend the region's background. But the > question I raised above still stands. Did I answer it now? > We could make :extend sticky in the sense that once an :extend for the > background has been defined, it will apply to all higher priority faces > as well. This would make specifying a nil :extend value idempotent to > not specifying a value at all as you (IIRC) proposed earlier. But the > mechanism then becomes considerably less powerful. I don't think this will be needed, or even desirable. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-28 17:21 ` Eli Zaretskii @ 2019-08-29 7:45 ` martin rudalics 2019-08-29 18:36 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-29 7:45 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel >> > I think we should simply not merge the background color of the region >> > face when its extend bit is reset. Then the merged face will not have >> > that background color. >> >> Then which background color would we use? That of the comment was >> lost when setting up the current face for the iterator. > > The one that was there before the region was activated. But where do we get that from? Consider a three lines C buffer with code on the first line and a two-line comment covering the remaining lines with the region covering the entire buffer. Hence, the spaces following the comment on the second line should be drawn with the background of the comment face. But when the display engine gets there, the respective face was not even realized. > Which one is > that will be determined by the order in which the merging process > merges the faces, and by the faces themselves -- whether they do or > don't define a background color, and whether they do or don't have the > :extend bit set. The merging process will kick in iff we treat the newline character at the end of line 2 as a stop position. Since no text property changes there, I don't see how this could happen. The only stop position in this buffer (apart from its beginning and end) is where the comment starts on line 2. >> I agree that we don't want to extend the region's background. But the >> question I raised above still stands. > > Did I answer it now? If so, I didn't understand the answer yet. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-29 7:45 ` martin rudalics @ 2019-08-29 18:36 ` Eli Zaretskii 2019-08-30 7:03 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-29 18:36 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Thu, 29 Aug 2019 09:45:50 +0200 > > >> > I think we should simply not merge the background color of the region > >> > face when its extend bit is reset. Then the merged face will not have > >> > that background color. > >> > >> Then which background color would we use? That of the comment was > >> lost when setting up the current face for the iterator. > > > > The one that was there before the region was activated. > > But where do we get that from? It will come out automatically from the face merging process. > Consider a three lines C buffer with > code on the first line and a two-line comment covering the remaining > lines with the region covering the entire buffer. Hence, the spaces > following the comment on the second line should be drawn with the > background of the comment face. The comment face doesn't have a background, btw. And for a good reason. But I digress. Maybe. > But when the display engine gets there, the respective face was not > even realized. It will be realized when the display engine comes to that place. That's exactly what we have been talking about here, right? Or maybe I don't understand what difficulty you are seeing there. > > Which one is > > that will be determined by the order in which the merging process > > merges the faces, and by the faces themselves -- whether they do or > > don't define a background color, and whether they do or don't have the > > :extend bit set. > > The merging process will kick in iff we treat the newline character at > the end of line 2 as a stop position. Since no text property changes > there, I don't see how this could happen. It will happen because we call append_space_for_newline and extend_face_to_end_of_line, and those functions _know_ they are at end of a line. > >> I agree that we don't want to extend the region's background. But the > >> question I raised above still stands. > > > > Did I answer it now? > > If so, I didn't understand the answer yet. Maybe I don't understand the question, because I see no problems here. Just coding. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-29 18:36 ` Eli Zaretskii @ 2019-08-30 7:03 ` martin rudalics 2019-08-30 8:48 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-30 7:03 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel >> But where do we get that from? > > It will come out automatically from the face merging process. You told me before and I'm still afraid that no such automatism exists. >> But when the display engine gets there, the respective face was not >> even realized. > > It will be realized when the display engine comes to that place. > That's exactly what we have been talking about here, right? Or maybe > I don't understand what difficulty you are seeing there. But then "realizing" the face for the spaces at the end of line becomes much harder: The display engine has to handle _every newline_ in every buffer as _if it were a stop position_ in order to merge all faces at that position and find out which background to use. >> The merging process will kick in iff we treat the newline character at >> the end of line 2 as a stop position. Since no text property changes >> there, I don't see how this could happen. > > It will happen because we call append_space_for_newline and > extend_face_to_end_of_line, and those functions _know_ they are at end > of a line. But they would still have to fully realize the face to use by merging all faces at each newline. This means we can do away with all those precalculated extend_background, extend_... bits because they cease to contribute anything to the solution. The only practical solution I see is to, instead of extend_background bits, use extend_background colors. In my example, this would mean that when, at the stop position prescribed by the comment start text property change, the face merger sets the background value of the face to realize to that of the region and the extend_background value of the face to realize to that of the comment. The display engine would then realize the face for writing the remainder of the line right from extend_background instead of from background + extend_background. > Maybe I don't understand the question, because I see no problems > here. Just coding. Maybe you're right. But I still don't see the light at the end of this tunnel. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-30 7:03 ` martin rudalics @ 2019-08-30 8:48 ` Eli Zaretskii 2019-08-31 7:29 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-30 8:48 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Fri, 30 Aug 2019 09:03:06 +0200 > > >> But where do we get that from? > > > > It will come out automatically from the face merging process. > > You told me before and I'm still afraid that no such automatism > exists. It happens as part of face merging. The attribute that doesn't get merged causes the same attribute of another face to become the attribute of the merged face. > >> But when the display engine gets there, the respective face was not > >> even realized. > > > > It will be realized when the display engine comes to that place. > > That's exactly what we have been talking about here, right? Or maybe > > I don't understand what difficulty you are seeing there. > > But then "realizing" the face for the spaces at the end of line > becomes much harder: The display engine has to handle _every newline_ > in every buffer as _if it were a stop position_ in order to merge all > faces at that position and find out which background to use. I thought we already agreed that there's no other way of having this feature than to realize a face at each EOL. > >> The merging process will kick in iff we treat the newline character at > >> the end of line 2 as a stop position. Since no text property changes > >> there, I don't see how this could happen. > > > > It will happen because we call append_space_for_newline and > > extend_face_to_end_of_line, and those functions _know_ they are at end > > of a line. > > But they would still have to fully realize the face to use by merging > all faces at each newline. This means we can do away with all those > precalculated extend_background, extend_... bits because they cease to > contribute anything to the solution. I don't think I understand what the "precalculated" part refers to. > The only practical solution I see is to, instead of extend_background > bits, use extend_background colors. In my example, this would mean > that when, at the stop position prescribed by the comment start text > property change, the face merger sets the background value of the face > to realize to that of the region and the extend_background value of > the face to realize to that of the comment. The display engine would > then realize the face for writing the remainder of the line right from > extend_background instead of from background + extend_background. I don't see how this will help anything. To remind you: the display engine manipulates face IDs, it doesn't know anything about the faces themselves, and in particular cannot magically exchange a face's background color for some other color. > > Maybe I don't understand the question, because I see no problems > > here. Just coding. > > Maybe you're right. But I still don't see the light at the end of > this tunnel. I don't think I see the tunnel. I thought the issue was resolved when you posted your summary up-thread. What am I missing? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-30 8:48 ` Eli Zaretskii @ 2019-08-31 7:29 ` martin rudalics 2019-08-31 7:57 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-31 7:29 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel > I thought we already agreed that there's no other way of having this > feature than to realize a face at each EOL. Then that's where we have been miscommunicating. The whole idea behind the extend_background, extend_underline, ... bits was to avoid the full handle_stop rigmarole at EOL, like finding the overlays and text properties and processing them in the right order. All this was already done at the last "real" stop position encountered by the display engine and has not changed since then. The only missing step is to process the :extend attribute of any face merged. For the normal background, this is the value of the :background attribute of the last face that specified that attribute and was merged in. For the extended background this is the value of the :background attribute of the last face that specified that attribute, had the :extend attribute set and was merged in. To put this into praxis, the face merger would maintain a shadow copy of the background value. That shadow value would not get overwritten when merging in the :background attribute of a face that does not have the :extend attribute set. Eventually, we would wind up with two, possibly distinct values of the background to realize - one for the normal and the shadow value for the extended background. If we wanted to realize both faces - the one to use for the current face and the one to use for extension - immediately (eagerly as I coined it earlier), we could do that right after merging terminates. We probably would set up a pointer to the realized face to use for extension, so the iterator, when arriving at EOL, would find it right away and make it current. That's all. But we probably don't want to realize the face to use for extension immediately and do it - as we agreed earlier - lazily when the iterator arrives at EOL. In my region/comment example, the comment could have terminated before or at the EOL where it started, resulting in a new stop position and we would have needlessly realized an extended face. Initially, that's where I wanted the extend_background etc. bits to kick in, just that I wrongly thought that filling the end of the line with the background of the default face would be sufficient ... Note: We could also try to find out whether there _is_ another stop position before the next EOL after merging faces and, if there's none, realize the extended face eagerly, but I'm not sure whether this idea can be incorporated easily. >> But they would still have to fully realize the face to use by merging >> all faces at each newline. This means we can do away with all those >> precalculated extend_background, extend_... bits because they cease to >> contribute anything to the solution. > > I don't think I understand what the "precalculated" part refers to. Is it clear from what I wrote above? The extend_background, ... bits would remember the precalculated differences between the attributes used for normal text and those for the extensions. >> The only practical solution I see is to, instead of extend_background >> bits, use extend_background colors. In my example, this would mean >> that when, at the stop position prescribed by the comment start text >> property change, the face merger sets the background value of the face >> to realize to that of the region and the extend_background value of >> the face to realize to that of the comment. The display engine would >> then realize the face for writing the remainder of the line right from >> extend_background instead of from background + extend_background. > > I don't see how this will help anything. To remind you: the display > engine manipulates face IDs, it doesn't know anything about the faces > themselves, and in particular cannot magically exchange a face's > background color for some other color. But it knows where the background of a realized face is stored and could easily realize a new face which is the same but for a different background swapped in. Hardly rocket science for the display engine. So what we could do is to simply maintain a vector of the values for background, underline, etc. calculated at the last real stop position and whenever the display engine encounters a newline, realize a face with the values of that vector replacing the current values, use that face for the spaces at the rest of the line, and restore the old face for the normal text on the next line (unless we have several newlines in a row and similar optimizations). > I don't think I see the tunnel. I thought the issue was resolved when > you posted your summary up-thread. What am I missing? When you saw my proposal to use a number of extend_background, extend_underline, ... bits, your crystal ball should have complained that multiple bits are useless because we would have to realize a new face anyway at EOL. A single flag (if at all) could have been set by the face merger to detect the case where an attribute without the :extend attribute set overwrote an attribute with the :extend attribute set. In my region/comment example this would have happened where the no-extend :background of the region face overwrote the extend :background of the comment face. The display engine, whenever it encountered the flag set at EOL, would have triggered a new face merge (and avoided it otherwise). That single flag approach wouldn't penalize the display engine if attributes were extended by default. In that case, the re-merging step at EOL would be needed only in cases as used in my region/comment example. But if, as Ergus requested earlier, we did _not_ want to extend attributes by default, the re-merge penalty would practically happen at each EOL. BTW: One problem with Ergus' proposal is that hacks like the one proposed for Bug#15934 won't work any more. For that bug, we could obviously set the :extend attribute of the respective highlight line face but all instances in the wild using the same hack already would be affected by our change. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-31 7:29 ` martin rudalics @ 2019-08-31 7:57 ` Eli Zaretskii 2019-09-01 8:14 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-31 7:57 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Sat, 31 Aug 2019 09:29:13 +0200 > > > I thought we already agreed that there's no other way of having this > > feature than to realize a face at each EOL. > > Then that's where we have been miscommunicating. The whole idea > behind the extend_background, extend_underline, ... bits was to avoid > the full handle_stop rigmarole at EOL, like finding the overlays and > text properties and processing them in the right order. We don't need everything from handle_stop, we only need the parts that affect the face. > The only missing step is to process the :extend attribute of any face > merged. For the normal background, this is the value of the > :background attribute of the last face that specified that attribute > and was merged in. For the extended background this is the value of > the :background attribute of the last face that specified that > attribute, had the :extend attribute set and was merged in. > > To put this into praxis, the face merger would maintain a shadow copy > of the background value. That shadow value would not get overwritten > when merging in the :background attribute of a face that does not have > the :extend attribute set. Eventually, we would wind up with two, > possibly distinct values of the background to realize - one for the > normal and the shadow value for the extended background. The face merger doesn't maintain any state, so I don't think this is easily done. > If we wanted to realize both faces - the one to use for the current > face and the one to use for extension - immediately (eagerly as I > coined it earlier), we could do that right after merging terminates. > We probably would set up a pointer to the realized face to use for > extension, so the iterator, when arriving at EOL, would find it right > away and make it current. That's all. > > But we probably don't want to realize the face to use for extension > immediately and do it - as we agreed earlier - lazily when the > iterator arrives at EOL. If lazy realization is hard to implement, there's nothing wrong with realizing both faces immediately, at each stop position. > Note: We could also try to find out whether there _is_ another stop > position before the next EOL after merging faces and, if there's none, > realize the extended face eagerly, but I'm not sure whether this idea > can be incorporated easily. Right. > > I don't see how this will help anything. To remind you: the display > > engine manipulates face IDs, it doesn't know anything about the faces > > themselves, and in particular cannot magically exchange a face's > > background color for some other color. > > But it knows where the background of a realized face is stored and > could easily realize a new face which is the same but for a different > background swapped in. Hardly rocket science for the display engine. If we extend faces to keep the information about how to do that, then yes, this can be done. > So what we could do is to simply maintain a vector of the values for > background, underline, etc. calculated at the last real stop position > and whenever the display engine encounters a newline, realize a face > with the values of that vector replacing the current values, use that > face for the spaces at the rest of the line, and restore the old face > for the normal text on the next line (unless we have several newlines > in a row and similar optimizations). That's possible, assuming faces are extended as mentioned above. But I'm not sure realizing both faces immediately ("eagerly") will not be an easier solution. > BTW: One problem with Ergus' proposal is that hacks like the one > proposed for Bug#15934 won't work any more. For that bug, we could > obviously set the :extend attribute of the respective highlight line > face but all instances in the wild using the same hack already would > be affected by our change. Yes, of course. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-31 7:57 ` Eli Zaretskii @ 2019-09-01 8:14 ` martin rudalics 2019-09-01 12:26 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-01 8:14 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel >> To put this into praxis, the face merger would maintain a shadow copy >> of the background value. That shadow value would not get overwritten >> when merging in the :background attribute of a face that does not have >> the :extend attribute set. Eventually, we would wind up with two, >> possibly distinct values of the background to realize - one for the >> normal and the shadow value for the extended background. > > The face merger doesn't maintain any state, so I don't think this is > easily done. The background would be stored in an extend_background slot of the face vector (or maybe even a separate extend_vector) which would contain the part of the state responsible for handling the background. >> Note: We could also try to find out whether there _is_ another stop >> position before the next EOL after merging faces and, if there's none, >> realize the extended face eagerly, but I'm not sure whether this idea >> can be incorporated easily. > > Right. IIUC next_interval is newline agnostic. The 'auto-composition-mode' check does look for a newline within the next 1000 characters (around line 3761 of xdisp.c) so we maybe could use that. >> BTW: One problem with Ergus' proposal is that hacks like the one >> proposed for Bug#15934 won't work any more. For that bug, we could >> obviously set the :extend attribute of the respective highlight line >> face but all instances in the wild using the same hack already would >> be affected by our change. > > Yes, of course. So we should probably provide a :no-extend attribute, extend face attributes by default and explicitly not extend some attributes like underline and box. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-01 8:14 ` martin rudalics @ 2019-09-01 12:26 ` Ergus 2019-09-02 8:36 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-01 12:26 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel Hi Marting and Eli: I have been thinking about this a little bit more and it seems like we are trying to replicate a behavior that is already there. If we had an extra face pointer within the face struct initialized to null (or default face), and then when we merge and the extend attribute is set we initialize it to the current merged face and we transmit that pointer from merge to merge until we have a new face with :extend, so we merge then those two... I think when we reach the end of the line we will have there already all the information we need. Lets say we have a sequence of consecutive merges (a,b,c,d,e); but only b and d have :extend. At the end we will have in the merges: (a, a+b, a+b+c, a+b+c+d, a+b+c+d+e) but with this pointers in them: (nul, b, b, b + d, b + d) Which for me it seems to be what we expect to have right? Does it makes sense? On Sun, Sep 01, 2019 at 10:14:06AM +0200, martin rudalics wrote: >>> To put this into praxis, the face merger would maintain a shadow copy >>> of the background value. That shadow value would not get overwritten >>> when merging in the :background attribute of a face that does not have >>> the :extend attribute set. Eventually, we would wind up with two, >>> possibly distinct values of the background to realize - one for the >>> normal and the shadow value for the extended background. >> >> The face merger doesn't maintain any state, so I don't think this is >> easily done. > >The background would be stored in an extend_background slot of the >face vector (or maybe even a separate extend_vector) which would >contain the part of the state responsible for handling the background. > >>> Note: We could also try to find out whether there _is_ another stop >>> position before the next EOL after merging faces and, if there's none, >>> realize the extended face eagerly, but I'm not sure whether this idea >>> can be incorporated easily. >> >> Right. > >IIUC next_interval is newline agnostic. The 'auto-composition-mode' >check does look for a newline within the next 1000 characters (around >line 3761 of xdisp.c) so we maybe could use that. > >>> BTW: One problem with Ergus' proposal is that hacks like the one >>> proposed for Bug#15934 won't work any more. For that bug, we could >>> obviously set the :extend attribute of the respective highlight line >>> face but all instances in the wild using the same hack already would >>> be affected by our change. >> >> Yes, of course. > >So we should probably provide a :no-extend attribute, extend face >attributes by default and explicitly not extend some attributes like >underline and box. > >martin > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-01 12:26 ` Ergus @ 2019-09-02 8:36 ` martin rudalics 2019-09-02 11:05 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-02 8:36 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel > I have been thinking about this a little bit more and it seems like we > are trying to replicate a behavior that is already there. > > If we had an extra face pointer within the face struct initialized to > null (or default face), and then when we merge and the extend attribute is set we > initialize it to the current merged face and we transmit that pointer > from merge to merge until we have a new face with :extend, so we merge > then those two... I think when we reach the end of the line we will > have there already all the information we need. > > Lets say we have a sequence of consecutive merges (a,b,c,d,e); but only > b and d have :extend. > > At the end we will have in the merges: > > (a, a+b, a+b+c, a+b+c+d, a+b+c+d+e) > > but with this pointers in them: > > (nul, b, b, b + d, b + d) > > Which for me it seems to be what we expect to have right? > > Does it makes sense? I think so. Now the realized face for normal text is a+b+c+d+e and the display engine would use it right away. When the display engine encounters a newline character it has to "switch" from a+b+c+d+e to b+d. But it has to assure that b+d _is a realized face_ because a reference to that face is the output expected from the display engine. Any additional pointers like yours would be ignored after that. Do you agree so far? If so, then the question remains _when_ to realize b+d. Eagerly, when the face merger has done its work, or lazily when the display engine encounters the newline. Eagerly has the advantage that the display engine has all the faces already realized. Its disadvantage is that when a new stop position is found before the EOL, the b+d face was realized needlessly. Do you still agree? If so then we might consider the following optimization: The extra face pointer in each face is no more needed after the display engine has processed the face. So we could build a "shadow" face for b+d, keep it in a separate, static face structure and realize a face from that structure whenever we want to (eagerly or lazily). The display engine, when it finds a pointer to such an extra face at EOL, uses it (maybe realizing it on the fly). Also, the merger could nullify the extra face if it's the same as the normal one, that is no single merge step had an :extend false value override a former :extend true value. So the display engine would know beforehand that it does not have to change the current face. Last but not least, the display engine has to, after processing the spaces at the EOL from b+d, restore the a+b+c+d+e face as its current face. So we have two static pointers to keep around: One for the b+d face structure (or its already realized face) while the display engine processes normal text and one for the a+b+c+d+e realized face while the display engine processes the spaces at EOL. Can you still agree? Can you imagine any difficulties with implementing such an approach? And we would have happily put to rest all those crazy extend_... bits I proposed earlier. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-02 8:36 ` martin rudalics @ 2019-09-02 11:05 ` Ergus 2019-09-02 16:18 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-02 11:05 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Mon, Sep 02, 2019 at 10:36:34AM +0200, martin rudalics wrote: >> I have been thinking about this a little bit more and it seems like we >> are trying to replicate a behavior that is already there. >> >> If we had an extra face pointer within the face struct initialized to >> null (or default face), and then when we merge and the extend attribute is set we >> initialize it to the current merged face and we transmit that pointer >> from merge to merge until we have a new face with :extend, so we merge >> then those two... I think when we reach the end of the line we will >> have there already all the information we need. >> >> Lets say we have a sequence of consecutive merges (a,b,c,d,e); but only >> b and d have :extend. >> >> At the end we will have in the merges: >> >> (a, a+b, a+b+c, a+b+c+d, a+b+c+d+e) >> >> but with this pointers in them: >> >> (nul, b, b, b + d, b + d) >> >> Which for me it seems to be what we expect to have right? >> >> Does it makes sense? > >I think so. Now the realized face for normal text is a+b+c+d+e and >the display engine would use it right away. When the display engine >encounters a newline character it has to "switch" from a+b+c+d+e to >b+d. But it has to assure that b+d _is a realized face_ because a >reference to that face is the output expected from the display engine. >Any additional pointers like yours would be ignored after that. > >Do you agree so far? If so, then the question remains _when_ to >realize b+d. Eagerly, when the face merger has done its work, or >lazily when the display engine encounters the newline. Eagerly has >the advantage that the display engine has all the faces already >realized. Its disadvantage is that when a new stop position is found >before the EOL, the b+d face was realized needlessly. Do you still >agree? > I think any of them is still a good trade-off because it is very use-case specific. When coding and with the actual wide screens; in most of the cases the lines are always extended, So I don't think there will be a significant difference. In any case we could implement any of them more or less with the same complexity... > >If so then we might consider the following optimization: The extra >face pointer in each face is no more needed after the display engine >has processed the face. So we could build a "shadow" face for b+d, >keep it in a separate, static face structure and realize a face from >that structure whenever we want to (eagerly or lazily). The display >engine, when it finds a pointer to such an extra face at EOL, uses it >(maybe realizing it on the fly). > >Also, the merger could nullify the extra face if it's the same as the >normal one, that is no single merge step had an :extend false value >override a former :extend true value. So the display engine would >know beforehand that it does not have to change the current face. > Yes; in my initial proposed approach the local pointer will be null in that case. >Last but not least, the display engine has to, after processing the >spaces at the EOL from b+d, restore the a+b+c+d+e face as its current >face. So we have two static pointers to keep around: One for the b+d >face structure (or its already realized face) while the display engine >processes normal text and one for the a+b+c+d+e realized face while >the display engine processes the spaces at EOL. Can you still agree? In the display engine we do this very frequently. As extend_face_to_end_of_line is very localized we just need to save a pointer to a+b+c+d on the beginning of the function and restore it at the end. It is a bit more complex than that because the code for gui and TUI is in different portions of an if condition, but this part is almost the same I made in the first patch I proposed. >Can you imagine any difficulties with implementing such an approach? > I only see small details like that in some cases we need to reinitialize the extend face and the default-face value maybe is not the right choice in all the cases (I need to look into it a bit more). And that in X there is some extra code (somewhere) to extend the background color using the color in the last inserted glyph (it is something happening by default without calling even extend_face_to_end_of_line). That code should be removed after this change; but I don't know where is it. But for sure Eli will tell. >And we would have happily put to rest all those crazy extend_... bits >I proposed earlier. > >martin > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-02 11:05 ` Ergus @ 2019-09-02 16:18 ` Eli Zaretskii 2019-09-03 5:33 ` Ergus ` (2 more replies) 0 siblings, 3 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-09-02 16:18 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Mon, 2 Sep 2019 13:05:04 +0200 > From: Ergus <spacibba@aol.com> > Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org > > >If so then we might consider the following optimization: The extra > >face pointer in each face is no more needed after the display engine > >has processed the face. So we could build a "shadow" face for b+d, > >keep it in a separate, static face structure and realize a face from > >that structure whenever we want to (eagerly or lazily). The display > >engine, when it finds a pointer to such an extra face at EOL, uses it > >(maybe realizing it on the fly). > > > >Also, the merger could nullify the extra face if it's the same as the > >normal one, that is no single merge step had an :extend false value > >override a former :extend true value. So the display engine would > >know beforehand that it does not have to change the current face. > > > Yes; in my initial proposed approach the local pointer will be null in > that case. I don't think I understand why you are talking about face pointers. The iterator doesn't keep any face pointers, it keeps face IDs (which allow to obtain the face pointer, when needed, by using FACE_FROM_ID). So all you need is to have another face ID member in the iterator, to be used for extending past EOL; depending on how the :extend bits are set, that face ID may or may not be identical to the "normal" face ID, the one we have now and use for buffer text. > >Last but not least, the display engine has to, after processing the > >spaces at the EOL from b+d, restore the a+b+c+d+e face as its current > >face. So we have two static pointers to keep around: One for the b+d > >face structure (or its already realized face) while the display engine > >processes normal text and one for the a+b+c+d+e realized face while > >the display engine processes the spaces at EOL. Can you still agree? > > In the display engine we do this very > frequently. As extend_face_to_end_of_line is very localized we just need > to save a pointer to a+b+c+d on the beginning of the function and > restore it at the end. Again, not a pointer: a face ID. And yes, we have saved_face_id member of the iterator for this purpose. > And that in X there is some extra code (somewhere) to extend the > background color using the color in the last inserted glyph (it is > something happening by default without calling even > extend_face_to_end_of_line). That code should be removed after this > change; but I don't know where is it. But for sure Eli will tell. It's just that we clear to EOL with the last background color, and avoid doing that if the background color is identical to the frame's background. I don't think anything will have to be changed there, but we will see (I hope). ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-02 16:18 ` Eli Zaretskii @ 2019-09-03 5:33 ` Ergus 2019-09-03 8:45 ` martin rudalics 2019-09-03 5:35 ` Ergus via Emacs development discussions. 2019-09-03 8:45 ` martin rudalics 2 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-03 5:33 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel Hi Eli and martin. Here I attach a patch minimal proof of concept for the last solution I proposed. At the moment it is not showing the color extension to the end of the line, but I cannot make it extend because it seems like the merge function I added is never executed (which makes no sense but it does not print the messages I added with printf.) Could any of you give a look to the patch to detect what is failing at least to triger the merge and extend? Probably the initialization. (which btw the lisp glue code may be buggy for sure.) Please, any help is very welcome. On Mon, Sep 02, 2019 at 07:18:19PM +0300, Eli Zaretskii wrote: >> Date: Mon, 2 Sep 2019 13:05:04 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org >> >> >If so then we might consider the following optimization: The extra >> >face pointer in each face is no more needed after the display engine >> >has processed the face. So we could build a "shadow" face for b+d, >> >keep it in a separate, static face structure and realize a face from >> >that structure whenever we want to (eagerly or lazily). The display >> >engine, when it finds a pointer to such an extra face at EOL, uses it >> >(maybe realizing it on the fly). >> > >> >Also, the merger could nullify the extra face if it's the same as the >> >normal one, that is no single merge step had an :extend false value >> >override a former :extend true value. So the display engine would >> >know beforehand that it does not have to change the current face. >> > >> Yes; in my initial proposed approach the local pointer will be null in >> that case. > >I don't think I understand why you are talking about face pointers. >The iterator doesn't keep any face pointers, it keeps face IDs (which >allow to obtain the face pointer, when needed, by using FACE_FROM_ID). > >So all you need is to have another face ID member in the iterator, to >be used for extending past EOL; depending on how the :extend bits are >set, that face ID may or may not be identical to the "normal" face ID, >the one we have now and use for buffer text. > >> >Last but not least, the display engine has to, after processing the >> >spaces at the EOL from b+d, restore the a+b+c+d+e face as its current >> >face. So we have two static pointers to keep around: One for the b+d >> >face structure (or its already realized face) while the display engine >> >processes normal text and one for the a+b+c+d+e realized face while >> >the display engine processes the spaces at EOL. Can you still agree? >> >> In the display engine we do this very >> frequently. As extend_face_to_end_of_line is very localized we just need >> to save a pointer to a+b+c+d on the beginning of the function and >> restore it at the end. > >Again, not a pointer: a face ID. And yes, we have saved_face_id >member of the iterator for this purpose. > >> And that in X there is some extra code (somewhere) to extend the >> background color using the color in the last inserted glyph (it is >> something happening by default without calling even >> extend_face_to_end_of_line). That code should be removed after this >> change; but I don't know where is it. But for sure Eli will tell. > >It's just that we clear to EOL with the last background color, and >avoid doing that if the background color is identical to the frame's >background. I don't think anything will have to be changed there, but >we will see (I hope). > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-03 5:33 ` Ergus @ 2019-09-03 8:45 ` martin rudalics 2019-09-03 11:23 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-03 8:45 UTC (permalink / raw) To: Ergus, Eli Zaretskii; +Cc: emacs-devel > Could any of you give a look to the patch I cannot build Emacs on Windows with the patch due to CC w32select.o ../../src/w32term.c: In function 'w32_draw_glyph_string': ../../src/w32term.c:2482:20: error: 'struct face' has no member named 'underline_p'; did you mean 'underline'? if (s->face->underline_p) ^~~~~~~~~~~ underline ../../src/w32term.c:2484:24: error: 'struct face' has no member named 'underline_type'; did you mean 'underline_color'? if (s->face->underline_type == FACE_UNDER_WAVE) ^~~~~~~~~~~~~~ underline_color ../../src/w32term.c:2495:29: error: 'struct face' has no member named 'underline_type'; did you mean 'underline_color'? else if (s->face->underline_type == FACE_UNDER_LINE) ^~~~~~~~~~~~~~ underline_color ../../src/w32term.c:2500:45: error: 'struct face' has no member named 'underline_p'; did you mean 'underline'? if (s->prev && s->prev->face->underline_p ^~~~~~~~~~~ underline ../../src/w32term.c:2501:23: error: 'struct face' has no member named 'underline_type'; did you mean 'underline_color'? && s->prev->face->underline_type == FACE_UNDER_LINE) ^~~~~~~~~~~~~~ underline_color make[1]: *** [Makefile:402: w32term.o] Fehler 1 make[1]: *** Es wird auf noch nicht beendete Prozesse gewartet.... make[1]: Verzeichnis „/c/emacs/trunk/non-64/src“ wird verlassen make: *** [Makefile:424: src] Fehler 2 and since I don't understand the underline_p/_type rationale I have no good idea how to proceed. > to detect what is failing at > least to triger the merge and extend? > Probably the initialization. (which btw the lisp glue code may be buggy > for sure.) I'd run Emacs under gdb to find out whether merge_extend_glyph_face gets called in the first place. And if it doesn't get called, I would continue investigating the places where it should get called. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-03 8:45 ` martin rudalics @ 2019-09-03 11:23 ` Ergus 2019-09-03 12:17 ` martin rudalics 2019-09-03 14:56 ` Eli Zaretskii 0 siblings, 2 replies; 183+ messages in thread From: Ergus @ 2019-09-03 11:23 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel On Tue, Sep 03, 2019 at 10:45:46AM +0200, martin rudalics wrote: >> Could any of you give a look to the patch > >I cannot build Emacs on Windows with the patch due to > > > CC w32select.o >../../src/w32term.c: In function 'w32_draw_glyph_string': >../../src/w32term.c:2482:20: error: 'struct face' has no member named 'underline_p'; did you mean 'underline'? > if (s->face->underline_p) > ^~~~~~~~~~~ > underline >../../src/w32term.c:2484:24: error: 'struct face' has no member named 'underline_type'; did you mean 'underline_color'? > if (s->face->underline_type == FACE_UNDER_WAVE) > ^~~~~~~~~~~~~~ > underline_color >../../src/w32term.c:2495:29: error: 'struct face' has no member named 'underline_type'; did you mean 'underline_color'? > else if (s->face->underline_type == FACE_UNDER_LINE) > ^~~~~~~~~~~~~~ > underline_color >../../src/w32term.c:2500:45: error: 'struct face' has no member named 'underline_p'; did you mean 'underline'? > if (s->prev && s->prev->face->underline_p > ^~~~~~~~~~~ > underline >../../src/w32term.c:2501:23: error: 'struct face' has no member named 'underline_type'; did you mean 'underline_color'? > && s->prev->face->underline_type == FACE_UNDER_LINE) > ^~~~~~~~~~~~~~ > underline_color >make[1]: *** [Makefile:402: w32term.o] Fehler 1 >make[1]: *** Es wird auf noch nicht beendete Prozesse gewartet.... >make[1]: Verzeichnis ???/c/emacs/trunk/non-64/src??? wird verlassen >make: *** [Makefile:424: src] Fehler 2 > > >and since I don't understand the underline_p/_type rationale I have no >good idea how to proceed. > Ohh sorry. My bad I made a code simplify and removed this member. I will fix it now. >> to detect what is failing at >> least to triger the merge and extend? >> Probably the initialization. (which btw the lisp glue code may be buggy >> for sure.) > >I'd run Emacs under gdb to find out whether merge_extend_glyph_face >gets called in the first place. And if it doesn't get called, I would >continue investigating the places where it should get called. > >martin > > After a while I made it to be called, so, forget the patch I will email a different one in a while. I found also that we where very concerned about what happen when merging, but there was not any comment about face_id changes in other cases (like reassign). For example, when we select a word in the middle of a line. The extend_face will be set to the region face when the iterator iterates throw the word, but then it shouldn't be extended at EOL. So we are dealing with a 2D problem here. Iterate on X (the line) vs merging on Y (the face). So I am not sure we have a criteria about when to propagate the extend in both dimensions; because as I see in most of the cases the face_id in X changes due to reassign associated to text properties. So we have been talking all the time about the Y problem? maybe we should test only the last face in the line before EOL to check for the extend flag; but then the extend_face_id will be again an intrinsic parameter of that face. I feel I am missing something for sure. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-03 11:23 ` Ergus @ 2019-09-03 12:17 ` martin rudalics 2019-09-03 14:56 ` Eli Zaretskii 1 sibling, 0 replies; 183+ messages in thread From: martin rudalics @ 2019-09-03 12:17 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel > I found also that we where very concerned about what happen when > merging, but there was not any comment about face_id changes in other > cases (like reassign). I don't know what reassign does but don't we have to redo all windows in that case? > For example, when we select a word in the middle of a line. The > extend_face will be set to the region face when the iterator iterates > throw the word, but then it shouldn't be extended at EOL. Why would that be a problem? The last stop position we care about here is the end of the word (because that's where the region text property terminates) and the region face should be long forgotten at the end of the line. Or what am I missing? > So we are dealing with a 2D problem here. Iterate on X (the line) vs > merging on Y (the face). I don't see this as two-dimensional. The iterator linearly iterates through the buffer, re-contemplating faces at each stop position. > So I am not sure we have a criteria about when to propagate the extend > in both dimensions; because as I see in most of the cases the face_id in > X changes due to reassign associated to text properties. So we have been > talking all the time about the Y problem? > > maybe we should test only the last face in the line before EOL to check > for the extend flag; but then the extend_face_id will be again an > intrinsic parameter of that face. The extend face to consider at any EOL is the extend face calculated at the last stop position before that EOL (which sometimes might be the beginning of the buffer). martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-03 11:23 ` Ergus 2019-09-03 12:17 ` martin rudalics @ 2019-09-03 14:56 ` Eli Zaretskii 1 sibling, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-09-03 14:56 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Tue, 3 Sep 2019 13:23:37 +0200 > From: Ergus <spacibba@aol.com> > Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org > > I found also that we where very concerned about what happen when > merging, but there was not any comment about face_id changes in other > cases (like reassign). > > For example, when we select a word in the middle of a line. The > extend_face will be set to the region face when the iterator iterates > throw the word, but then it shouldn't be extended at EOL. We need to recalculate extend_face_id at the same places where we recalculate face_id. > maybe we should test only the last face in the line before EOL to check > for the extend flag; but then the extend_face_id will be again an > intrinsic parameter of that face. How do you know it's "the last face"? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-02 16:18 ` Eli Zaretskii 2019-09-03 5:33 ` Ergus @ 2019-09-03 5:35 ` Ergus via Emacs development discussions. 2019-09-03 8:45 ` martin rudalics 2 siblings, 0 replies; 183+ messages in thread From: Ergus via Emacs development discussions. @ 2019-09-03 5:35 UTC (permalink / raw) To: Eli Zaretskii; +Cc: rudalics, emacs-devel [-- Attachment #1: Type: text/plain, Size: 2920 bytes --] PATCH: (relative to dd162a3f2264940e3e329d0bf) On Mon, Sep 02, 2019 at 07:18:19PM +0300, Eli Zaretskii wrote: >> Date: Mon, 2 Sep 2019 13:05:04 +0200 >> From: Ergus <spacibba@aol.com> >> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org >> >> >If so then we might consider the following optimization: The extra >> >face pointer in each face is no more needed after the display engine >> >has processed the face. So we could build a "shadow" face for b+d, >> >keep it in a separate, static face structure and realize a face from >> >that structure whenever we want to (eagerly or lazily). The display >> >engine, when it finds a pointer to such an extra face at EOL, uses it >> >(maybe realizing it on the fly). >> > >> >Also, the merger could nullify the extra face if it's the same as the >> >normal one, that is no single merge step had an :extend false value >> >override a former :extend true value. So the display engine would >> >know beforehand that it does not have to change the current face. >> > >> Yes; in my initial proposed approach the local pointer will be null in >> that case. > >I don't think I understand why you are talking about face pointers. >The iterator doesn't keep any face pointers, it keeps face IDs (which >allow to obtain the face pointer, when needed, by using FACE_FROM_ID). > >So all you need is to have another face ID member in the iterator, to >be used for extending past EOL; depending on how the :extend bits are >set, that face ID may or may not be identical to the "normal" face ID, >the one we have now and use for buffer text. > >> >Last but not least, the display engine has to, after processing the >> >spaces at the EOL from b+d, restore the a+b+c+d+e face as its current >> >face. So we have two static pointers to keep around: One for the b+d >> >face structure (or its already realized face) while the display engine >> >processes normal text and one for the a+b+c+d+e realized face while >> >the display engine processes the spaces at EOL. Can you still agree? >> >> In the display engine we do this very >> frequently. As extend_face_to_end_of_line is very localized we just need >> to save a pointer to a+b+c+d on the beginning of the function and >> restore it at the end. > >Again, not a pointer: a face ID. And yes, we have saved_face_id >member of the iterator for this purpose. > >> And that in X there is some extra code (somewhere) to extend the >> background color using the color in the last inserted glyph (it is >> something happening by default without calling even >> extend_face_to_end_of_line). That code should be removed after this >> change; but I don't know where is it. But for sure Eli will tell. > >It's just that we clear to EOL with the last background color, and >avoid doing that if the background color is identical to the frame's >background. I don't think anything will have to be changed there, but >we will see (I hope). > [-- Attachment #2: extend.patch --] [-- Type: text/plain, Size: 31218 bytes --] diff --git a/lisp/cus-face.el b/lisp/cus-face.el index d73bce42c3..5a49a81043 100644 --- a/lisp/cus-face.el +++ b/lisp/cus-face.el @@ -233,7 +233,11 @@ custom-face-attributes (file :tag "File" :help-echo "Name of bitmap file." :must-match t))) - + (:extend + (choice :tag "Extend" + :help-echo "Control whether attributes should be extended after EOL." + (const :tag "Off" nil) + (const :tag "On" t))) (:inherit (repeat :tag "Inherit" :help-echo "List of faces to inherit attributes from." diff --git a/lisp/faces.el b/lisp/faces.el index 5193c216d0..11e42c5380 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -342,6 +342,7 @@ face-x-resources (:box (".attributeBox" . "Face.AttributeBox")) (:underline (".attributeUnderline" . "Face.AttributeUnderline")) (:inverse-video (".attributeInverse" . "Face.AttributeInverse")) + (:extend (".attributeExtend" . "Face.AttributeExtend")) (:stipple (".attributeStipple" . "Face.AttributeStipple") (".attributeBackgroundPixmap" . "Face.AttributeBackgroundPixmap")) @@ -594,6 +595,13 @@ face-italic-p (let ((italic (face-attribute face :slant frame inherit))) (memq italic '(italic oblique)))) +(defun face-extend-p (face &optional frame inherit) + "Return non-nil if FACE specifies a non-nil extend. +If the optional argument FRAME is given, report on face FACE in that frame. +If FRAME is t, report on the defaults for face FACE (for new frames). +If FRAME is omitted or nil, use the selected frame. +Optional argument INHERIT is passed to `face-attribute'." + (eq (face-attribute face :extend frame inherit) t)) \f ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -760,6 +768,11 @@ set-face-attribute `:height', `:weight', and `:slant' may also be set in one step from an X font name: +`:extend' + +VALUE specifies whether the FACE should be extended after EOL. +VALUE must be one of t or nil. + `:font' Set font-related face attributes from VALUE. @@ -979,6 +992,18 @@ set-face-italic (define-obsolete-function-alias 'set-face-italic-p 'set-face-italic "24.4") +(defun set-face-extend (face extend-p &optional frame) + "Specify whether face FACE should be extended. +EXTEND-P nil means FACE explicitly doesn't extend after EOL. +EXTEND-P t means FACE extends after EOL. + +FRAME nil or not specified means change face on all frames. +Use `set-face-attribute' to \"unspecify\" underlining." + (interactive + (let ((list (read-face-and-attribute :extend))) + (list (car list) (if (cadr list) t)))) + (set-face-attribute face frame :extend extend-p)) + (defalias 'set-face-background-pixmap 'set-face-stipple) @@ -1102,7 +1127,7 @@ face-valid-attribute-values (:slant (mapcar #'(lambda (x) (cons (symbol-name (aref x 1)) (aref x 1))) font-slant-table)) - (:inverse-video + ((or :inverse-video :extend) (mapcar #'(lambda (x) (cons (symbol-name x) x)) (internal-lisp-face-attribute-values attribute))) ((or :underline :overline :strike-through :box) @@ -1147,12 +1172,13 @@ face-attribute-name-alist (:slant . "slant") (:underline . "underline") (:overline . "overline") + (:extend . "extend") (:strike-through . "strike-through") (:box . "box") (:inverse-video . "inverse-video display") (:foreground . "foreground color") (:background . "background color") - (:stipple . "background stipple") + (:background . "background color") (:inherit . "inheritance")) "An alist of descriptive names for face attributes. Each element has the form (ATTRIBUTE-NAME . DESCRIPTION) where @@ -2432,24 +2458,24 @@ highlight ;; if background is light. (defface region '((((class color) (min-colors 88) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 88) (background light) (type gtk)) :distant-foreground "gtk_selection_fg_color" - :background "gtk_selection_bg_color") + :background "gtk_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light) (type ns)) :distant-foreground "ns_selection_fg_color" - :background "ns_selection_bg_color") + :background "ns_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 16) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 16) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 8)) - :background "blue" :foreground "white") + :background "blue" :foreground "white" :extend t) (((type tty) (class mono)) :inverse-video t) - (t :background "gray")) + (t :background "gray" :extend t)) "Basic face for highlighting the region." :version "21.1" :group 'basic-faces) diff --git a/src/dispextern.h b/src/dispextern.h index 05f199ff35..e09d36944a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1564,6 +1564,7 @@ #define FONT_TOO_HIGH(ft) \ LFACE_INHERIT_INDEX, LFACE_FONTSET_INDEX, LFACE_DISTANT_FOREGROUND_INDEX, + LFACE_EXTEND_INDEX, LFACE_VECTOR_SIZE }; @@ -1589,6 +1590,7 @@ #define FONT_TOO_HIGH(ft) \ enum face_underline_type { + FACE_NO_UNDERLINE = 0, FACE_UNDER_LINE, FACE_UNDER_WAVE }; @@ -1632,11 +1634,9 @@ #define FONT_TOO_HIGH(ft) \ /* Pixel value or color index of background color. */ unsigned long background; - /* Pixel value or color index of underline color. */ + /* Pixel value or color index of underline, overlined, + strike-through, or box color. */ unsigned long underline_color; - - /* Pixel value or color index of overlined, strike-through, or box - color. */ unsigned long overline_color; unsigned long strike_through_color; unsigned long box_color; @@ -1663,7 +1663,7 @@ #define FONT_TOO_HIGH(ft) \ ENUM_BF (face_box_type) box : 2; /* Style of underlining. */ - ENUM_BF (face_underline_type) underline_type : 1; + ENUM_BF (face_underline_type) underline : 2; /* If `box' above specifies a 3D type, true means use box_color for drawing shadows. */ @@ -1671,7 +1671,6 @@ #define FONT_TOO_HIGH(ft) \ /* Non-zero if text in this face should be underlined, overlined, strike-through or have a box drawn around it. */ - bool_bf underline_p : 1; bool_bf overline_p : 1; bool_bf strike_through_p : 1; @@ -1681,14 +1680,10 @@ #define FONT_TOO_HIGH(ft) \ bool_bf foreground_defaulted_p : 1; bool_bf background_defaulted_p : 1; - /* True means that either no color is specified for underlining or that - the specified color couldn't be loaded. Use the foreground - color when drawing in that case. */ - bool_bf underline_defaulted_p : 1; - /* True means that either no color is specified for the corresponding attribute or that the specified color couldn't be loaded. Use the foreground color when drawing in that case. */ + bool_bf underline_defaulted_p : 1; bool_bf overline_color_defaulted_p : 1; bool_bf strike_through_color_defaulted_p : 1; bool_bf box_color_defaulted_p : 1; @@ -2448,6 +2443,9 @@ #define OVERLAY_STRING_CHUNK_SIZE 16 /* Face to use. */ int face_id; + /* Face to extend at EOL/ */ + int extend_face_id; + /* Setting of buffer-local variable selective-display-ellipses. */ bool_bf selective_display_ellipsis_p : 1; diff --git a/src/xdisp.c b/src/xdisp.c index 75bc536cb9..015a80af42 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -7141,18 +7141,50 @@ lookup_glyphless_char_display (int c, struct it *it) } /* Merge escape glyph face and cache the result. */ +static struct frame *last_extend_glyph_frame = NULL; +static int last_extend_glyph_face_id = (1 << FACE_ID_BITS); +static int last_extend_glyph_merged_face_id = 0; +static int +merge_extend_glyph_face (struct it *it) +{ + int extend_face_id = it->extend_face_id; + + struct face *face = FACE_FROM_ID (it->f, it->extend_face_id); + fprintf(stderr, "extending1!!!\n"); + + if (!NILP (face->lface[LFACE_EXTEND_INDEX])) + { + fprintf(stderr,"extending2!!!\n"); + + if (it->f == last_extend_glyph_frame + && it->extend_face_id == last_extend_glyph_face_id) + return last_extend_glyph_merged_face_id; + + /* Merge the `glyphless-char' face into the current face. */ + extend_face_id = merge_faces (it->w, Qt, it->face_id, extend_face_id); + last_extend_glyph_frame = it->f; + last_extend_glyph_face_id = it->extend_face_id; + last_extend_glyph_merged_face_id = extend_face_id; + } + return extend_face_id; +} + + +/* Merge escape glyph face and cache the result. */ static struct frame *last_escape_glyph_frame = NULL; static int last_escape_glyph_face_id = (1 << FACE_ID_BITS); static int last_escape_glyph_merged_face_id = 0; static int -merge_escape_glyph_face (struct it *it) +merge_escape_glyph_face (struct it *it, int lface_id) { int face_id; - if (it->f == last_escape_glyph_frame - && it->face_id == last_escape_glyph_face_id) + if (lface_id) + face_id = merge_faces (it->w, Qt, lface_id, it->face_id); + else if (it->f == last_escape_glyph_frame + && it->face_id == last_escape_glyph_face_id) face_id = last_escape_glyph_merged_face_id; else { @@ -7162,6 +7194,8 @@ merge_escape_glyph_face (struct it *it) last_escape_glyph_face_id = it->face_id; last_escape_glyph_merged_face_id = face_id; } + + merge_extend_glyph_face (it); return face_id; } @@ -7187,9 +7221,12 @@ merge_glyphless_glyph_face (struct it *it) last_glyphless_glyph_face_id = it->face_id; last_glyphless_glyph_merged_face_id = face_id; } + + merge_extend_glyph_face (it); return face_id; } + /* Forget the `escape-glyph' and `glyphless-char' faces. This should be called before redisplaying windows, and when the frame's face cache is freed. */ @@ -7355,9 +7392,7 @@ get_next_display_element (struct it *it) lface_id = GLYPH_CODE_FACE (gc); } - face_id = (lface_id - ? merge_faces (it->w, Qt, lface_id, it->face_id) - : merge_escape_glyph_face (it)); + face_id = merge_escape_glyph_face (it, lface_id); XSETINT (it->ctl_chars[0], g); XSETINT (it->ctl_chars[1], c ^ 0100); @@ -7373,6 +7408,8 @@ get_next_display_element (struct it *it) /* Merge `nobreak-space' into the current face. */ face_id = merge_faces (it->w, Qnobreak_space, 0, it->face_id); + + merge_extend_glyph_face (it); XSETINT (it->ctl_chars[0], ' '); ctl_len = 1; goto display_control; @@ -7385,7 +7422,10 @@ get_next_display_element (struct it *it) { /* Merge `nobreak-space' into the current face. */ face_id = merge_faces (it->w, Qnobreak_hyphen, 0, - it->face_id); + it->face_id); + + merge_extend_glyph_face (it); + XSETINT (it->ctl_chars[0], '-'); ctl_len = 1; goto display_control; @@ -7403,12 +7443,10 @@ get_next_display_element (struct it *it) lface_id = GLYPH_CODE_FACE (gc); } - face_id = (lface_id - ? merge_faces (it->w, Qt, lface_id, it->face_id) - : merge_escape_glyph_face (it)); + face_id = merge_escape_glyph_face (it, lface_id); + /* Draw non-ASCII space/hyphen with escape glyph: */ - if (nonascii_space_p || nonascii_hyphen_p) { XSETINT (it->ctl_chars[0], escape_glyph); @@ -8032,8 +8070,11 @@ next_element_from_display_vector (struct it *it) { int lface_id = GLYPH_CODE_FACE (gc); if (lface_id > 0) - it->face_id = merge_faces (it->w, Qt, lface_id, - it->saved_face_id); + { + it->face_id = merge_faces (it->w, Qt, lface_id, + it->saved_face_id); + merge_extend_glyph_face (it); + } } /* Glyphs in the display vector could have the box face, so we @@ -8061,8 +8102,11 @@ next_element_from_display_vector (struct it *it) GLYPH_CODE_FACE (it->dpvec[it->current.dpvec_index + 1]); if (lface_id > 0) - next_face_id = merge_faces (it->w, Qt, lface_id, - it->saved_face_id); + { + next_face_id = merge_faces (it->w, Qt, lface_id, + it->saved_face_id); + merge_extend_glyph_face (it); + } } } next_face = FACE_FROM_ID_OR_NULL (it->f, next_face_id); @@ -20324,7 +20368,7 @@ append_space_for_newline (struct it *it, bool default_face_p) = XFIXNAT (Vdisplay_fill_column_indicator_character); it->face_id = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); + 0, it->extend_face_id); face = FACE_FROM_ID (it->f, it->face_id); goto produce_glyphs; } @@ -20471,33 +20515,33 @@ extend_face_to_end_of_line (struct it *it) 1-``pixel'' wide, so they hit the equality too early. This grace is needed only for R2L rows that are not continued, to produce one extra blank where we could display the cursor. */ - if ((it->current_x >= it->last_visible_x - + (!FRAME_WINDOW_P (f) - && it->glyph_row->reversed_p - && !it->glyph_row->continued_p)) - /* If the window has display margins, we will need to extend - their face even if the text area is filled. */ - && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 - || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) - return; - - /* Face extension extends the background and box of IT->face_id - to the end of the line. If the background equals the background - of the frame, we don't have to do anything. */ +/* if ((it->current_x >= it->last_visible_x */ +/* + (!FRAME_WINDOW_P (f) */ +/* && it->glyph_row->reversed_p */ +/* && !it->glyph_row->continued_p)) */ +/* /\* If the window has display margins, we will need to extend */ +/* their face even if the text area is filled. *\/ */ +/* && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 */ +/* || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) */ +/* return; */ + +/* /\* Face extension extends the background and box of IT->face_id */ +/* to the end of the line. If the background equals the background */ +/* of the frame, we don't have to do anything. *\/ */ face = FACE_FROM_ID (f, (it->face_before_selective_p ? it->saved_face_id - : it->face_id)); - - if (FRAME_WINDOW_P (f) - && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) - && face->box == FACE_NO_BOX - && FACE_COLOR_TO_PIXEL (face->background, f) == FRAME_BACKGROUND_PIXEL (f) -#ifdef HAVE_WINDOW_SYSTEM - && !face->stipple -#endif - && !it->glyph_row->reversed_p - && !Vdisplay_fill_column_indicator) - return; + : it->extend_face_id)); + +/* if (FRAME_WINDOW_P (f) */ +/* && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) */ +/* && face->box == FACE_NO_BOX */ +/* && FACE_COLOR_TO_PIXEL (face->background, f) == FRAME_BACKGROUND_PIXEL (f) */ +/* #ifdef HAVE_WINDOW_SYSTEM */ +/* && !face->stipple */ +/* #endif */ +/* && !it->glyph_row->reversed_p */ +/* && !Vdisplay_fill_column_indicator) */ +/* return; */ /* Set the glyph row flag indicating that the face of the last glyph in the text area has to be drawn to the end of the text area. */ @@ -20560,79 +20604,88 @@ extend_face_to_end_of_line (struct it *it) /* Display fill column indicator if not in modeline or toolbar and display fill column indicator mode is active. */ + const char saved_char = it->char_to_display; + const struct text_pos saved_pos = it->position; + const bool saved_avoid_cursor = it->avoid_cursor_p; + const int saved_face_id = it->face_id; + const bool saved_box_start = it->start_of_box_run_p; + Lisp_Object save_object = it->object; + + it->avoid_cursor_p = true; + it->object = Qnil; + memset (&it->position, 0, sizeof it->position); + int indicator_column = (it->w->pseudo_window_p == 0 ? fill_column_indicator_column (it) : -1); - if (indicator_column >= 0) - { - struct font *font = (default_face->font + + struct font *font = (default_face->font ? default_face->font : FRAME_FONT (f)); - const int char_width = (font->average_width - ? font->average_width - : font->space_width); - int column_x; - - if (!INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) - && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) - && column_x >= it->current_x - && column_x <= it->last_visible_x) - { - const char saved_char = it->char_to_display; - const struct text_pos saved_pos = it->position; - const bool saved_avoid_cursor = it->avoid_cursor_p; - const int saved_face_id = it->face_id; - const bool saved_box_start = it->start_of_box_run_p; - Lisp_Object save_object = it->object; - - /* The stretch width needs to considet the latter - added glyph. */ - const int stretch_width - = column_x - it->current_x - char_width; - - memset (&it->position, 0, sizeof it->position); - it->avoid_cursor_p = true; - it->object = Qnil; - - /* Only generate a stretch glyph if there is distance - between current_x and and the indicator position. */ - if (stretch_width > 0) - { - int stretch_ascent = (((it->ascent + it->descent) - * FONT_BASE (font)) / FONT_HEIGHT (font)); - append_stretch_glyph (it, Qnil, stretch_width, - it->ascent + it->descent, - stretch_ascent); - } + const int char_width = (font->average_width + ? font->average_width + : font->space_width); + int column_x; + + if (indicator_column >= 0 + && !INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) + && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) + && column_x >= it->current_x + && column_x <= it->last_visible_x) + { + + /* The stretch width needs to considet the latter + added glyph. */ + const int stretch_width + = column_x - it->current_x - char_width; + + /* Only generate a stretch glyph if there is distance + between current_x and and the indicator position. */ + if (stretch_width > 0) + { + it->face_id = it->extend_face_id; - /* Generate the glyph indicator only if - append_space_for_newline didn't already. */ - if (it->current_x < column_x) - { - it->char_to_display - = XFIXNAT (Vdisplay_fill_column_indicator_character); - it->face_id - = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); - PRODUCE_GLYPHS (it); - } - - /* Restore the face after the indicator was generated. */ - it->face_id = saved_face_id; - - /* If there is space after the indicator generate an - extra empty glyph to restore the face. Issue was - observed in X systems. */ - it->char_to_display = ' '; - PRODUCE_GLYPHS (it); - - it->char_to_display = saved_char; - it->position = saved_pos; - it->avoid_cursor_p = saved_avoid_cursor; - it->start_of_box_run_p = saved_box_start; - it->object = save_object; - } - } + int stretch_ascent = (((it->ascent + it->descent) + * FONT_BASE (font)) / FONT_HEIGHT (font)); + append_stretch_glyph (it, Qnil, stretch_width, + it->ascent + it->descent, + stretch_ascent); + } + + /* Generate the glyph indicator only if + append_space_for_newline didn't already. */ + if (it->current_x < column_x) + { + it->char_to_display + = XFIXNAT (Vdisplay_fill_column_indicator_character); + it->face_id + = merge_faces (it->w, Qfill_column_indicator, + 0, it->extend_face_id); + PRODUCE_GLYPHS (it); + it->char_to_display = saved_char; + } + + } + + const int stretch_width = it->last_visible_x - it->current_x; + + if (stretch_width > 0) + { + it->face_id = it->extend_face_id; + + int stretch_ascent = (((it->ascent + it->descent) + * FONT_BASE (font)) / FONT_HEIGHT (font)); + append_stretch_glyph (it, Qnil, stretch_width, + it->ascent + it->descent, + stretch_ascent); + } + + it->char_to_display = saved_char; + it->position = saved_pos; + it->avoid_cursor_p = saved_avoid_cursor; + it->face_id = saved_face_id; + it->start_of_box_run_p = saved_box_start; + it->object = save_object; } if (it->glyph_row->reversed_p) { @@ -20718,7 +20771,7 @@ extend_face_to_end_of_line (struct it *it) it->len = 1; if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 - && (it->glyph_row->used[LEFT_MARGIN_AREA] + && (it->glyph_row->used[LEFT_MARGIN_AREA] < WINDOW_LEFT_MARGIN_WIDTH (it->w)) && !it->glyph_row->mode_line_p && FACE_COLOR_TO_PIXEL (face->background, f) != FRAME_BACKGROUND_PIXEL (f)) @@ -20762,24 +20815,25 @@ extend_face_to_end_of_line (struct it *it) indicator_column = -1; do { - int saved_face_id; - bool indicate = it->current_x == indicator_column; - if (indicate) + if (it->current_x == indicator_column) { - saved_face_id = it->face_id; + int saved_face_id = it->face_id; + it->face_id - = merge_faces (it->w, Qfill_column_indicator, 0, saved_face_id); + = merge_faces (it->w, Qfill_column_indicator, 0, + it->extend_face_id); it->c = it->char_to_display = XFIXNAT (Vdisplay_fill_column_indicator_character); - } - PRODUCE_GLYPHS (it); + PRODUCE_GLYPHS (it); - if (indicate) - { it->face_id = saved_face_id; it->c = it->char_to_display = ' '; } + else + { + PRODUCE_GLYPHS (it); + } } while (it->current_x <= it->last_visible_x); @@ -21760,6 +21814,7 @@ display_line (struct it *it, int cursor_vpos) it->starts_in_middle_of_char_p = false; it->tab_offset = 0; it->line_number_produced_p = false; + it->extend_face_id = DEFAULT_FACE_ID; /* Arrange the overlays nicely for our purposes. Usually, we call display_line on only one line at a time, in which case this @@ -27354,7 +27409,7 @@ font_for_underline_metrics (struct glyph_string *s) for (g = s->first_glyph - 1; g >= g0; g--) { struct face *prev_face = FACE_FROM_ID (s->f, g->face_id); - if (!(prev_face && prev_face->underline_p)) + if (!(prev_face && prev_face->underline != FACE_NO_UNDERLINE)) break; } diff --git a/src/xfaces.c b/src/xfaces.c index c3cae7e2a6..092e110de5 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -1209,7 +1209,7 @@ free_face_colors (struct frame *f, struct face *face) IF_DEBUG (--ncolors_allocated); } - if (face->underline_p + if (face->underline && !face->underline_defaulted_p) { x_free_colors (f, &face->underline_color, 1); @@ -1590,6 +1590,7 @@ #define LFACE_BOX(LFACE) AREF ((LFACE), LFACE_BOX_INDEX) #define LFACE_FONT(LFACE) AREF ((LFACE), LFACE_FONT_INDEX) #define LFACE_INHERIT(LFACE) AREF ((LFACE), LFACE_INHERIT_INDEX) #define LFACE_FONTSET(LFACE) AREF ((LFACE), LFACE_FONTSET_INDEX) +#define LFACE_EXTEND(LFACE) AREF ((LFACE), LFACE_EXTEND_INDEX) #define LFACE_DISTANT_FOREGROUND(LFACE) \ AREF ((LFACE), LFACE_DISTANT_FOREGROUND_INDEX) @@ -2512,6 +2513,13 @@ merge_face_ref (struct window *w, err_msgs, named_merge_points)) err = true; } + else if (EQ (keyword, QCextend)) + { + if (EQ (value, Qt) || NILP (value)) + to[LFACE_EXTEND_INDEX] = value; + else + err = true; + } else err = true; @@ -3030,6 +3038,17 @@ DEFUN ("internal-set-lisp-face-attribute", Finternal_set_lisp_face_attribute, old_value = LFACE_INVERSE (lface); ASET (lface, LFACE_INVERSE_INDEX, value); } + else if (EQ (attr, QCextend)) + { + if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) + { + CHECK_SYMBOL (value); + if (!EQ (value, Qt) && !NILP (value)) + signal_error ("Invalid inverse-video face attribute value", value); + } + old_value = LFACE_EXTEND (lface); + ASET (lface, LFACE_EXTEND_INDEX, value); + } else if (EQ (attr, QCforeground)) { /* Compatibility with 20.x. */ @@ -3203,6 +3222,14 @@ DEFUN ("internal-set-lisp-face-attribute", Finternal_set_lisp_face_attribute, ASET (lface, LFACE_SLANT_INDEX, NILP (value) ? Qnormal : Qitalic); prop_index = FONT_SLANT_INDEX; } + else if (EQ (attr, QCitalic)) + { + attr = QCslant; + old_value = LFACE_SLANT (lface); + ASET (lface, LFACE_SLANT_INDEX, NILP (value) ? Qnormal : Qitalic); + prop_index = FONT_SLANT_INDEX; + } + else signal_error ("Invalid face attribute name", attr); @@ -3503,7 +3530,9 @@ DEFUN ("internal-set-lisp-face-attribute-from-resource", value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCweight) || EQ (attr, QCslant) || EQ (attr, QCwidth)) value = intern (SSDATA (value)); - else if (EQ (attr, QCreverse_video) || EQ (attr, QCinverse_video)) + else if (EQ (attr, QCreverse_video) + || EQ (attr, QCinverse_video) + || EQ (attr, QCextend)) value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCunderline) || EQ (attr, QCoverline) @@ -3727,6 +3756,8 @@ DEFUN ("internal-get-lisp-face-attribute", Finternal_get_lisp_face_attribute, value = LFACE_SWIDTH (lface); else if (EQ (keyword, QCinherit)) value = LFACE_INHERIT (lface); + else if (EQ (keyword, QCextend)) + value = LFACE_EXTEND (lface); else if (EQ (keyword, QCfont)) value = LFACE_FONT (lface); else if (EQ (keyword, QCfontset)) @@ -5694,16 +5725,14 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] if (EQ (underline, Qt)) { /* Use default color (same as foreground color). */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = true; face->underline_color = 0; } else if (STRINGP (underline)) { /* Use specified color. */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = false; face->underline_color = load_color (f, face, underline, @@ -5711,7 +5740,7 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] } else if (NILP (underline)) { - face->underline_p = false; + face->underline = FACE_NO_UNDERLINE; face->underline_defaulted_p = false; face->underline_color = 0; } @@ -5719,10 +5748,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] { /* `(:color COLOR :style STYLE)'. STYLE being one of `line' or `wave'. */ - face->underline_p = true; + face->underline = FACE_UNDER_LINE; face->underline_color = 0; face->underline_defaulted_p = true; - face->underline_type = FACE_UNDER_LINE; /* FIXME? This is also not robust about checking the precise form. See comments in Finternal_set_lisp_face_attribute. */ @@ -5755,9 +5783,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] else if (EQ (keyword, QCstyle)) { if (EQ (value, Qline)) - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; else if (EQ (value, Qwave)) - face->underline_type = FACE_UNDER_WAVE; + face->underline = FACE_UNDER_WAVE; } } } @@ -6292,9 +6320,8 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, { struct frame *f = WINDOW_XFRAME (w); Lisp_Object attrs[LFACE_VECTOR_SIZE]; - struct face *base_face; + struct face *base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); - base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); if (!base_face) return base_face_id; @@ -6319,12 +6346,14 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, } else { - struct face *face; if (face_id < 0) return base_face_id; - face = FACE_FROM_ID_OR_NULL (f, face_id); + + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); + if (!face) return base_face_id; + merge_face_vectors (w, f, face->lface, attrs, 0); } @@ -6412,7 +6441,7 @@ dump_realized_face (struct face *face) #endif fprintf (stderr, "fontset: %d\n", face->fontset); fprintf (stderr, "underline: %d (%s)\n", - face->underline_p, + face->underline, SDATA (Fsymbol_name (face->lface[LFACE_UNDERLINE_INDEX]))); fprintf (stderr, "hash: %" PRIuPTR "\n", face->hash); } @@ -6537,6 +6566,7 @@ syms_of_xfaces (void) DEFSYM (QCstrike_through, ":strike-through"); DEFSYM (QCbox, ":box"); DEFSYM (QCinherit, ":inherit"); + DEFSYM (QCextend, ":extend"); /* Symbols used for Lisp face attribute values. */ DEFSYM (QCcolor, ":color"); diff --git a/src/xterm.c b/src/xterm.c index b761eaf4d1..b8f8db56a7 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3798,9 +3798,9 @@ x_draw_glyph_string (struct glyph_string *s) if (!s->for_overlaps) { /* Draw underline. */ - if (s->face->underline_p) + if (s->face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { if (s->face->underline_defaulted_p) x_draw_underwave (s); @@ -3814,13 +3814,13 @@ x_draw_glyph_string (struct glyph_string *s) XSetForeground (display, s->gc, xgcv.foreground); } } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { unsigned long thickness, position; int y; - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE) + if (s->prev && + s->prev->face->underline == FACE_UNDER_LINE) { /* We use the same underline style as the previous one. */ thickness = s->prev->underline_thickness; ^ permalink raw reply related [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-02 16:18 ` Eli Zaretskii 2019-09-03 5:33 ` Ergus 2019-09-03 5:35 ` Ergus via Emacs development discussions. @ 2019-09-03 8:45 ` martin rudalics 2019-09-03 14:53 ` Eli Zaretskii 2 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-03 8:45 UTC (permalink / raw) To: Eli Zaretskii, Ergus; +Cc: emacs-devel > I don't think I understand why you are talking about face pointers. > The iterator doesn't keep any face pointers, it keeps face IDs (which > allow to obtain the face pointer, when needed, by using FACE_FROM_ID). > > So all you need is to have another face ID member in the iterator, to > be used for extending past EOL; depending on how the :extend bits are > set, that face ID may or may not be identical to the "normal" face ID, > the one we have now and use for buffer text. But a face ID is only available after realizing a face. With a lazy approach there might be no realized face yet and the iterator would realize that face on the fly. >> In the display engine we do this very >> frequently. As extend_face_to_end_of_line is very localized we just need >> to save a pointer to a+b+c+d on the beginning of the function and >> restore it at the end. > > Again, not a pointer: a face ID. And yes, we have saved_face_id > member of the iterator for this purpose. In that case we would have a face ID for sure. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-03 8:45 ` martin rudalics @ 2019-09-03 14:53 ` Eli Zaretskii 2019-09-03 16:41 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-03 14:53 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Tue, 3 Sep 2019 10:45:18 +0200 > > > I don't think I understand why you are talking about face pointers. > > The iterator doesn't keep any face pointers, it keeps face IDs (which > > allow to obtain the face pointer, when needed, by using FACE_FROM_ID). > > > > So all you need is to have another face ID member in the iterator, to > > be used for extending past EOL; depending on how the :extend bits are > > set, that face ID may or may not be identical to the "normal" face ID, > > the one we have now and use for buffer text. > > But a face ID is only available after realizing a face. With a lazy > approach there might be no realized face yet and the iterator would > realize that face on the fly. What do you call "realize a face", exactly, and why do you think it is so expensive as to justify doing that lazily? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-03 14:53 ` Eli Zaretskii @ 2019-09-03 16:41 ` martin rudalics 2019-09-03 17:31 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-03 16:41 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel > What do you call "realize a face", exactly, Whatever realize_face does with its attrs argument. > and why do you think it is > so expensive as to justify doing that lazily? Due to the overhead to calculate, cache and eventually free the realized face. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-03 16:41 ` martin rudalics @ 2019-09-03 17:31 ` Eli Zaretskii 2019-09-03 18:59 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-09-03 17:31 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: spacibba@aol.com, emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Tue, 3 Sep 2019 18:41:40 +0200 > > > What do you call "realize a face", exactly, > > Whatever realize_face does with its attrs argument. > > > and why do you think it is > > so expensive as to justify doing that lazily? > > Due to the overhead to calculate, cache and eventually free the > realized face. I don't think it's expensive enough to justify such premature optimization. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-03 17:31 ` Eli Zaretskii @ 2019-09-03 18:59 ` martin rudalics 2019-09-04 18:33 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-03 18:59 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel > I don't think it's expensive enough to justify such premature > optimization. Earlier you preferred a lazy variant because > it scales better, because the > display code is frequently invoked on short portions of the text, so > there's no guarantee that it will actually get to producing glyphs > with the "extension" variant of the face, so realizing that face in > advance might well be waste of unneeded effort, because the additional > face will never be used. Either way, let's see what Ergus comes up with. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-03 18:59 ` martin rudalics @ 2019-09-04 18:33 ` Ergus 2019-09-04 20:04 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-04 18:33 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel Hi: I have just uploaded some changes but the functionality is still not working. I separated the changes in 3 commits and in the last one are only the ones I made in the xdisp.c (the ones that need to be checked, because the rest is only infrastructure.) see the master branch in: https://github.com/Ergus/Emacs But at this point I will need some extra comments about what I am doing wrong there. Ir if I am doing anything right. The extend now is working like always (testing for the region). In principle the region is the only face I have added :extend t But when I set it to nil it should be not extended and it is; so some extra condition is still missing.. The filter if condition (to merge or not) is a new macro FACE_EXTENSIBLE_P (face). So please any hint is very welcome now. On Tue, Sep 03, 2019 at 08:59:33PM +0200, martin rudalics wrote: >> I don't think it's expensive enough to justify such premature >> optimization. > >Earlier you preferred a lazy variant because > >> it scales better, because the >> display code is frequently invoked on short portions of the text, so >> there's no guarantee that it will actually get to producing glyphs >> with the "extension" variant of the face, so realizing that face in >> advance might well be waste of unneeded effort, because the additional >> face will never be used. > >Either way, let's see what Ergus comes up with. > >martin > ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-04 18:33 ` Ergus @ 2019-09-04 20:04 ` martin rudalics 2019-09-04 20:19 ` Ergus via Emacs development discussions. [not found] ` <1826922767.1725310.1567682307734@mail.yahoo.com> 0 siblings, 2 replies; 183+ messages in thread From: martin rudalics @ 2019-09-04 20:04 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel > I have just uploaded some changes but the functionality is still not > working. > > I separated the changes in 3 commits and in the last one are only the > ones I made in the xdisp.c (the ones that need to be checked, because > the rest is only infrastructure.) > > see the master branch in: https://github.com/Ergus/Emacs Please send a patch for current master. Otherwise I have no idea how to compare your changes. Thanks, martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-04 20:04 ` martin rudalics @ 2019-09-04 20:19 ` Ergus via Emacs development discussions. 2019-09-05 7:32 ` martin rudalics [not found] ` <1826922767.1725310.1567682307734@mail.yahoo.com> 1 sibling, 1 reply; 183+ messages in thread From: Ergus via Emacs development discussions. @ 2019-09-04 20:19 UTC (permalink / raw) To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel [-- Attachment #1: Type: text/plain, Size: 662 bytes --] Here is the diff of the latest commit. (Patch attached anyway). https://github.com/Ergus/Emacs/commit/4943087027acd3f2c7a54a092b64bc839ef8850e On Wed, Sep 04, 2019 at 10:04:16PM +0200, martin rudalics wrote: >> I have just uploaded some changes but the functionality is still not >> working. >> >> I separated the changes in 3 commits and in the last one are only the >> ones I made in the xdisp.c (the ones that need to be checked, because >> the rest is only infrastructure.) >> >> see the master branch in: https://github.com/Ergus/Emacs > >Please send a patch for current master. Otherwise I have no idea how >to compare your changes. > >Thanks, martin [-- Attachment #2: patch.patch --] [-- Type: text/plain, Size: 42425 bytes --] diff --git a/lisp/cus-face.el b/lisp/cus-face.el index d73bce42c3..5a49a81043 100644 --- a/lisp/cus-face.el +++ b/lisp/cus-face.el @@ -233,7 +233,11 @@ custom-face-attributes (file :tag "File" :help-echo "Name of bitmap file." :must-match t))) - + (:extend + (choice :tag "Extend" + :help-echo "Control whether attributes should be extended after EOL." + (const :tag "Off" nil) + (const :tag "On" t))) (:inherit (repeat :tag "Inherit" :help-echo "List of faces to inherit attributes from." diff --git a/lisp/faces.el b/lisp/faces.el index 5193c216d0..6b6fcf0d2d 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -342,6 +342,7 @@ face-x-resources (:box (".attributeBox" . "Face.AttributeBox")) (:underline (".attributeUnderline" . "Face.AttributeUnderline")) (:inverse-video (".attributeInverse" . "Face.AttributeInverse")) + (:extend (".attributeExtend" . "Face.AttributeExtend")) (:stipple (".attributeStipple" . "Face.AttributeStipple") (".attributeBackgroundPixmap" . "Face.AttributeBackgroundPixmap")) @@ -594,6 +595,13 @@ face-italic-p (let ((italic (face-attribute face :slant frame inherit))) (memq italic '(italic oblique)))) +(defun face-extend-p (face &optional frame inherit) + "Return non-nil if FACE specifies a non-nil extend. +If the optional argument FRAME is given, report on face FACE in that frame. +If FRAME is t, report on the defaults for face FACE (for new frames). +If FRAME is omitted or nil, use the selected frame. +Optional argument INHERIT is passed to `face-attribute'." + (eq (face-attribute face :extend frame inherit) t)) \f ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -760,6 +768,11 @@ set-face-attribute `:height', `:weight', and `:slant' may also be set in one step from an X font name: +`:extend' + +VALUE specifies whether the FACE should be extended after EOL. +VALUE must be one of t or nil. + `:font' Set font-related face attributes from VALUE. @@ -979,6 +992,18 @@ set-face-italic (define-obsolete-function-alias 'set-face-italic-p 'set-face-italic "24.4") +(defun set-face-extend (face extend-p &optional frame) + "Specify whether face FACE should be extended. +EXTEND-P nil means FACE explicitly doesn't extend after EOL. +EXTEND-P t means FACE extends after EOL. + +FRAME nil or not specified means change face on all frames. +Use `set-face-attribute' to \"unspecify\" underlining." + (interactive + (let ((list (read-face-and-attribute :extend))) + (list (car list) (if (cadr list) t)))) + (set-face-attribute face frame :extend extend-p)) + (defalias 'set-face-background-pixmap 'set-face-stipple) @@ -1102,7 +1127,7 @@ face-valid-attribute-values (:slant (mapcar #'(lambda (x) (cons (symbol-name (aref x 1)) (aref x 1))) font-slant-table)) - (:inverse-video + ((or :inverse-video :extend) (mapcar #'(lambda (x) (cons (symbol-name x) x)) (internal-lisp-face-attribute-values attribute))) ((or :underline :overline :strike-through :box) @@ -1147,6 +1172,7 @@ face-attribute-name-alist (:slant . "slant") (:underline . "underline") (:overline . "overline") + (:extend . "extend") (:strike-through . "strike-through") (:box . "box") (:inverse-video . "inverse-video display") @@ -2432,24 +2458,24 @@ highlight ;; if background is light. (defface region '((((class color) (min-colors 88) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 88) (background light) (type gtk)) :distant-foreground "gtk_selection_fg_color" - :background "gtk_selection_bg_color") + :background "gtk_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light) (type ns)) :distant-foreground "ns_selection_fg_color" - :background "ns_selection_bg_color") + :background "ns_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 16) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 16) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 8)) - :background "blue" :foreground "white") + :background "blue" :foreground "white" :extend t) (((type tty) (class mono)) :inverse-video t) - (t :background "gray")) + (t :background "gray" :extend t)) "Basic face for highlighting the region." :version "21.1" :group 'basic-faces) diff --git a/src/dispextern.h b/src/dispextern.h index 05f199ff35..c11a3a7b54 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1564,6 +1564,7 @@ #define FONT_TOO_HIGH(ft) \ LFACE_INHERIT_INDEX, LFACE_FONTSET_INDEX, LFACE_DISTANT_FOREGROUND_INDEX, + LFACE_EXTEND_INDEX, LFACE_VECTOR_SIZE }; @@ -1589,6 +1590,7 @@ #define FONT_TOO_HIGH(ft) \ enum face_underline_type { + FACE_NO_UNDERLINE = 0, FACE_UNDER_LINE, FACE_UNDER_WAVE }; @@ -1632,11 +1634,9 @@ #define FONT_TOO_HIGH(ft) \ /* Pixel value or color index of background color. */ unsigned long background; - /* Pixel value or color index of underline color. */ + /* Pixel value or color index of underline, overlined, + strike-through, or box color. */ unsigned long underline_color; - - /* Pixel value or color index of overlined, strike-through, or box - color. */ unsigned long overline_color; unsigned long strike_through_color; unsigned long box_color; @@ -1663,7 +1663,7 @@ #define FONT_TOO_HIGH(ft) \ ENUM_BF (face_box_type) box : 2; /* Style of underlining. */ - ENUM_BF (face_underline_type) underline_type : 1; + ENUM_BF (face_underline_type) underline : 2; /* If `box' above specifies a 3D type, true means use box_color for drawing shadows. */ @@ -1671,7 +1671,6 @@ #define FONT_TOO_HIGH(ft) \ /* Non-zero if text in this face should be underlined, overlined, strike-through or have a box drawn around it. */ - bool_bf underline_p : 1; bool_bf overline_p : 1; bool_bf strike_through_p : 1; @@ -1681,14 +1680,10 @@ #define FONT_TOO_HIGH(ft) \ bool_bf foreground_defaulted_p : 1; bool_bf background_defaulted_p : 1; - /* True means that either no color is specified for underlining or that - the specified color couldn't be loaded. Use the foreground - color when drawing in that case. */ - bool_bf underline_defaulted_p : 1; - /* True means that either no color is specified for the corresponding attribute or that the specified color couldn't be loaded. Use the foreground color when drawing in that case. */ + bool_bf underline_defaulted_p : 1; bool_bf overline_color_defaulted_p : 1; bool_bf strike_through_color_defaulted_p : 1; bool_bf box_color_defaulted_p : 1; @@ -1822,6 +1817,9 @@ #define FACE_FROM_ID_OR_NULL(F, ID) \ ? FRAME_FACE_CACHE (F)->faces_by_id[ID] \ : NULL) +#define FACE_EXTENSIBLE_P(F) \ + (!NILP (F->lface[LFACE_EXTEND_INDEX])) + /* True if FACE is suitable for displaying ASCII characters. */ INLINE bool FACE_SUITABLE_FOR_ASCII_CHAR_P (struct face *face) @@ -2328,7 +2326,7 @@ #define IT_STACK_SIZE 5 /* Face id of the iterator saved in case a glyph from dpvec contains a face. The face is restored when all glyphs from dpvec have been delivered. */ - int saved_face_id; + int saved_face_id, saved_extend_face_id; /* Vector of glyphs for control character translation. The pointer dpvec is set to ctl_chars when a control character is translated. @@ -2390,7 +2388,7 @@ #define OVERLAY_STRING_CHUNK_SIZE 16 ptrdiff_t prev_stop; ptrdiff_t base_level_stop; struct composition_it cmp_it; - int face_id; + int face_id, extend_face_id; /* Save values specific to a given method. */ union { @@ -2448,6 +2446,9 @@ #define OVERLAY_STRING_CHUNK_SIZE 16 /* Face to use. */ int face_id; + /* Face to extend at EOL/ */ + int extend_face_id; + /* Setting of buffer-local variable selective-display-ellipses. */ bool_bf selective_display_ellipsis_p : 1; diff --git a/src/nsterm.m b/src/nsterm.m index 42ef4dd010..99b621533a 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3404,9 +3404,9 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. return; /* Do underline. */ - if (face->underline_p) + if (face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { if (face->underline_defaulted_p) [defaultCol set]; @@ -3415,15 +3415,15 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. ns_draw_underwave (s, width, x); } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { NSRect r; unsigned long thickness, position; /* If the prev was underlined, match its appearance. */ - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE + if (s->prev + && s->prev->face->underline == FACE_UNDER_LINE && s->prev->underline_thickness > 0) { thickness = s->prev->underline_thickness; diff --git a/src/w32term.c b/src/w32term.c index e5874f2d36..99a1db5784 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -2479,9 +2479,9 @@ w32_draw_glyph_string (struct glyph_string *s) if (!s->for_overlaps) { /* Draw underline. */ - if (s->face->underline_p) + if (s->face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { COLORREF color; @@ -2492,13 +2492,13 @@ w32_draw_glyph_string (struct glyph_string *s) w32_draw_underwave (s, color); } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { unsigned long thickness, position; int y; - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE) + if (s->prev + && s->prev->face->underline == FACE_UNDER_LINE) { /* We use the same underline style as the previous one. */ thickness = s->prev->underline_thickness; @@ -2512,7 +2512,7 @@ w32_draw_glyph_string (struct glyph_string *s) BOOL use_underline_position_properties; Lisp_Object val = buffer_local_value (Qunderline_minimum_offset, - s->w->contents); + s->w->contents); if (FIXNUMP (val)) minimum_offset = max (0, XFIXNUM (val)); else diff --git a/src/xdisp.c b/src/xdisp.c index 94f969f37c..db7f1e8d34 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3120,6 +3120,7 @@ init_iterator (struct it *it, struct window *w, struct face *face; it->face_id = remapped_base_face_id; + it->extend_face_id = remapped_base_face_id; /* If we have a boxed mode line, make the first character appear with a left box line. */ @@ -3141,6 +3142,8 @@ init_iterator (struct it *it, struct window *w, /* We will rely on `reseat' to set this up properly, via handle_face_prop. */ it->face_id = it->base_face_id; + it->extend_face_id = it->base_face_id; // ERGUS: FIX_THIS + it->start = it->current; /* Do we need to reorder bidirectional text? Not if this is a @@ -3536,7 +3539,10 @@ handle_stop (struct it *it) /* Use face of preceding text for ellipsis (if invisible) */ if (it->selective_display_ellipsis_p) - it->saved_face_id = it->face_id; + { + it->saved_face_id = it->face_id; + it->saved_extend_face_id = it->extend_face_id; + } /* Here's the description of the semantics of, and the logic behind, the various HANDLED_* statuses: @@ -4154,7 +4160,15 @@ handle_face_prop (struct it *it) it->start_of_box_run_p = (new_face->box != FACE_NO_BOX && (old_face == NULL || !old_face->box)); it->face_box_p = new_face->box != FACE_NO_BOX; + + /* Update the faces id and extend. */ + it->face_id = new_face_id; + + if (FACE_EXTENSIBLE_P (new_face)) + it->extend_face_id = new_face_id; + } + } else { @@ -4253,10 +4267,16 @@ handle_face_prop (struct it *it) it->start_of_box_run_p = new_face->box && (old_face == NULL || !old_face->box); it->face_box_p = new_face->box != FACE_NO_BOX; + + /* Update the faces id and extend. */ + it->face_id = new_face_id; + + if (FACE_EXTENSIBLE_P (new_face)) + it->extend_face_id = new_face_id; + } } - it->face_id = new_face_id; return HANDLED_NORMALLY; } @@ -4854,6 +4874,9 @@ setup_for_ellipsis (struct it *it, int len) if (it->saved_face_id >= 0) it->face_id = it->saved_face_id; + if (it->saved_extend_face_id >= 0) + it->extend_face_id = it->saved_extend_face_id; + /* If the ellipsis represents buffer text, it means we advanced in the buffer, so we should no longer ignore overlay strings. */ if (it->method == GET_FROM_BUFFER) @@ -5063,7 +5086,8 @@ display_prop_end (struct it *it, Lisp_Object object, struct text_pos start_pos) of buffer or string text. */ static int -handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, +handle_single_display_spec (struct it *it, Lisp_Object spec, + Lisp_Object object, Lisp_Object overlay, struct text_pos *position, ptrdiff_t bufpos, int display_replaced, bool frame_window_p, bool enable_eval_p) @@ -5137,7 +5161,11 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, int steps = XFIXNUM (XCAR (XCDR (it->font_height))); if (EQ (XCAR (it->font_height), Qplus)) steps = - steps; + it->face_id = smaller_face (it->f, it->face_id, steps); + it->extend_face_id + = smaller_face (it->f, it->extend_face_id, steps); + } else if (FUNCTIONP (it->font_height) && enable_eval_p) { @@ -5180,7 +5208,12 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, } if (new_height > 0) - it->face_id = face_with_height (it->f, it->face_id, new_height); + { + it->face_id + = face_with_height (it->f, it->face_id, new_height); + it->extend_face_id + = face_with_height (it->f, it->extend_face_id, new_height); + } } } @@ -5370,6 +5403,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, it->method = GET_FROM_IMAGE; it->from_overlay = Qnil; it->face_id = face_id; + it->extend_face_id = face_id; // ERGUS: FIX_THIS it->from_disp_prop_p = true; /* Say that we haven't consumed the characters with @@ -6263,6 +6297,7 @@ push_it (struct it *it, struct text_pos *position) p->cmp_it = it->cmp_it; eassert (it->face_id >= 0); p->face_id = it->face_id; + p->extend_face_id = it->extend_face_id; p->string = it->string; p->method = it->method; p->from_overlay = it->from_overlay; @@ -6366,6 +6401,7 @@ pop_it (struct it *it) it->base_level_stop = p->base_level_stop; it->cmp_it = p->cmp_it; it->face_id = p->face_id; + it->extend_face_id = p->extend_face_id; it->current = p->current; it->position = p->position; it->string = p->string; @@ -7142,17 +7178,32 @@ lookup_glyphless_char_display (int c, struct it *it) /* Merge escape glyph face and cache the result. */ +static int +merge_extend_glyph_face (struct it *it, int lface_id) +{ + + struct face *lface = FACE_FROM_ID (it->f, lface_id); + + if (lface && FACE_EXTENSIBLE_P (lface)) + return merge_faces (it->w, Qt, lface_id, it->extend_face_id); + + return it->extend_face_id; +} + +/* Merge escape glyph face and cache the result. */ static struct frame *last_escape_glyph_frame = NULL; static int last_escape_glyph_face_id = (1 << FACE_ID_BITS); static int last_escape_glyph_merged_face_id = 0; static int -merge_escape_glyph_face (struct it *it) +merge_escape_glyph_face (struct it *it, int lface_id) { int face_id; - if (it->f == last_escape_glyph_frame - && it->face_id == last_escape_glyph_face_id) + if (lface_id) + face_id = merge_faces (it->w, Qt, lface_id, it->face_id); + else if (it->f == last_escape_glyph_frame + && it->face_id == last_escape_glyph_face_id) face_id = last_escape_glyph_merged_face_id; else { @@ -7162,6 +7213,7 @@ merge_escape_glyph_face (struct it *it) last_escape_glyph_face_id = it->face_id; last_escape_glyph_merged_face_id = face_id; } + return face_id; } @@ -7187,9 +7239,11 @@ merge_glyphless_glyph_face (struct it *it) last_glyphless_glyph_face_id = it->face_id; last_glyphless_glyph_merged_face_id = face_id; } + return face_id; } + /* Forget the `escape-glyph' and `glyphless-char' faces. This should be called before redisplaying windows, and when the frame's face cache is freed. */ @@ -7275,6 +7329,7 @@ get_next_display_element (struct it *it) it->current.dpvec_index = 0; it->dpvec_face_id = -1; it->saved_face_id = it->face_id; + it->saved_extend_face_id = it->extend_face_id; it->method = GET_FROM_DISPLAY_VECTOR; it->ellipsis_p = false; } @@ -7355,9 +7410,7 @@ get_next_display_element (struct it *it) lface_id = GLYPH_CODE_FACE (gc); } - face_id = (lface_id - ? merge_faces (it->w, Qt, lface_id, it->face_id) - : merge_escape_glyph_face (it)); + face_id = merge_escape_glyph_face (it, lface_id); XSETINT (it->ctl_chars[0], g); XSETINT (it->ctl_chars[1], c ^ 0100); @@ -7373,6 +7426,7 @@ get_next_display_element (struct it *it) /* Merge `nobreak-space' into the current face. */ face_id = merge_faces (it->w, Qnobreak_space, 0, it->face_id); + XSETINT (it->ctl_chars[0], ' '); ctl_len = 1; goto display_control; @@ -7385,7 +7439,8 @@ get_next_display_element (struct it *it) { /* Merge `nobreak-space' into the current face. */ face_id = merge_faces (it->w, Qnobreak_hyphen, 0, - it->face_id); + it->face_id); + XSETINT (it->ctl_chars[0], '-'); ctl_len = 1; goto display_control; @@ -7403,12 +7458,9 @@ get_next_display_element (struct it *it) lface_id = GLYPH_CODE_FACE (gc); } - face_id = (lface_id - ? merge_faces (it->w, Qt, lface_id, it->face_id) - : merge_escape_glyph_face (it)); + face_id = merge_escape_glyph_face (it, lface_id); /* Draw non-ASCII space/hyphen with escape glyph: */ - if (nonascii_space_p || nonascii_hyphen_p) { XSETINT (it->ctl_chars[0], escape_glyph); @@ -7443,6 +7495,7 @@ get_next_display_element (struct it *it) it->current.dpvec_index = 0; it->dpvec_face_id = face_id; it->saved_face_id = it->face_id; + it->saved_extend_face_id = it->extend_face_id; it->method = GET_FROM_DISPLAY_VECTOR; it->ellipsis_p = false; goto get_next; @@ -7778,6 +7831,7 @@ set_iterator_to_next (struct it *it, bool reseat_p) /* Restore face of the iterator to what they were before the display vector entry (these entries may contain faces). */ it->face_id = it->saved_face_id; + it->extend_face_id = it->saved_extend_face_id; if (it->dpvec + it->current.dpvec_index >= it->dpend) { @@ -8012,6 +8066,7 @@ next_element_from_display_vector (struct it *it) eassert (it->dpvec && it->current.dpvec_index >= 0); it->face_id = it->saved_face_id; + it->extend_face_id = it->saved_extend_face_id; /* KFS: This code used to check ip->dpvec[0] instead of the current element. That seemed totally bogus - so I changed it... */ @@ -8027,13 +8082,24 @@ next_element_from_display_vector (struct it *it) the id of a Lisp face, not a realized face. A face id of zero means no face is specified. */ if (it->dpvec_face_id >= 0) - it->face_id = it->dpvec_face_id; + { + it->face_id = it->dpvec_face_id; + //it->extend_face_id = it->dpvec_face_id; // ERGUS: FIX_THIS + } else { int lface_id = GLYPH_CODE_FACE (gc); if (lface_id > 0) - it->face_id = merge_faces (it->w, Qt, lface_id, - it->saved_face_id); + { + it->face_id = merge_faces (it->w, Qt, lface_id, + it->saved_face_id); + + struct face *lface = FACE_FROM_ID (it->f, lface_id); + + if (FACE_EXTENSIBLE_P (lface)) + it->extend_face_id = merge_faces (it->w, Qt, lface_id, + it->saved_extend_face_id);; + } } /* Glyphs in the display vector could have the box face, so we @@ -8061,8 +8127,12 @@ next_element_from_display_vector (struct it *it) GLYPH_CODE_FACE (it->dpvec[it->current.dpvec_index + 1]); if (lface_id > 0) - next_face_id = merge_faces (it->w, Qt, lface_id, - it->saved_face_id); + { + next_face_id = merge_faces (it->w, Qt, lface_id, + it->saved_face_id); + it->extend_face_id = + merge_extend_glyph_face (it, lface_id); + } } } next_face = FACE_FROM_ID_OR_NULL (it->f, next_face_id); @@ -8411,6 +8481,7 @@ next_element_from_ellipsis (struct it *it) was in IT->saved_face_id, and signal that it's there by setting face_before_selective_p. */ it->saved_face_id = it->face_id; + it->saved_extend_face_id = it->extend_face_id; it->method = GET_FROM_BUFFER; it->object = it->w->contents; reseat_at_next_visible_line_start (it, true); @@ -12848,7 +12919,10 @@ display_tool_bar_line (struct it *it, int height) use the tool-bar face for the border too. */ if (!MATRIX_ROW_DISPLAYS_TEXT_P (row) && !EQ (Vauto_resize_tool_bars, Qgrow_only)) - it->face_id = DEFAULT_FACE_ID; + { + it->face_id = DEFAULT_FACE_ID; + it->extend_face_id = DEFAULT_FACE_ID; + } extend_face_to_end_of_line (it); last = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1; @@ -20325,7 +20399,7 @@ append_space_for_newline (struct it *it, bool default_face_p) = XFIXNAT (Vdisplay_fill_column_indicator_character); it->face_id = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); + 0, it->extend_face_id); face = FACE_FROM_ID (it->f, it->face_id); goto produce_glyphs; } @@ -20472,33 +20546,33 @@ extend_face_to_end_of_line (struct it *it) 1-``pixel'' wide, so they hit the equality too early. This grace is needed only for R2L rows that are not continued, to produce one extra blank where we could display the cursor. */ - if ((it->current_x >= it->last_visible_x - + (!FRAME_WINDOW_P (f) - && it->glyph_row->reversed_p - && !it->glyph_row->continued_p)) - /* If the window has display margins, we will need to extend - their face even if the text area is filled. */ - && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 - || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) - return; - - /* Face extension extends the background and box of IT->face_id - to the end of the line. If the background equals the background - of the frame, we don't have to do anything. */ +/* if ((it->current_x >= it->last_visible_x */ +/* + (!FRAME_WINDOW_P (f) */ +/* && it->glyph_row->reversed_p */ +/* && !it->glyph_row->continued_p)) */ +/* /\* If the window has display margins, we will need to extend */ +/* their face even if the text area is filled. *\/ */ +/* && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 */ +/* || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) */ +/* return; */ + +/* /\* Face extension extends the background and box of IT->face_id */ +/* to the end of the line. If the background equals the background */ +/* of the frame, we don't have to do anything. *\/ */ face = FACE_FROM_ID (f, (it->face_before_selective_p - ? it->saved_face_id - : it->face_id)); - - if (FRAME_WINDOW_P (f) - && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) - && face->box == FACE_NO_BOX - && FACE_COLOR_TO_PIXEL (face->background, f) == FRAME_BACKGROUND_PIXEL (f) -#ifdef HAVE_WINDOW_SYSTEM - && !face->stipple -#endif - && !it->glyph_row->reversed_p - && !Vdisplay_fill_column_indicator) - return; + ? it->saved_extend_face_id + : it->extend_face_id)); + +/* if (FRAME_WINDOW_P (f) */ +/* && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) */ +/* && face->box == FACE_NO_BOX */ +/* && FACE_COLOR_TO_PIXEL (face->background, f) == FRAME_BACKGROUND_PIXEL (f) */ +/* #ifdef HAVE_WINDOW_SYSTEM */ +/* && !face->stipple */ +/* #endif */ +/* && !it->glyph_row->reversed_p */ +/* && !Vdisplay_fill_column_indicator) */ +/* return; */ /* Set the glyph row flag indicating that the face of the last glyph in the text area has to be drawn to the end of the text area. */ @@ -20561,79 +20635,88 @@ extend_face_to_end_of_line (struct it *it) /* Display fill column indicator if not in modeline or toolbar and display fill column indicator mode is active. */ + const char saved_char = it->char_to_display; + const struct text_pos saved_pos = it->position; + const bool saved_avoid_cursor = it->avoid_cursor_p; + const int saved_face_id = it->face_id; + const bool saved_box_start = it->start_of_box_run_p; + Lisp_Object save_object = it->object; + + it->avoid_cursor_p = true; + it->object = Qnil; + memset (&it->position, 0, sizeof it->position); + int indicator_column = (it->w->pseudo_window_p == 0 ? fill_column_indicator_column (it) : -1); - if (indicator_column >= 0) - { - struct font *font = (default_face->font + + struct font *font = (default_face->font ? default_face->font : FRAME_FONT (f)); - const int char_width = (font->average_width - ? font->average_width - : font->space_width); - int column_x; - - if (!INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) - && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) - && column_x >= it->current_x - && column_x <= it->last_visible_x) - { - const char saved_char = it->char_to_display; - const struct text_pos saved_pos = it->position; - const bool saved_avoid_cursor = it->avoid_cursor_p; - const int saved_face_id = it->face_id; - const bool saved_box_start = it->start_of_box_run_p; - Lisp_Object save_object = it->object; - - /* The stretch width needs to considet the latter - added glyph. */ - const int stretch_width - = column_x - it->current_x - char_width; - - memset (&it->position, 0, sizeof it->position); - it->avoid_cursor_p = true; - it->object = Qnil; - - /* Only generate a stretch glyph if there is distance - between current_x and and the indicator position. */ - if (stretch_width > 0) - { - int stretch_ascent = (((it->ascent + it->descent) - * FONT_BASE (font)) / FONT_HEIGHT (font)); - append_stretch_glyph (it, Qnil, stretch_width, - it->ascent + it->descent, - stretch_ascent); - } + const int char_width = (font->average_width + ? font->average_width + : font->space_width); + int column_x; + + if (indicator_column >= 0 + && !INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) + && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) + && column_x >= it->current_x + && column_x <= it->last_visible_x) + { + + /* The stretch width needs to considet the latter + added glyph. */ + const int stretch_width + = column_x - it->current_x - char_width; + + /* Only generate a stretch glyph if there is distance + between current_x and and the indicator position. */ + if (stretch_width > 0) + { + it->face_id = it->extend_face_id; - /* Generate the glyph indicator only if - append_space_for_newline didn't already. */ - if (it->current_x < column_x) - { - it->char_to_display - = XFIXNAT (Vdisplay_fill_column_indicator_character); - it->face_id - = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); - PRODUCE_GLYPHS (it); - } - - /* Restore the face after the indicator was generated. */ - it->face_id = saved_face_id; - - /* If there is space after the indicator generate an - extra empty glyph to restore the face. Issue was - observed in X systems. */ - it->char_to_display = ' '; - PRODUCE_GLYPHS (it); - - it->char_to_display = saved_char; - it->position = saved_pos; - it->avoid_cursor_p = saved_avoid_cursor; - it->start_of_box_run_p = saved_box_start; - it->object = save_object; - } - } + int stretch_ascent = (((it->ascent + it->descent) + * FONT_BASE (font)) / FONT_HEIGHT (font)); + append_stretch_glyph (it, Qnil, stretch_width, + it->ascent + it->descent, + stretch_ascent); + } + + /* Generate the glyph indicator only if + append_space_for_newline didn't already. */ + if (it->current_x < column_x) + { + it->char_to_display + = XFIXNAT (Vdisplay_fill_column_indicator_character); + it->face_id + = merge_faces (it->w, Qfill_column_indicator, + 0, it->extend_face_id); + PRODUCE_GLYPHS (it); + it->char_to_display = saved_char; + } + + } + + const int stretch_width = it->last_visible_x - it->current_x; + + if (stretch_width > 0) + { + it->face_id = it->extend_face_id; + + int stretch_ascent = (((it->ascent + it->descent) + * FONT_BASE (font)) / FONT_HEIGHT (font)); + append_stretch_glyph (it, Qnil, stretch_width, + it->ascent + it->descent, + stretch_ascent); + } + + it->char_to_display = saved_char; + it->position = saved_pos; + it->avoid_cursor_p = saved_avoid_cursor; + it->face_id = saved_face_id; + it->start_of_box_run_p = saved_box_start; + it->object = save_object; } if (it->glyph_row->reversed_p) { @@ -20679,10 +20762,9 @@ extend_face_to_end_of_line (struct it *it) /* The last row's stretch glyph should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ - if (it->glyph_row->ends_at_zv_p) - it->face_id = default_face->id; - else - it->face_id = face->id; + it->face_id = (it->glyph_row->ends_at_zv_p ? + default_face->id : face->id); + it->start_of_box_run_p = false; append_stretch_glyph (it, Qnil, stretch_width, it->ascent + it->descent, stretch_ascent); @@ -20719,7 +20801,7 @@ extend_face_to_end_of_line (struct it *it) it->len = 1; if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 - && (it->glyph_row->used[LEFT_MARGIN_AREA] + && (it->glyph_row->used[LEFT_MARGIN_AREA] < WINDOW_LEFT_MARGIN_WIDTH (it->w)) && !it->glyph_row->mode_line_p && FACE_COLOR_TO_PIXEL (face->background, f) != FRAME_BACKGROUND_PIXEL (f)) @@ -20750,10 +20832,8 @@ extend_face_to_end_of_line (struct it *it) /* The last row's blank glyphs should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ - if (it->glyph_row->ends_at_zv_p) - it->face_id = default_face->id; - else - it->face_id = face->id; + it->face_id = (it->glyph_row->ends_at_zv_p ? + default_face->id : face->id); /* Display fill-column indicator if needed. */ int indicator_column = fill_column_indicator_column (it); @@ -20763,24 +20843,25 @@ extend_face_to_end_of_line (struct it *it) indicator_column = -1; do { - int saved_face_id; - bool indicate = it->current_x == indicator_column; - if (indicate) + if (it->current_x == indicator_column) { - saved_face_id = it->face_id; + int saved_face_id = it->face_id; + it->face_id - = merge_faces (it->w, Qfill_column_indicator, 0, saved_face_id); + = merge_faces (it->w, Qfill_column_indicator, 0, + it->extend_face_id); it->c = it->char_to_display = XFIXNAT (Vdisplay_fill_column_indicator_character); - } - PRODUCE_GLYPHS (it); + PRODUCE_GLYPHS (it); - if (indicate) - { it->face_id = saved_face_id; it->c = it->char_to_display = ' '; } + else + { + PRODUCE_GLYPHS (it); + } } while (it->current_x <= it->last_visible_x); @@ -25423,7 +25504,8 @@ display_count_lines (ptrdiff_t start_byte, Value is the number of columns displayed. */ static int -display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_string, +display_string (const char *string, Lisp_Object lisp_string, + Lisp_Object face_string, ptrdiff_t face_string_pos, ptrdiff_t start, struct it *it, int field_width, int precision, int max_x, int multibyte) { @@ -25446,12 +25528,13 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st if (STRINGP (face_string)) { ptrdiff_t endptr; - struct face *face; it->face_id = face_at_string_position (it->w, face_string, face_string_pos, 0, &endptr, it->base_face_id, false); - face = FACE_FROM_ID (it->f, it->face_id); + + struct face *face = FACE_FROM_ID (it->f, it->face_id); + it->face_box_p = face->box != FACE_NO_BOX; } @@ -27355,7 +27438,7 @@ font_for_underline_metrics (struct glyph_string *s) for (g = s->first_glyph - 1; g >= g0; g--) { struct face *prev_face = FACE_FROM_ID (s->f, g->face_id); - if (!(prev_face && prev_face->underline_p)) + if (!(prev_face && prev_face->underline != FACE_NO_UNDERLINE)) break; } diff --git a/src/xfaces.c b/src/xfaces.c index c3cae7e2a6..7987681ce9 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -1209,7 +1209,7 @@ free_face_colors (struct frame *f, struct face *face) IF_DEBUG (--ncolors_allocated); } - if (face->underline_p + if (face->underline && !face->underline_defaulted_p) { x_free_colors (f, &face->underline_color, 1); @@ -1590,6 +1590,7 @@ #define LFACE_BOX(LFACE) AREF ((LFACE), LFACE_BOX_INDEX) #define LFACE_FONT(LFACE) AREF ((LFACE), LFACE_FONT_INDEX) #define LFACE_INHERIT(LFACE) AREF ((LFACE), LFACE_INHERIT_INDEX) #define LFACE_FONTSET(LFACE) AREF ((LFACE), LFACE_FONTSET_INDEX) +#define LFACE_EXTEND(LFACE) AREF ((LFACE), LFACE_EXTEND_INDEX) #define LFACE_DISTANT_FOREGROUND(LFACE) \ AREF ((LFACE), LFACE_DISTANT_FOREGROUND_INDEX) @@ -2512,6 +2513,13 @@ merge_face_ref (struct window *w, err_msgs, named_merge_points)) err = true; } + else if (EQ (keyword, QCextend)) + { + if (EQ (value, Qt) || NILP (value)) + to[LFACE_EXTEND_INDEX] = value; + else + err = true; + } else err = true; @@ -3030,6 +3038,17 @@ DEFUN ("internal-set-lisp-face-attribute", Finternal_set_lisp_face_attribute, old_value = LFACE_INVERSE (lface); ASET (lface, LFACE_INVERSE_INDEX, value); } + else if (EQ (attr, QCextend)) + { + if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) + { + CHECK_SYMBOL (value); + if (!EQ (value, Qt) && !NILP (value)) + signal_error ("Invalid inverse-video face attribute value", value); + } + old_value = LFACE_EXTEND (lface); + ASET (lface, LFACE_EXTEND_INDEX, value); + } else if (EQ (attr, QCforeground)) { /* Compatibility with 20.x. */ @@ -3503,7 +3522,9 @@ DEFUN ("internal-set-lisp-face-attribute-from-resource", value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCweight) || EQ (attr, QCslant) || EQ (attr, QCwidth)) value = intern (SSDATA (value)); - else if (EQ (attr, QCreverse_video) || EQ (attr, QCinverse_video)) + else if (EQ (attr, QCreverse_video) + || EQ (attr, QCinverse_video) + || EQ (attr, QCextend)) value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCunderline) || EQ (attr, QCoverline) @@ -3727,6 +3748,8 @@ DEFUN ("internal-get-lisp-face-attribute", Finternal_get_lisp_face_attribute, value = LFACE_SWIDTH (lface); else if (EQ (keyword, QCinherit)) value = LFACE_INHERIT (lface); + else if (EQ (keyword, QCextend)) + value = LFACE_EXTEND (lface); else if (EQ (keyword, QCfont)) value = LFACE_FONT (lface); else if (EQ (keyword, QCfontset)) @@ -5694,16 +5717,14 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] if (EQ (underline, Qt)) { /* Use default color (same as foreground color). */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = true; face->underline_color = 0; } else if (STRINGP (underline)) { /* Use specified color. */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = false; face->underline_color = load_color (f, face, underline, @@ -5711,7 +5732,7 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] } else if (NILP (underline)) { - face->underline_p = false; + face->underline = FACE_NO_UNDERLINE; face->underline_defaulted_p = false; face->underline_color = 0; } @@ -5719,10 +5740,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] { /* `(:color COLOR :style STYLE)'. STYLE being one of `line' or `wave'. */ - face->underline_p = true; + face->underline = FACE_UNDER_LINE; face->underline_color = 0; face->underline_defaulted_p = true; - face->underline_type = FACE_UNDER_LINE; /* FIXME? This is also not robust about checking the precise form. See comments in Finternal_set_lisp_face_attribute. */ @@ -5755,9 +5775,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] else if (EQ (keyword, QCstyle)) { if (EQ (value, Qline)) - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; else if (EQ (value, Qwave)) - face->underline_type = FACE_UNDER_WAVE; + face->underline = FACE_UNDER_WAVE; } } } @@ -6292,9 +6312,8 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, { struct frame *f = WINDOW_XFRAME (w); Lisp_Object attrs[LFACE_VECTOR_SIZE]; - struct face *base_face; + struct face *base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); - base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); if (!base_face) return base_face_id; @@ -6319,12 +6338,14 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, } else { - struct face *face; if (face_id < 0) return base_face_id; - face = FACE_FROM_ID_OR_NULL (f, face_id); + + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); + if (!face) return base_face_id; + merge_face_vectors (w, f, face->lface, attrs, 0); } @@ -6412,7 +6433,7 @@ dump_realized_face (struct face *face) #endif fprintf (stderr, "fontset: %d\n", face->fontset); fprintf (stderr, "underline: %d (%s)\n", - face->underline_p, + face->underline, SDATA (Fsymbol_name (face->lface[LFACE_UNDERLINE_INDEX]))); fprintf (stderr, "hash: %" PRIuPTR "\n", face->hash); } @@ -6537,6 +6558,7 @@ syms_of_xfaces (void) DEFSYM (QCstrike_through, ":strike-through"); DEFSYM (QCbox, ":box"); DEFSYM (QCinherit, ":inherit"); + DEFSYM (QCextend, ":extend"); /* Symbols used for Lisp face attribute values. */ DEFSYM (QCcolor, ":color"); diff --git a/src/xterm.c b/src/xterm.c index b761eaf4d1..b8f8db56a7 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3798,9 +3798,9 @@ x_draw_glyph_string (struct glyph_string *s) if (!s->for_overlaps) { /* Draw underline. */ - if (s->face->underline_p) + if (s->face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { if (s->face->underline_defaulted_p) x_draw_underwave (s); @@ -3814,13 +3814,13 @@ x_draw_glyph_string (struct glyph_string *s) XSetForeground (display, s->gc, xgcv.foreground); } } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { unsigned long thickness, position; int y; - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE) + if (s->prev && + s->prev->face->underline == FACE_UNDER_LINE) { /* We use the same underline style as the previous one. */ thickness = s->prev->underline_thickness; ^ permalink raw reply related [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-04 20:19 ` Ergus via Emacs development discussions. @ 2019-09-05 7:32 ` martin rudalics 2019-09-05 13:54 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-09-05 7:32 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel > Here is the diff of the latest commit. (Patch attached anyway). Thanks. I tried with the patch.patch you attached. When trying a gtk build I get: ../../src/xfaces.c:5434: Emacs fatal error: assertion failed: lface_fully_specified_p (XVECTOR (lface)->contents) Fatal error 6: Aborted Backtrace: ../src/bootstrap-emacs[0x67e32f] ../src/bootstrap-emacs[0x6344c8] ../src/bootstrap-emacs[0x74fb6f] ../src/bootstrap-emacs[0x5a8e43] ../src/bootstrap-emacs[0x5a83f8] ../src/bootstrap-emacs[0x59bccf] ../src/bootstrap-emacs[0x436ad1] ../src/bootstrap-emacs[0x4fd0ad] ../src/bootstrap-emacs[0x76376c] ../src/bootstrap-emacs[0x63530c] ../src/bootstrap-emacs[0x635860] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f68217952e1] ../src/bootstrap-emacs[0x4151aa] /bin/bash: Zeile 2: 12088 Abgebrochen EMACSLOADPATH= '../src/bootstrap-emacs' -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)' -l bytecomp -f byte-compile-refresh-preloaded -f batch-byte-compile ../../lisp/cus-face.el Makefile:280: die Regel für Ziel „../../lisp/cus-face.elc“ scheiterte make[2]: *** [../../lisp/cus-face.elc] Fehler 134 Makefile:784: die Regel für Ziel „../../lisp/cus-face.elc“ scheiterte make[1]: *** [../../lisp/cus-face.elc] Fehler 2 make[1]: *** Es wird auf noch nicht beendete Prozesse gewartet... ../../src/xfaces.c:5434: Emacs fatal error: assertion failed: lface_fully_specified_p (XVECTOR (lface)->contents) Backtrace: ../src/bootstrap-emacs[0x67e32f] ../src/bootstrap-emacs[0x6344c8] ../src/bootstrap-emacs[0x74fb6f] ../src/bootstrap-emacs[0x5a8e43] ../src/bootstrap-emacs[0x5a83f8] ../src/bootstrap-emacs[0x59bccf] ../src/bootstrap-emacs[0x436ad1] ../src/bootstrap-emacs[0x4fd0ad] ../src/bootstrap-emacs[0x76376c] ../src/bootstrap-emacs[0x63530c] ../src/bootstrap-emacs[0x635860] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f0e8f3a32e1] ../src/bootstrap-emacs[0x4151aa] /bin/bash: Zeile 2: 12090 Abgebrochen EMACSLOADPATH= '../src/bootstrap-emacs' -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)' -l bytecomp -f byte-compile-refresh-preloaded -f batch-byte-compile ../../lisp/faces.el Makefile:280: die Regel für Ziel „../../lisp/faces.elc“ scheiterte make[2]: *** [../../lisp/faces.elc] Fehler 134 Makefile:784: die Regel für Ziel „../../lisp/faces.elc“ scheiterte make[1]: *** [../../lisp/faces.elc] Fehler 2 make[1]: Verzeichnis „/home/martin/emacs-git/trunk/obj-gtk/src“ wird verlassen Makefile:424: die Regel für Ziel „src“ scheiterte make: *** [src] Fehler 2 and a similar crash on Windows. Before proceeding to dig into this I'd like to hear your ideas. > https://github.com/Ergus/Emacs/commit/4943087027acd3f2c7a54a092b64bc839ef8850e Is there any way to get the diffs wrt current master on that site? I never use github for such a thing and my browser settings are quite restrictive. Thanks, martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-05 7:32 ` martin rudalics @ 2019-09-05 13:54 ` Ergus 2019-09-05 19:31 ` Ergus 0 siblings, 1 reply; 183+ messages in thread From: Ergus @ 2019-09-05 13:54 UTC (permalink / raw) To: rudalics; +Cc: eliz, emacs-devel [-- Attachment #1: Type: text/plain, Size: 3411 bytes --] For some reason I was not facing this; but it was actually a bug I just fixed. I'll send a patch in a while because this exposed an issue somewhere else. -----Original Message----- From: martin rudalics <rudalics@gmx.at> To: Ergus <spacibba@aol.com> Cc: Eli Zaretskii <eliz@gnu.org>; emacs-devel <emacs-devel@gnu.org> Sent: Thu, Sep 5, 2019 11:24 am Subject: Re: Question about display engine > Here is the diff of the latest commit. (Patch attached anyway). Thanks. I tried with the patch.patch you attached. When trying a gtk build I get: ../../src/xfaces.c:5434: Emacs fatal error: assertion failed: lface_fully_specified_p (XVECTOR (lface)->contents) Fatal error 6: Aborted Backtrace: ../src/bootstrap-emacs[0x67e32f] ../src/bootstrap-emacs[0x6344c8] ../src/bootstrap-emacs[0x74fb6f] ../src/bootstrap-emacs[0x5a8e43] ../src/bootstrap-emacs[0x5a83f8] ../src/bootstrap-emacs[0x59bccf] ../src/bootstrap-emacs[0x436ad1] ../src/bootstrap-emacs[0x4fd0ad] ../src/bootstrap-emacs[0x76376c] ../src/bootstrap-emacs[0x63530c] ../src/bootstrap-emacs[0x635860] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f68217952e1] ../src/bootstrap-emacs[0x4151aa] /bin/bash: Zeile 2: 12088 Abgebrochen EMACSLOADPATH= '../src/bootstrap-emacs' -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)' -l bytecomp -f byte-compile-refresh-preloaded -f batch-byte-compile ../../lisp/cus-face.el Makefile:280: die Regel für Ziel „../../lisp/cus-face.elc“ scheiterte make[2]: *** [../../lisp/cus-face.elc] Fehler 134 Makefile:784: die Regel für Ziel „../../lisp/cus-face.elc“ scheiterte make[1]: *** [../../lisp/cus-face.elc] Fehler 2 make[1]: *** Es wird auf noch nicht beendete Prozesse gewartet... ../../src/xfaces.c:5434: Emacs fatal error: assertion failed: lface_fully_specified_p (XVECTOR (lface)->contents) Backtrace: ../src/bootstrap-emacs[0x67e32f] ../src/bootstrap-emacs[0x6344c8] ../src/bootstrap-emacs[0x74fb6f] ../src/bootstrap-emacs[0x5a8e43] ../src/bootstrap-emacs[0x5a83f8] ../src/bootstrap-emacs[0x59bccf] ../src/bootstrap-emacs[0x436ad1] ../src/bootstrap-emacs[0x4fd0ad] ../src/bootstrap-emacs[0x76376c] ../src/bootstrap-emacs[0x63530c] ../src/bootstrap-emacs[0x635860] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f0e8f3a32e1] ../src/bootstrap-emacs[0x4151aa] /bin/bash: Zeile 2: 12090 Abgebrochen EMACSLOADPATH= '../src/bootstrap-emacs' -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)' -l bytecomp -f byte-compile-refresh-preloaded -f batch-byte-compile ../../lisp/faces.el Makefile:280: die Regel für Ziel „../../lisp/faces.elc“ scheiterte make[2]: *** [../../lisp/faces.elc] Fehler 134 Makefile:784: die Regel für Ziel „../../lisp/faces.elc“ scheiterte make[1]: *** [../../lisp/faces.elc] Fehler 2 make[1]: Verzeichnis „/home/martin/emacs-git/trunk/obj-gtk/src“ wird verlassen Makefile:424: die Regel für Ziel „src“ scheiterte make: *** [src] Fehler 2 and a similar crash on Windows. Before proceeding to dig into this I'd like to hear your ideas. > https://github.com/Ergus/Emacs/commit/4943087027acd3f2c7a54a092b64bc839ef8850e Is there any way to get the diffs wrt current master on that site? I never use github for such a thing and my browser settings are quite restrictive. Thanks, martin [-- Attachment #2: Type: text/html, Size: 4921 bytes --] ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-09-05 13:54 ` Ergus @ 2019-09-05 19:31 ` Ergus 0 siblings, 0 replies; 183+ messages in thread From: Ergus @ 2019-09-05 19:31 UTC (permalink / raw) To: rudalics; +Cc: eliz, emacs-devel [-- Attachment #1: Type: text/plain, Size: 3757 bytes --] BTW: in the code are come comments starting with // ERGUS: that is code not clear for me what to do there. -----Original Message----- From: Ergus <spacibba@aol.com> To: rudalics <rudalics@gmx.at> Cc: eliz <eliz@gnu.org>; emacs-devel <emacs-devel@gnu.org> Sent: Thu, Sep 5, 2019 3:55 pm Subject: Re: Question about display engine For some reason I was not facing this; but it was actually a bug I just fixed. I'll send a patch in a while because this exposed an issue somewhere else. -----Original Message----- From: martin rudalics <rudalics@gmx.at> To: Ergus <spacibba@aol.com> Cc: Eli Zaretskii <eliz@gnu.org>; emacs-devel <emacs-devel@gnu.org> Sent: Thu, Sep 5, 2019 11:24 am Subject: Re: Question about display engine > Here is the diff of the latest commit. (Patch attached anyway). Thanks. I tried with the patch.patch you attached. When trying a gtk build I get: ../../src/xfaces.c:5434: Emacs fatal error: assertion failed: lface_fully_specified_p (XVECTOR (lface)->contents) Fatal error 6: Aborted Backtrace: ../src/bootstrap-emacs[0x67e32f] ../src/bootstrap-emacs[0x6344c8] ../src/bootstrap-emacs[0x74fb6f] ../src/bootstrap-emacs[0x5a8e43] ../src/bootstrap-emacs[0x5a83f8] ../src/bootstrap-emacs[0x59bccf] ../src/bootstrap-emacs[0x436ad1] ../src/bootstrap-emacs[0x4fd0ad] ../src/bootstrap-emacs[0x76376c] ../src/bootstrap-emacs[0x63530c] ../src/bootstrap-emacs[0x635860] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f68217952e1] ../src/bootstrap-emacs[0x4151aa] /bin/bash: Zeile 2: 12088 Abgebrochen EMACSLOADPATH= '../src/bootstrap-emacs' -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)' -l bytecomp -f byte-compile-refresh-preloaded -f batch-byte-compile ../../lisp/cus-face.el Makefile:280: die Regel für Ziel „../../lisp/cus-face.elc“ scheiterte make[2]: *** [../../lisp/cus-face.elc] Fehler 134 Makefile:784: die Regel für Ziel „../../lisp/cus-face.elc“ scheiterte make[1]: *** [../../lisp/cus-face.elc] Fehler 2 make[1]: *** Es wird auf noch nicht beendete Prozesse gewartet... ../../src/xfaces.c:5434: Emacs fatal error: assertion failed: lface_fully_specified_p (XVECTOR (lface)->contents) Backtrace: ../src/bootstrap-emacs[0x67e32f] ../src/bootstrap-emacs[0x6344c8] ../src/bootstrap-emacs[0x74fb6f] ../src/bootstrap-emacs[0x5a8e43] ../src/bootstrap-emacs[0x5a83f8] ../src/bootstrap-emacs[0x59bccf] ../src/bootstrap-emacs[0x436ad1] ../src/bootstrap-emacs[0x4fd0ad] ../src/bootstrap-emacs[0x76376c] ../src/bootstrap-emacs[0x63530c] ../src/bootstrap-emacs[0x635860] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f0e8f3a32e1] ../src/bootstrap-emacs[0x4151aa] /bin/bash: Zeile 2: 12090 Abgebrochen EMACSLOADPATH= '../src/bootstrap-emacs' -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)' -l bytecomp -f byte-compile-refresh-preloaded -f batch-byte-compile ../../lisp/faces.el Makefile:280: die Regel für Ziel „../../lisp/faces.elc“ scheiterte make[2]: *** [../../lisp/faces.elc] Fehler 134 Makefile:784: die Regel für Ziel „../../lisp/faces.elc“ scheiterte make[1]: *** [../../lisp/faces.elc] Fehler 2 make[1]: Verzeichnis „/home/martin/emacs-git/trunk/obj-gtk/src“ wird verlassen Makefile:424: die Regel für Ziel „src“ scheiterte make: *** [src] Fehler 2 and a similar crash on Windows. Before proceeding to dig into this I'd like to hear your ideas. > https://github.com/Ergus/Emacs/commit/4943087027acd3f2c7a54a092b64bc839ef8850e Is there any way to get the diffs wrt current master on that site? I never use github for such a thing and my browser settings are quite restrictive. Thanks, martin [-- Attachment #2: Type: text/html, Size: 5809 bytes --] ^ permalink raw reply [flat|nested] 183+ messages in thread
[parent not found: <1826922767.1725310.1567682307734@mail.yahoo.com>]
* Re: Question about display engine [not found] ` <1826922767.1725310.1567682307734@mail.yahoo.com> @ 2019-09-05 11:18 ` Ergus 0 siblings, 0 replies; 183+ messages in thread From: Ergus @ 2019-09-05 11:18 UTC (permalink / raw) To: rudalics; +Cc: eliz, emacs-devel [-- Attachment #1: Type: text/plain, Size: 2006 bytes --] Hi again: I was just checking the code once again and it is actually working. Theproblem before was in the lisp part. the interactive functions: (set-face-extend 'region t) does not change the face value when called interactively. (We haveobserved similar issues before with customize-variable and maybe itneeds to be fix.) They seem to be changing the values of the variableslocally in the minibuffer instead of the "caller" buffer. But it workswhen executed throw C-x C-e; so maybe some lisper can give a look tothis please. As now it works at least for the region and fixes these issues. 1) Tui and gui extension is consistent (still needs some work but shouldbe a minor issues to fix) 2) the region extension can be customized (which could be considered anew feature). 3) The interaction with dfci reported in the bug that started this isnot broken anymore. At the end I implemented it lazily because it appeared to be the easiestalternative for me; but I am completely open to any comment/suggestion(please ignore code style for now.) Finally I have a explicit question: when we set :extend nil for the region face do you consider correct thatthe extra space we always add must have the region color (instead of thedefault) in order to seea colored space in the empty lines? -----Original Message----- From: martin rudalics <rudalics@gmx.at> To: Ergus <spacibba@aol.com> Cc: Eli Zaretskii <eliz@gnu.org>; emacs-devel <emacs-devel@gnu.org> Sent: Wed, Sep 4, 2019 10:34 pm Subject: Re: Question about display engine > I have just uploaded some changes but the functionality is still not > working. > > I separated the changes in 3 commits and in the last one are only the > ones I made in the xdisp.c (the ones that need to be checked, because > the rest is only infrastructure.) > > see the master branch in: https://github.com/Ergus/Emacs Please send a patch for current master. Otherwise I have no idea how to compare your changes. Thanks, martin [-- Attachment #2: Type: text/html, Size: 3886 bytes --] ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-19 16:13 ` Ergus 2019-08-19 16:50 ` Eli Zaretskii @ 2019-08-21 7:37 ` martin rudalics 1 sibling, 0 replies; 183+ messages in thread From: martin rudalics @ 2019-08-21 7:37 UTC (permalink / raw) To: Ergus; +Cc: Eli Zaretskii, emacs-devel > Extending the underline|overline to the right of the line in the region > is a fancy detail, but I don't find it useful at all (underlining empty > long spaces is conceptually an error), and in the actual gui it is not > happening (not even extend_face_to_end_of_line in gui is executed as the > background color is extended automatically somewhere else) and there > haven't been complains either, so there is not people using that, so why > do we provide a complex solution implementation for a problem nobody > really cares and that potentially will produce overheads, code > complexity and more issues? > > I am wondering about over-specifications and over-engineering for such a > detail, when most of the users only need to extend the background color. Agreed. But what would we do when in the foreseeable future somebody asks us to provide such a feature? No one here has Eli's experience when it comes to guessing at what Emacs users might eventually want. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 8:38 ` Ergus 2019-08-08 8:45 ` martin rudalics @ 2019-08-08 17:37 ` Eli Zaretskii 2019-08-09 12:46 ` martin rudalics 2019-08-08 17:38 ` Eli Zaretskii 2 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-08 17:37 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Thu, 8 Aug 2019 10:38:04 +0200 > From: Ergus <spacibba@aol.com> > Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org > > >I now think it would make more sense to add an 'extend-to-window-edge' > >attribute in the face definition itself. > > I like that option as a concept, but it adds a new flag to a general > struct like the face for something that only affects the region face > now. As mentioned up-thread, this affects not only the region face. So perhaps a face attribute is indeed a good solution. But I still feel that this is not about faces, this is about face attributes, so the customization should on the attribute level, not on the face level. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 17:37 ` Eli Zaretskii @ 2019-08-09 12:46 ` martin rudalics 2019-08-10 11:25 ` Eli Zaretskii 0 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-09 12:46 UTC (permalink / raw) To: Eli Zaretskii, Ergus; +Cc: emacs-devel > As mentioned up-thread, this affects not only the region face. So > perhaps a face attribute is indeed a good solution. > > But I still feel that this is not about faces, this is about face > attributes, so the customization should on the attribute level, not on > the face level. You're right. But then the earlier 'face-extend-to-window-edge' is not appropriate either. Maybe we could start with a simple 'extend-face-background' option (and add others if needed)? If we agree that "most" backgrounds should not extend, otherwise we should probably add an 'inhibit-extend-face-background' option. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-09 12:46 ` martin rudalics @ 2019-08-10 11:25 ` Eli Zaretskii 2019-08-10 23:04 ` Stefan Monnier 2019-08-11 8:11 ` martin rudalics 0 siblings, 2 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-10 11:25 UTC (permalink / raw) To: martin rudalics; +Cc: spacibba, emacs-devel > Cc: emacs-devel@gnu.org > From: martin rudalics <rudalics@gmx.at> > Date: Fri, 9 Aug 2019 14:46:03 +0200 > > > But I still feel that this is not about faces, this is about face > > attributes, so the customization should on the attribute level, not on > > the face level. > > You're right. But then the earlier 'face-extend-to-window-edge' is > not appropriate either. Right, that idea eats dust. > Maybe we could start with a simple 'extend-face-background' option > (and add others if needed)? What about users who change the region or hl-line faces to use underlining? IOW, the problem with the attribute-level idea is that it will affect those attributes regardless of the face from which they came. So I now tend to think that if we consider some faces not eligible for extension, we should not extend any face attributes at all. Too bad no one else except the 3 of us is talking in this thread; we need more opinions. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-10 11:25 ` Eli Zaretskii @ 2019-08-10 23:04 ` Stefan Monnier 2019-08-11 2:43 ` Eli Zaretskii 2019-08-11 8:11 ` martin rudalics 1 sibling, 1 reply; 183+ messages in thread From: Stefan Monnier @ 2019-08-10 23:04 UTC (permalink / raw) To: Eli Zaretskii; +Cc: martin rudalics, spacibba, emacs-devel > IOW, the problem with the attribute-level idea is that it will affect > those attributes regardless of the face from which they came. Per-face indeed sounds like a better option than per-attribute. Furthermore, it should be much easier to add it in a clean way to the current system. Of course per-face per-attribute would be even more flexible, but I'm not completely convinced it's worth the trouble. Stefan ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-10 23:04 ` Stefan Monnier @ 2019-08-11 2:43 ` Eli Zaretskii 2019-08-11 8:17 ` martin rudalics 0 siblings, 1 reply; 183+ messages in thread From: Eli Zaretskii @ 2019-08-11 2:43 UTC (permalink / raw) To: Stefan Monnier; +Cc: rudalics, spacibba, emacs-devel > From: Stefan Monnier <monnier@iro.umontreal.ca> > Date: Sat, 10 Aug 2019 19:04:13 -0400 > Cc: martin rudalics <rudalics@gmx.at>, spacibba@aol.com, emacs-devel@gnu.org > > > IOW, the problem with the attribute-level idea is that it will affect > > those attributes regardless of the face from which they came. > > Per-face indeed sounds like a better option than per-attribute. > Furthermore, it should be much easier to add it in a clean way to the > current system. > > Of course per-face per-attribute would be even more flexible, but I'm > not completely convinced it's worth the trouble. I later came to the conclusion that even per-face is not really workable, due to face merging. WDYT? ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-11 2:43 ` Eli Zaretskii @ 2019-08-11 8:17 ` martin rudalics 0 siblings, 0 replies; 183+ messages in thread From: martin rudalics @ 2019-08-11 8:17 UTC (permalink / raw) To: Eli Zaretskii, Stefan Monnier; +Cc: spacibba, emacs-devel >> Per-face indeed sounds like a better option than per-attribute. >> Furthermore, it should be much easier to add it in a clean way to the >> current system. >> >> Of course per-face per-attribute would be even more flexible, but I'm >> not completely convinced it's worth the trouble. > > I later came to the conclusion that even per-face is not really > workable, due to face merging. WDYT? I think both would be feasible. Just that with a face attribute the face merger would have to specify whether a certain property should extend to the end of line while with an attribute property the (face agnostic) display engine could handle face extension alone. Suppose we want to display a newline character that is both highlighted and part of the region and assume that highlighting is realized via :underline and the region via :background. With the face attribute based approach, the face merger would set a 'background-extend' flag according to the :extend attribute of the region face and an 'underline-extend' flag according to the :extend attribute of the highlight face. The face agnostic display engine would use these flags to decide whether the corresponding properties should extend to the edge of the window or not With the attribute based approach, the display engine would extend the background directly from the newline character corresponding to whether the background attribute's extend property was set (for example, because 'background' is explicitly listed in an 'attribute-extend' variable) and do the same for the newline's underline property (if we wanted to allow that). The face-based approach will "misfire" when a user decides to show the region via underline and sets the region's extend property. I'd consider that a pilot error. The attribute-based approach will misfire when the user makes the underline attribute have the extend property (if we allowed to do that). Or am I missing something? martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-10 11:25 ` Eli Zaretskii 2019-08-10 23:04 ` Stefan Monnier @ 2019-08-11 8:11 ` martin rudalics 1 sibling, 0 replies; 183+ messages in thread From: martin rudalics @ 2019-08-11 8:11 UTC (permalink / raw) To: Eli Zaretskii; +Cc: spacibba, emacs-devel >> Maybe we could start with a simple 'extend-face-background' option >> (and add others if needed)? > > What about users who change the region or hl-line faces to use > underlining? Any underlining behavior would remain unaffected by setting 'extend-face-background'. If both, underlining and background are specified, the display engine would do what it does now. > IOW, the problem with the attribute-level idea is that it will affect > those attributes regardless of the face from which they came. If the 'extend-face-background' is a simple boolean, yes. If it is a list of faces, it is largely idempotent to the face-level concept: A user could say (by including or excluding) a face from that list whether it should have any impact on extending the background to the end of the window edge. Just that the face merger would have to process that variable if it is a list of faces while handling it in the display engine would be sufficient for a boolean. > So I now tend to think that if we consider some faces not eligible for Didn't you mean to say "some face attributes not eligible" here ... > extension, we should not extend any face attributes at all. Too bad > no one else except the 3 of us is talking in this thread; we need more > opinions. ... because otherwise I don't see how we possibly could do that. IIUC the face merger would then have to decide whether "that" occurred. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 8:38 ` Ergus 2019-08-08 8:45 ` martin rudalics 2019-08-08 17:37 ` Eli Zaretskii @ 2019-08-08 17:38 ` Eli Zaretskii 2 siblings, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-08 17:38 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Thu, 8 Aug 2019 10:38:04 +0200 > From: Ergus <spacibba@aol.com> > Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org > > Looking at the merge_face function could anyone please explain better > what means: realized face and lface_id and please direct me to where is > documented how emacs uses the faces internally; the functionalities > available and specially the merge rules? You need to read xfaces.c, the code is all there. Feel free to ask questions if the code doesn't speak for itself. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-07 16:41 ` Eli Zaretskii 2019-08-08 7:25 ` martin rudalics @ 2019-08-08 8:15 ` Ergus 2019-08-08 8:45 ` martin rudalics ` (2 more replies) 1 sibling, 3 replies; 183+ messages in thread From: Ergus @ 2019-08-08 8:15 UTC (permalink / raw) To: Eli Zaretskii; +Cc: martin rudalics, emacs-devel On Wed, Aug 07, 2019 at 07:41:25PM +0300, Eli Zaretskii wrote: >> Cc: emacs-devel@gnu.org >> From: martin rudalics <rudalics@gmx.at> >> Date: Wed, 7 Aug 2019 18:25:37 +0200 >> >> > And, of course, this leaves the more general problem I described in my >> > message: what is the right behavior for extending the face that >> > crosses a newline. (Note that the display engine in general doesn't >> > know whether a face that doesn't end before a newline will or won't >> > continue on the next screen line.) >> >> Recalling your proposal >> >> (defcustom face-extend-to-window-edge t >> "Non-nil means extend face of last character on line to window edge. > >Thanks for the reminder. > >> Certain face attributes, if present in the face of the last character >> of a line and different from those of the default face, cause the >> empty space following the end of text on the line to be drawn with >> those attributes, to give the empty space appearance similar to that >> of the preceding text. These attributes are those which affect the >> background of a face: `:background', `:stipple', `:box', `:underline', >> `:overline', and `:strike-through'. By default, if the face of a >> line's last character has any of these attributes, and the value is >> different from that of the default face, the empty space following the >> line's text will be drawn in the face of the last character. > >This is inaccurate, I think: on GUI frames only :background and :box >are extended all the way, the rest only "infect" the glyph we add for >displaying the newline. > >> This variable allows fine-tuning which attributes trigger the face >> extension. The default value of t means any of the mentioned >> attributes will cause face extension. The value of nil means face >> extension is turned off. A value that is a list of attributes will >> extend the face only if any of the attributes from the list are >> present in the last character's face. Note that only attributes from >> the above list are meaningful in list values of this variable.") >> >> in the discussion of Bug#23574. > >And I think we need to consider the case of the region using one of >the attributes that are not in the list. > In gui our actual behavior seems to be very reasonable and simple (And we haven't too many complains about this.). It extends the region colors, but not the underline (and similes). For me this makes sense because underline empty spaces after \n, until the page border, does not really means anything as conceptually there is nothing that should be underlined there. The "surprise" is that there is no code for this effect in the display engine and it has to do with some X||gtk feature in use. (That's why I needed to ad an extra glyph after the indicator.) Comparing around: VIM, when toggle to visual mode it only highlights the real text. The rest of the line stays unchanged. This is useful to detect trailing whitespaces when no set by default (I am not telling that we should adopt that approach, but it looks very reasonable and simple and it is the default in most gui libraries; so also for the users) Geany, QtCreator, Sublime, Web Browsers (Firefox, chromium), MS Word, all of them do the same. Eclipse, on the other hand, extends the color to the end of the line as we do, but it only allows to set background and foreground to what we call region. So no underlined region to worry about. I think that these are the most extended approaches around (so we don't need to reinvent the wheel) and Eli should make the design choice so we/he can start implementing that; otherwise it will be forgotten after hours and hours of arguments and at the end there will be always somebody unhappy. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 8:15 ` Ergus @ 2019-08-08 8:45 ` martin rudalics 2019-08-08 9:17 ` Ergus 2019-08-08 17:35 ` Eli Zaretskii 2019-08-08 20:37 ` Juri Linkov 2 siblings, 1 reply; 183+ messages in thread From: martin rudalics @ 2019-08-08 8:45 UTC (permalink / raw) To: Ergus, Eli Zaretskii; +Cc: emacs-devel > VIM, when toggle to visual mode it only highlights the real > text. The rest of the line stays unchanged. This is useful to detect > trailing whitespaces when no set by default ... at the expense of not being able to tell where the region ends or starts within a bunch of consecutive newlines ... > (I am not telling that we > should adopt that approach, but it looks very reasonable and simple and > it is the default in most gui libraries; so also for the users) > I think that these are the most extended approaches around (so we don't > need to reinvent the wheel) and Eli should make the design choice so > we/he can start implementing that; otherwise it will be forgotten after > hours and hours of arguments and at the end there will be always > somebody unhappy. Indeed. martin ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 8:45 ` martin rudalics @ 2019-08-08 9:17 ` Ergus 0 siblings, 0 replies; 183+ messages in thread From: Ergus @ 2019-08-08 9:17 UTC (permalink / raw) To: emacs-devel, martin rudalics, Eli Zaretskii On August 8, 2019 10:45:49 AM GMT+02:00, martin rudalics <rudalics@gmx.at> wrote: > > VIM, when toggle to visual mode it only highlights the real > > text. The rest of the line stays unchanged. This is useful to detect > > trailing whitespaces when no set by default > >... at the expense of not being able to tell where the region ends or >starts within a bunch of consecutive newlines ... > In our case in gui we have a space for new line that can be highlited even in empty lines at the end of the line. In vim this space only exists in insert mode. > > (I am not telling that we >> should adopt that approach, but it looks very reasonable and simple >and > > it is the default in most gui libraries; so also for the users) > >> I think that these are the most extended approaches around (so we >don't > > need to reinvent the wheel) and Eli should make the design choice so >> we/he can start implementing that; otherwise it will be forgotten >after > > hours and hours of arguments and at the end there will be always > > somebody unhappy. > >Indeed. > >martin -- Sent from my Android device with K-9 Mail. Please excuse my brevity. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 8:15 ` Ergus 2019-08-08 8:45 ` martin rudalics @ 2019-08-08 17:35 ` Eli Zaretskii 2019-08-08 20:37 ` Juri Linkov 2 siblings, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-08 17:35 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel > Date: Thu, 8 Aug 2019 10:15:53 +0200 > From: Ergus <spacibba@aol.com> > Cc: martin rudalics <rudalics@gmx.at>, emacs-devel@gnu.org > > In gui our actual behavior seems to be very reasonable and simple (And > we haven't too many complains about this.). It extends the region > colors, but not the underline (and similes). For me this makes sense > because underline empty spaces after \n, until the page border, does not > really means anything as conceptually there is nothing that should be > underlined there. > > The "surprise" is that there is no code for this effect in the display > engine and it has to do with some X||gtk feature in use. (That's why I > needed to ad an extra glyph after the indicator.) We simply clear-to-end-of-line using the background color. > I think that these are the most extended approaches around (so we don't > need to reinvent the wheel) and Eli should make the design choice so > we/he can start implementing that; otherwise it will be forgotten after > hours and hours of arguments and at the end there will be always > somebody unhappy. I don't think this is just my decision, I still hope others will chime in with opinions. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 8:15 ` Ergus 2019-08-08 8:45 ` martin rudalics 2019-08-08 17:35 ` Eli Zaretskii @ 2019-08-08 20:37 ` Juri Linkov 2019-08-08 22:24 ` Ergus 2 siblings, 1 reply; 183+ messages in thread From: Juri Linkov @ 2019-08-08 20:37 UTC (permalink / raw) To: Ergus; +Cc: martin rudalics, Eli Zaretskii, emacs-devel > I think that these are the most extended approaches around (so we don't > need to reinvent the wheel) and Eli should make the design choice so > we/he can start implementing that; otherwise it will be forgotten after > hours and hours of arguments and at the end there will be always > somebody unhappy. While designing please consider supporting at least 3 options: - extend highlighting to the window edge as most faces do now; - highlight only to the end of lines as underline does now; - limit highlighting to a fixed customizable column like display-fill-column-indicator defaulting to fill-column. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 20:37 ` Juri Linkov @ 2019-08-08 22:24 ` Ergus 2019-08-09 6:42 ` Eli Zaretskii 2019-08-09 17:54 ` Juri Linkov 0 siblings, 2 replies; 183+ messages in thread From: Ergus @ 2019-08-08 22:24 UTC (permalink / raw) To: Juri Linkov; +Cc: martin rudalics, Eli Zaretskii, emacs-devel On Thu, Aug 08, 2019 at 11:37:32PM +0300, Juri Linkov wrote: >> I think that these are the most extended approaches around (so we don't >> need to reinvent the wheel) and Eli should make the design choice so >> we/he can start implementing that; otherwise it will be forgotten after >> hours and hours of arguments and at the end there will be always >> somebody unhappy. > >While designing please consider supporting at least 3 options: >- extend highlighting to the window edge as most faces do now; >- highlight only to the end of lines as underline does now; >- limit highlighting to a fixed customizable column like > display-fill-column-indicator defaulting to fill-column. Hi Juri: Up to now we are only dealing with the first two cases... The third one will add even more complexity (and corner cases when dealing with dfci) for a very low gain (in my opinion) because I don't find yet any use case for it. I am not telling it is impossible, just unneeded. If you have a good use case for it, please share it. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 22:24 ` Ergus @ 2019-08-09 6:42 ` Eli Zaretskii 2019-08-09 17:54 ` Juri Linkov 1 sibling, 0 replies; 183+ messages in thread From: Eli Zaretskii @ 2019-08-09 6:42 UTC (permalink / raw) To: Ergus; +Cc: rudalics, emacs-devel, juri > Date: Fri, 9 Aug 2019 00:24:04 +0200 > From: Ergus <spacibba@aol.com> > Cc: martin rudalics <rudalics@gmx.at>, Eli Zaretskii <eliz@gnu.org>, > emacs-devel@gnu.org > > If you have a good use case for it, please share it. Seconded. ^ permalink raw reply [flat|nested] 183+ messages in thread
* Re: Question about display engine 2019-08-08 22:24 ` Ergus 2019-08-09 6:42 ` Eli Zaretskii @ 2019-08-09 17:54 ` Juri Linkov 1 sibling, 0 replies; 183+ messages in thread From: Juri Linkov @ 2019-08-09 17:54 UTC (permalink / raw) To: Ergus; +Cc: martin rudalics, Eli Zaretskii, emacs-devel [-- Attachment #1: Type: text/plain, Size: 867 bytes --] >>- extend highlighting to the window edge as most faces do now; >>- highlight only to the end of lines as underline does now; >>- limit highlighting to a fixed customizable column like >> display-fill-column-indicator defaulting to fill-column. > > Up to now we are only dealing with the first two cases... The third one > will add even more complexity (and corner cases when dealing with dfci) > for a very low gain (in my opinion) because I don't find yet any use > case for it. I am not telling it is impossible, just unneeded. > > If you have a good use case for it, please share it. The third one is for purely aesthetic reasons: a single window on a very wide frame usually is full of ribbons (like on the first screenshot) whereas for example, the second screenshot (that was edited) shows how limiting face scope by fill-column is more visually pleasant. [-- Attachment #2: 1_window-edge-faces.png --] [-- Type: image/png, Size: 129102 bytes --] [-- Attachment #3: 2_fill-column-faces.png --] [-- Type: image/png, Size: 129138 bytes --] ^ permalink raw reply [flat|nested] 183+ messages in thread
end of thread, other threads:[~2019-10-21 6:38 UTC | newest] Thread overview: 183+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <318675867.1913640.1567711569517.ref@mail.yahoo.com> 2019-09-05 19:26 ` Question about display engine Ergus 2019-09-06 8:22 ` martin rudalics 2019-09-06 9:31 ` Ergus 2019-09-07 6:52 ` martin rudalics 2019-09-07 7:37 ` Eli Zaretskii 2019-09-07 7:55 ` Eli Zaretskii 2019-09-08 0:51 ` Ergus via Emacs development discussions. 2019-09-08 8:40 ` martin rudalics 2019-09-08 12:53 ` Ergus 2019-09-09 7:39 ` martin rudalics 2019-09-09 13:56 ` Ergus 2019-09-09 16:00 ` Eli Zaretskii 2019-09-09 17:08 ` Ergus 2019-09-09 18:08 ` Eli Zaretskii 2019-09-09 19:29 ` Ergus 2019-09-10 2:27 ` Eli Zaretskii 2019-09-12 3:37 ` Ergus 2019-09-13 8:50 ` Eli Zaretskii 2019-09-08 17:51 ` Eli Zaretskii 2019-09-08 18:23 ` Ergus 2019-09-14 20:42 ` Ergus 2019-09-15 8:25 ` martin rudalics 2019-09-15 11:26 ` Ergus 2019-09-15 12:22 ` martin rudalics 2019-09-15 14:28 ` Stefan Monnier 2019-09-16 9:05 ` martin rudalics 2019-09-15 15:32 ` Eli Zaretskii 2019-09-15 21:42 ` Ergus 2019-09-17 2:17 ` Ergus 2019-09-17 9:48 ` Eli Zaretskii 2019-09-21 8:20 ` Eli Zaretskii 2019-09-21 13:57 ` Ergus 2019-09-21 21:55 ` Ergus 2019-09-26 16:32 ` Ergus 2019-09-28 10:35 ` Eli Zaretskii 2019-09-29 10:30 ` Ergus 2019-09-29 10:57 ` Eli Zaretskii 2019-10-07 15:40 ` Ergus 2019-10-09 9:02 ` Eli Zaretskii 2019-10-12 18:16 ` Ergus 2019-10-12 18:29 ` Eli Zaretskii 2019-09-06 8:55 ` Eli Zaretskii 2019-09-06 10:30 ` Ergus 2019-09-06 13:28 ` Eli Zaretskii 2019-09-06 16:34 ` Ergus 2019-09-06 18:12 ` Eli Zaretskii 2019-09-07 2:35 ` Ergus 2019-09-07 6:41 ` Eli Zaretskii [not found] <20191012222305.jpjinkd5y2lz6xiv@Ergus> [not found] ` <83mue5kmfx.fsf@gnu.org> 2019-10-13 15:40 ` Ergus 2019-10-13 16:06 ` Eli Zaretskii 2019-10-13 16:44 ` Ergus 2019-10-13 17:04 ` Eli Zaretskii 2019-10-13 18:11 ` Ergus 2019-10-13 18:25 ` Ergus 2019-10-13 18:53 ` Eli Zaretskii 2019-10-13 19:38 ` Ergus 2019-10-13 21:01 ` Eli Zaretskii 2019-10-13 22:27 ` Ergus 2019-10-14 8:26 ` Eli Zaretskii 2019-10-20 22:20 ` Ergus 2019-10-21 6:38 ` Eli Zaretskii 2019-10-13 19:41 ` Ergus 2019-10-13 16:11 ` Eli Zaretskii 2019-08-27 16:01 Keith David Bershatsky -- strict thread matches above, loose matches on Subject: below -- 2019-08-07 0:54 Ergus 2019-08-07 15:01 ` Eli Zaretskii 2019-08-07 15:32 ` Ergus 2019-08-07 15:45 ` Eli Zaretskii 2019-08-07 15:57 ` Ergus 2019-08-07 16:12 ` Eli Zaretskii 2019-08-07 16:25 ` martin rudalics 2019-08-07 16:41 ` Eli Zaretskii 2019-08-08 7:25 ` martin rudalics 2019-08-08 8:38 ` Ergus 2019-08-08 8:45 ` martin rudalics 2019-08-08 9:29 ` Ergus 2019-08-08 13:05 ` martin rudalics 2019-08-08 13:59 ` Eli Zaretskii 2019-08-08 16:43 ` Ergus 2019-08-08 17:50 ` Eli Zaretskii 2019-08-08 22:37 ` Ergus 2019-08-09 6:28 ` Eli Zaretskii 2019-08-09 9:08 ` Ergus 2019-08-09 9:40 ` Eli Zaretskii 2019-08-09 11:31 ` Ergus 2019-08-09 14:04 ` Eli Zaretskii 2019-08-09 15:09 ` Ergus 2019-08-09 8:59 ` martin rudalics 2019-08-09 9:31 ` Ergus 2019-08-09 9:38 ` Ergus 2019-08-10 11:42 ` Eli Zaretskii 2019-08-11 8:14 ` martin rudalics 2019-08-09 8:59 ` martin rudalics 2019-08-08 14:50 ` Ergus 2019-08-09 8:59 ` martin rudalics 2019-08-10 11:30 ` Eli Zaretskii 2019-08-11 8:14 ` martin rudalics 2019-08-11 14:13 ` Eli Zaretskii 2019-08-12 8:59 ` martin rudalics 2019-08-12 15:29 ` Eli Zaretskii 2019-08-12 22:18 ` Stefan Monnier 2019-08-13 8:17 ` martin rudalics 2019-08-13 15:32 ` Eli Zaretskii 2019-08-13 22:33 ` Stefan Monnier 2019-08-14 8:58 ` martin rudalics 2019-08-13 8:17 ` martin rudalics 2019-08-13 15:31 ` Eli Zaretskii 2019-08-14 8:58 ` martin rudalics 2019-08-14 15:14 ` Eli Zaretskii 2019-08-15 8:13 ` martin rudalics 2019-08-15 15:18 ` Eli Zaretskii 2019-08-16 7:29 ` martin rudalics 2019-08-16 8:34 ` Eli Zaretskii 2019-08-17 8:25 ` martin rudalics 2019-08-19 16:13 ` Ergus 2019-08-19 16:50 ` Eli Zaretskii 2019-08-19 21:30 ` Ergus 2019-08-20 14:09 ` Eli Zaretskii 2019-08-25 10:22 ` Ergus 2019-08-25 10:44 ` Eli Zaretskii 2019-08-26 4:31 ` Ergus 2019-08-26 7:45 ` Eli Zaretskii 2019-08-26 8:18 ` Ergus 2019-08-26 9:49 ` Eli Zaretskii 2019-08-27 22:20 ` Ergus 2019-08-28 8:35 ` martin rudalics 2019-08-28 9:07 ` Eli Zaretskii 2019-08-28 12:19 ` martin rudalics 2019-08-28 16:31 ` Ergus 2019-08-28 17:24 ` Eli Zaretskii 2019-08-28 18:19 ` Ergus 2019-08-29 18:28 ` Eli Zaretskii 2019-08-30 7:02 ` martin rudalics 2019-08-30 7:26 ` Eli Zaretskii 2019-08-30 9:34 ` Ergus 2019-08-29 7:45 ` martin rudalics 2019-08-28 17:21 ` Eli Zaretskii 2019-08-29 7:45 ` martin rudalics 2019-08-29 18:36 ` Eli Zaretskii 2019-08-30 7:03 ` martin rudalics 2019-08-30 8:48 ` Eli Zaretskii 2019-08-31 7:29 ` martin rudalics 2019-08-31 7:57 ` Eli Zaretskii 2019-09-01 8:14 ` martin rudalics 2019-09-01 12:26 ` Ergus 2019-09-02 8:36 ` martin rudalics 2019-09-02 11:05 ` Ergus 2019-09-02 16:18 ` Eli Zaretskii 2019-09-03 5:33 ` Ergus 2019-09-03 8:45 ` martin rudalics 2019-09-03 11:23 ` Ergus 2019-09-03 12:17 ` martin rudalics 2019-09-03 14:56 ` Eli Zaretskii 2019-09-03 5:35 ` Ergus via Emacs development discussions. 2019-09-03 8:45 ` martin rudalics 2019-09-03 14:53 ` Eli Zaretskii 2019-09-03 16:41 ` martin rudalics 2019-09-03 17:31 ` Eli Zaretskii 2019-09-03 18:59 ` martin rudalics 2019-09-04 18:33 ` Ergus 2019-09-04 20:04 ` martin rudalics 2019-09-04 20:19 ` Ergus via Emacs development discussions. 2019-09-05 7:32 ` martin rudalics 2019-09-05 13:54 ` Ergus 2019-09-05 19:31 ` Ergus [not found] ` <1826922767.1725310.1567682307734@mail.yahoo.com> 2019-09-05 11:18 ` Ergus 2019-08-21 7:37 ` martin rudalics 2019-08-08 17:37 ` Eli Zaretskii 2019-08-09 12:46 ` martin rudalics 2019-08-10 11:25 ` Eli Zaretskii 2019-08-10 23:04 ` Stefan Monnier 2019-08-11 2:43 ` Eli Zaretskii 2019-08-11 8:17 ` martin rudalics 2019-08-11 8:11 ` martin rudalics 2019-08-08 17:38 ` Eli Zaretskii 2019-08-08 8:15 ` Ergus 2019-08-08 8:45 ` martin rudalics 2019-08-08 9:17 ` Ergus 2019-08-08 17:35 ` Eli Zaretskii 2019-08-08 20:37 ` Juri Linkov 2019-08-08 22:24 ` Ergus 2019-08-09 6:42 ` Eli Zaretskii 2019-08-09 17:54 ` Juri Linkov
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.