From 15e5f404f05f7a1ca5bdd8eb6a7579e0546472da Mon Sep 17 00:00:00 2001 From: Manuel Giraud Date: Thu, 28 May 2026 10:01:58 +0200 Subject: [PATCH] Optional display of overlay-arrow in margin (bug#81109) * lisp/emacs-lisp/edebug.el (edebug-prepare-margin): New function to set up left margin for Edebug. (edebug--display-1): Use it. * src/xdisp.c (display_line): Try to use left margin to display overlay arrow and fallback to the text area otherwise. * doc/lispref/display.texi (Overlay Arrow): * doc/lispref/edebug.texi (Using Edebug): * doc/emacs/building.texi (Debugger Operation): Document the change. * etc/NEWS: Announce the change. --- doc/emacs/building.texi | 14 +++++++------- doc/lispref/display.texi | 11 ++++++----- doc/lispref/edebug.texi | 6 ++++-- etc/NEWS | 7 +++++++ lisp/emacs-lisp/edebug.el | 15 ++++++++++++++- src/xdisp.c | 23 +++++++++++++++++++---- 6 files changed, 57 insertions(+), 19 deletions(-) diff --git a/doc/emacs/building.texi b/doc/emacs/building.texi index 2af98997480..78c13903edf 100644 --- a/doc/emacs/building.texi +++ b/doc/emacs/building.texi @@ -746,13 +746,13 @@ for special commands that can be used in the GUD interaction buffer. As you debug a program, Emacs displays the relevant source files by visiting them in Emacs buffers, with an arrow in the left fringe indicating the current execution line. (On a text terminal, the arrow -appears as @samp{=>}, overlaid on the first two text columns.) Moving -point in such a buffer does not move the arrow. You are free to edit -these source files, but note that inserting or deleting lines will -throw off the arrow's positioning, as Emacs has no way to figure out -which edited source line corresponds to the line reported by the -debugger subprocess. To update this information, you typically have -to recompile and restart the program. +appears as @samp{=>}, in the left margin.) Moving point in such a +buffer does not move the arrow. You are free to edit these source +files, but note that inserting or deleting lines will throw off the +arrow's positioning, as Emacs has no way to figure out which edited +source line corresponds to the line reported by the debugger subprocess. +To update this information, you typically have to recompile and restart +the program. @cindex GUD and hl-line-mode @cindex highlighting execution lines in GUD diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 49b09f6583d..ae7d314c795 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -5065,11 +5065,12 @@ to the left of the display area. @defvar overlay-arrow-position This variable holds a marker that indicates where to display the overlay arrow. It should point at the beginning of a line. On a non-graphical -display, or when the left fringe is not shown, the arrow text -appears at the beginning of that line, overlaying any text that would -otherwise appear. Since the arrow is usually short, and the line -usually begins with indentation, normally nothing significant is -overwritten. +display, or when the left fringe is not shown, the arrow text appears at +the beginning of that line, overlaying any text that would otherwise +appear. Since the arrow is usually short, and the line usually begins +with indentation, normally nothing significant is overwritten. If the +window has a left margin with enough space, Emacs displays the arrow +there instead and the text area is not overwritten. The overlay-arrow string is displayed in any given buffer if the value of @code{overlay-arrow-position} in that buffer points into that diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi index 8aec8abf7c0..e729cb7aef3 100644 --- a/doc/lispref/edebug.texi +++ b/doc/lispref/edebug.texi @@ -105,8 +105,10 @@ the Lisp code you are debugging. This is referred to as the @dfn{source code buffer}, and it is temporarily read-only. An arrow in the left fringe indicates the line where the function is -executing. Point initially shows where within the line the function is -executing, but this ceases to be true if you move point yourself. +executing. On a non-graphical display (or when the left fringe is not +shown), this arrow is displayed in the left margin instead. Point +initially shows where within the line the function is executing, but +this ceases to be true if you move point yourself. If you instrument the definition of @code{fac} (shown below) and then execute @code{(fac 3)}, here is what you would normally see. Point is diff --git a/etc/NEWS b/etc/NEWS index 70bb5a8ac0b..1efc9a86b86 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -72,6 +72,13 @@ accept or ignore the value. unconditionally. The previous behavior, toggling the mode, was neither reliable nor generally desirable. ++++ +** Emacs tries to display overlay arrow in the left margin. +On a non-graphical display (or when the left fringe is not shown), if a +left margin is present, Emacs will now display the overlay arrow into +this margin. Edebug is now using this feature by explicitly setting up +a left margin for it. + * Editing Changes in Emacs 32.1 diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index 3bb12e18842..d938e39b30b 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el @@ -2721,6 +2721,9 @@ when edebug becomes active." edebug-function) )) + ;; Margin setup for overlay arrow. + (edebug-prepare-margin) + ;; Make sure we bind those in the right buffer (bug#16410). (let ((overlay-arrow-position overlay-arrow-position) (overlay-arrow-string overlay-arrow-string)) @@ -3001,6 +3004,17 @@ when edebug becomes active." ) "Association list of arrows for each edebug mode.") +(defun edebug-prepare-margin () + "Increase (or set) left margin with the size of the longest arrow string." + (let ((arrow-len (apply #'max (mapcar (lambda (x) + (string-width (cdr x))) + edebug-arrow-alist))) + (margins (window-margins))) + ;; Set or increase left margin. + (if (numberp (car margins)) + (set-window-margins nil (+ (car margins) arrow-len)) + (set-window-margins nil arrow-len)))) + (defun edebug-overlay-arrow () ;; Set up the overlay arrow at beginning-of-line in current buffer. ;; The arrow string is derived from edebug-arrow-alist and @@ -3011,7 +3025,6 @@ when edebug becomes active." (setq overlay-arrow-position (make-marker)) (set-marker overlay-arrow-position pos (current-buffer)))) - (defun edebug-toggle-save-all-windows () "Toggle the saving and restoring of all windows. Also, each time you toggle it on, the inside and outside window diff --git a/src/xdisp.c b/src/xdisp.c index 67fe2295dc2..e2321762699 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -26753,8 +26753,23 @@ display_line (struct it *it, int cursor_vpos) = get_overlay_arrow_glyph_row (it->w, overlay_arrow_string); struct glyph *glyph = arrow_row->glyphs[TEXT_AREA]; struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA]; - struct glyph *p = row->glyphs[TEXT_AREA]; - struct glyph *p2, *end; + struct glyph *p, *p2, *end, *where; + short *p_used; + + /* When possible, put the arrow glyphs at the start of the + left margin. Otherwise put them at the start of the text + area. */ + if (WINDOW_LEFT_MARGIN_WIDTH (it->w) >= arrow_row->used[TEXT_AREA]) + { + p = where = row->glyphs[LEFT_MARGIN_AREA]; + p_used = &(row->used[LEFT_MARGIN_AREA]); + row->used[LEFT_MARGIN_AREA] += arrow_row->used[TEXT_AREA]; + } + else + { + p = where = row->glyphs[TEXT_AREA]; + p_used = &(row->used[TEXT_AREA]); + } /* Copy the arrow glyphs. */ while (glyph < arrow_end) @@ -26762,14 +26777,14 @@ display_line (struct it *it, int cursor_vpos) /* Throw away padding glyphs. */ p2 = p; - end = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA]; + end = where + *p_used; while (p2 < end && CHAR_GLYPH_PADDING_P (*p2)) ++p2; if (p2 > p) { while (p2 < end) *p++ = *p2++; - row->used[TEXT_AREA] = p2 - row->glyphs[TEXT_AREA]; + *p_used = p2 - where; } } else