From bb6004521faefdd8936dafe7a64f24b3525fdaff Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Fri, 2 Jun 2023 20:09:43 +0300 Subject: [PATCH v2] Avoid header line with some empty non-nil formats Allow the value of 'header-line-format' to indicate that no header line should be displayed when it trivially yields 'nil', even if it is not plain 'nil'. Previously, any non-nil 'header-line-format' resulted in a (possibly empty) header line. This change adds some flexibility by also taking a non-nil value of 'header-line-format' to mean that no header line should be displayed if it's a list whose 'car' is a symbol and either that symbol is ':eval' and the second list element evaluates to 'nil', or the symbol's value as a variable is 'nil' or void. (Bug#63825) * src/xdisp.c (safe_eval_inhibit_quit): New function. (display_mode_element): Use it. * src/lisp.h (safe_eval_inhibit_quit): Declare it. * src/window.c (null_header_line_format): New function. (window_wants_header_line): Use it. * doc/lispref/modes.texi (Header Line): Update to reflect new conditions for displaying a window's header line. (Emulating Mode Line): Don't falsely suggest that if 'format-mode-line' yields the empty string then there is no header line, as there may be an empty header line instead. * etc/NEWS: Announce updated treatment of 'header-line-format'. --- doc/lispref/modes.texi | 18 ++++++++++++----- etc/NEWS | 8 ++++++++ src/lisp.h | 1 + src/window.c | 44 ++++++++++++++++++++++++++++++++++++++++-- src/xdisp.c | 8 +++++++- 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index c2698da6d99..c94ad229250 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi @@ -2597,6 +2597,15 @@ Header Lines line. @end defvar +Emacs displays the header line for a window unless +@code{header-line-format} is either @code{nil}, or it's a list whose +@sc{car} is a symbol, and either that symbol is @code{:eval} and the +second list element evaluates to @code{nil} or the symbol's value as a +variable is @code{nil} or void. Note that there are other possible +values @code{header-line-format} that result in an empty header line +(for example, @code{""}), but all other values tell Emacs to display a +header line, whether or not it is empty. + If @code{display-line-numbers-mode} is turned on in a buffer (@pxref{Display Custom, display-line-numbers-mode,, emacs, The GNU Emacs Manual}), the buffer text is indented on display by the amount @@ -2707,11 +2716,10 @@ Emulating Mode Line (Other faces do not cause redisplay.) For example, @code{(format-mode-line header-line-format)} returns the -text that would appear in the selected window's header line (@code{""} -if it has no header line). @code{(format-mode-line header-line-format -'header-line)} returns the same text, with each character -carrying the face that it will have in the header line itself, and also -redraws the header line. +text that would appear in the selected window's header line. +@code{(format-mode-line header-line-format 'header-line)} returns the +same text, with each character carrying the face that it will have in +the header line itself, and also redraws the header line. @end defun @node Imenu diff --git a/etc/NEWS b/etc/NEWS index 9529282f047..f09e8972bc6 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -451,6 +451,14 @@ hooks named after the feature name, like 'esh-mode-unload-hook'. +++ ** 'copy-tree' now copies records when its optional 2nd argument is non-nil. ++++ +** Certain values of 'header-line-format' now inhibit empty header line. +Emacs now avoids displaying a header line, instead of displaying an +empty one, when 'header-line-format' is a list whose 'car' is a +symbol, and either that symbol is ':eval' and the second element of +the list evaluates to 'nil' or the symbol's value as a variable is +'nil' or void. + * Lisp Changes in Emacs 30.1 diff --git a/src/lisp.h b/src/lisp.h index 2bfcd1a1983..2978de962d9 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4174,6 +4174,7 @@ verify (FLT_RADIX == 2 || FLT_RADIX == 16); extern void syms_of_xdisp (void); extern void init_xdisp (void); extern Lisp_Object safe_eval (Lisp_Object); +extern Lisp_Object safe_eval_inhibit_quit (Lisp_Object); extern bool pos_visible_p (struct window *, ptrdiff_t, int *, int *, int *, int *, int *, int *); diff --git a/src/window.c b/src/window.c index f4e09f49eae..fd9d7cbd9d3 100644 --- a/src/window.c +++ b/src/window.c @@ -5471,6 +5471,45 @@ window_wants_mode_line (struct window *w) } +/** + * null_header_line_format: + * + * Return non-zero when header line format FMT indicates that the + * header line should not be displayed at all. + * + * This is when FMT is nil, or if FMT is a cons cell and either its + * car is a symbol whose value as a variable is nil or void, or its + * car is the symbol ':eval' and its cadr evaluates to nil. + */ +static bool +null_header_line_format (Lisp_Object fmt) +{ + Lisp_Object car; + Lisp_Object val; + + if (NILP (fmt)) + return true; + + if (CONSP (fmt)) + { + car = XCAR (fmt); + if (SYMBOLP (car)) + { + if (EQ (car, QCeval) + && NILP (safe_eval_inhibit_quit (XCAR (XCDR (fmt))))) + return true; + + val = find_symbol_value (car); + return (SYMBOLP (car) + && (EQ (val, Qunbound) + || NILP (val))); + } + } + + return false; +} + + /** * window_wants_header_line: * @@ -5495,8 +5534,9 @@ window_wants_header_line (struct window *w) && !MINI_WINDOW_P (w) && !WINDOW_PSEUDO_P (w) && !EQ (window_header_line_format, Qnone) - && (!NILP (window_header_line_format) - || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), header_line_format))) + && (!null_header_line_format (window_header_line_format) + || !null_header_line_format (BVAR (XBUFFER (WINDOW_BUFFER (w)), + header_line_format))) && (WINDOW_PIXEL_HEIGHT (w) > (window_wants_mode_line (w) ? 2 * WINDOW_FRAME_LINE_HEIGHT (w) diff --git a/src/xdisp.c b/src/xdisp.c index a6ec966ea3c..fc7de149d2b 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3074,6 +3074,12 @@ safe__eval (bool inhibit_quit, Lisp_Object sexpr) return safe__call1 (inhibit_quit, Qeval, sexpr); } +Lisp_Object +safe_eval_inhibit_quit (Lisp_Object sexpr) +{ + return safe__eval (true, sexpr); +} + /* Call function FN with two arguments ARG1 and ARG2. Return the result, or nil if something went wrong. */ @@ -27408,7 +27414,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, if (CONSP (XCDR (elt))) { Lisp_Object spec; - spec = safe__eval (true, XCAR (XCDR (elt))); + spec = safe_eval_inhibit_quit (XCAR (XCDR (elt))); /* The :eval form could delete the frame stored in the iterator, which will cause a crash if we try to access faces and other fields (e.g., FRAME_KBOARD) -- 2.40.1