unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Vladimir Kazanov <vekazanov@gmail.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: emacs-devel@gnu.org
Subject: Re: [PATCH] User-defined fringe tooltips (a request for review)
Date: Sun, 7 Apr 2024 12:14:54 +0100	[thread overview]
Message-ID: <CAAs=0-0pr01+DnHYb0k6DMVDYSUw4bb+BHhtNTSzo41kJUiOEQ@mail.gmail.com> (raw)
In-Reply-To: <86il12bxwj.fsf@gnu.org>

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

Hi Eli,

Here's a 3rd version of the patch. Please, ignore documentation, which
I'll update later, and take a look at the code itself.

> Like I said earlier: I think it would be better to have the tooltip
> text in a separate property, not as part of the 'display' property
> spec.
>
> Also, I don't see a need for recording the positions in the glyph_row
> structure, because finding the glyph that corresponds to buffer/string
> text with that special property is easy enough.

Done.

The code in the patch goes through glyphs of the row under a mouse
pointer, finds an object that generated the glyph (glyph->object,
which can be a buffer or a string) and checks if
left-fringe-help/right-fringe-help text properties are defined.
Strings from the properties are then displayed as tooltips.

This only works for properties of visible text that has glyphs
generated for it. Properties coming from invisible text and
zero-length overlays are not represented as glyphs as much I can see
from the code.  Here are some code examples:

;;; tooltips will be shown in the examples below:

  (insert (propertize "foo" 'left-fringe-help "left tooltip"))
  (insert (propertize "foo" 'right-fringe-help "right tooltip"))

  (overlay-put (make-overlay (point) (1+ (point)))
               'right-fringe-help "right tooltip")

  (overlay-put
   (make-overlay (point) (1+ (point)))
   'after-string
   (propertize
    "lll"
    'left-fringe-help "left tooltip"))

  (overlay-put
   (make-overlay (point) (1+ (point)))
   'after-string
   (propertize
    "rrr"
    'right-fringe-help "right tooltip"))

;;; Tooltips will NOT be shown
  (insert (propertize "foo" 'display '(left-fringe left-arrow warning)
                      'left-fringe-help "left tooltip"))
  (insert (propertize "foo" 'display '(right-fringe left-arrow warning)
                      'right-fringe-help "right tooltip"))
  (insert (propertize "foo" 'left-fringe-help "left tooltip"))

  (insert (propertize "foo" 'right-fringe-help "right tooltip"))

(overlay-put
   (make-overlay 1 2)
   'before-string (propertize
                   "x"
                   'left-fringe-help "left tooltip"
                   'display '(left-fringe right-arrow warning)))

So this is a partial solution. If you're fine with the general
approach, we can do this in step-by-step fashion. I'll fix the
documentation and provide a final version of this implementation, and
then think about what to do about invisible text.

Thanks!

-- 
Regards,

Vladimir Kazanov

[-- Attachment #2: v3-0001-Tooltips-for-user-defined-fringe-indicators.patch --]
[-- Type: text/x-patch, Size: 6408 bytes --]

From 06ccf155aabc663a92bb6552df74df52c2c6fec5 Mon Sep 17 00:00:00 2001
From: Vladimir Kazanov <vekazanov@gmail.com>
Date: Sun, 24 Dec 2023 11:13:10 +0000
Subject: [PATCH v3] Tooltips for user-defined fringe indicators

---
 doc/lispref/display.texi |  7 +++--
 etc/NEWS                 |  6 ++++
 etc/TODO                 |  4 ---
 src/frame.c              |  2 ++
 src/xdisp.c              | 61 ++++++++++++++++++++++++++++++++++++++--
 5 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index f82c2fad14d..b3b81bd342c 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -5492,14 +5492,15 @@ Other Display Specs
 but it is done as a special case of marginal display (@pxref{Display
 Margins}).

-@item (left-fringe @var{bitmap} @r{[}@var{face}@r{]})
-@itemx (right-fringe @var{bitmap} @r{[}@var{face}@r{]})
+@item (left-fringe @var{bitmap} @r{[}@var{face}@r{]} @r{[}@var{help-echo}@r{]})
+@itemx (right-fringe @var{bitmap} @r{[}@var{face}@r{]} @r{[}@var{help-echo}@r{]})
 This display specification on any character of a line of text causes
 the specified @var{bitmap} be displayed in the left or right fringes
 for that line, instead of the characters that have the display
 specification.  The optional @var{face} specifies the face whose
 colors are to be used for the bitmap display.  @xref{Fringe Bitmaps},
-for the details.
+for the details.  The optional @var{help-echo} string can be used to
+display tooltips or help text in the echo area.

 @item (space-width @var{factor})
 This display specification affects all the space characters within the
diff --git a/etc/NEWS b/etc/NEWS
index 32cec82f970..b1f72cb9bf4 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1815,6 +1815,12 @@ the handler code without unwinding the stack, such that we can record
 the backtrace and other dynamic state at the point of the error.  See
 the Info node "(elisp) Handling Errors".

++++
+** Tooltips for user fringe indicators.
+User fringe indicators defined in text display specifications now
+support user-defined tooltips.  See the "Other Display Specifications"
+node in the Emacs Lisp Reference Manual.
+
 +++
 ** New 'pop-up-frames' action alist entry for 'display-buffer'.
 This has the same effect as the variable of the same name and takes
diff --git a/etc/TODO b/etc/TODO
index 52c77ccc28d..21b504ad18b 100644
--- a/etc/TODO
+++ b/etc/TODO
@@ -172,10 +172,6 @@ Change them to use report-emacs-bug.
 **** lm-report-bug
 **** tramp-bug
 **** c-submit-bug-report
-
-** Allow fringe indicators to display a tooltip
-Provide a help-echo property?
-
 ** Add a defcustom that supplies a function to name numeric backup files
 Like 'make-backup-file-name-function' for non-numeric backup files.

diff --git a/src/frame.c b/src/frame.c
index abd6ef00901..ff99b0353af 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -6383,6 +6383,7 @@ syms_of_frame (void)
   DEFSYM (Qchild_frame_border_width, "child-frame-border-width");
   DEFSYM (Qinternal_border_width, "internal-border-width");
   DEFSYM (Qleft_fringe, "left-fringe");
+  DEFSYM (Qleft_fringe_help, "left-fringe-help");
   DEFSYM (Qline_spacing, "line-spacing");
   DEFSYM (Qmenu_bar_lines, "menu-bar-lines");
   DEFSYM (Qtab_bar_lines, "tab-bar-lines");
@@ -6390,6 +6391,7 @@ syms_of_frame (void)
   DEFSYM (Qname, "name");
   DEFSYM (Qright_divider_width, "right-divider-width");
   DEFSYM (Qright_fringe, "right-fringe");
+  DEFSYM (Qright_fringe_help, "right-fringe-help");
   DEFSYM (Qscreen_gamma, "screen-gamma");
   DEFSYM (Qscroll_bar_background, "scroll-bar-background");
   DEFSYM (Qscroll_bar_foreground, "scroll-bar-foreground");
diff --git a/src/xdisp.c b/src/xdisp.c
index 140d71129f3..b4d57b5b6f2 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -35730,6 +35730,59 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
 }


+/* Take proper action when mouse has moved to the window WINDOW, with
+   window-local x-position X and y-position Y. This is only used for
+   displaying user-defined fringe indicator help-echo messages.  */
+
+static void
+note_fringe_highlight (Lisp_Object window, int x, int y,
+		       enum window_part part)
+{
+  if (!NILP (help_echo_string))
+    return;
+
+  /* Find a message to display through the help-echo mechanism whenever
+     the mouse hovers over a fringe indicator.  Both text properties and
+     overlays have to be checked.  */
+
+  /* Check the text property symbol to use.  */
+  Lisp_Object sym;
+  if (part == ON_LEFT_FRINGE)
+    sym = Qleft_fringe_help;
+  else
+    sym = Qright_fringe_help;
+
+  /* Translate windows coordinates into a vertical window position.  */
+  int hpos, vpos, area;
+  struct window *w = XWINDOW (window);
+  x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, 0, 0, &area);
+
+  /* Get to the first glyph of a text row based on the vertical position
+     of the fringe.  */
+  struct glyph *glyph = MATRIX_ROW_GLYPH_START(w->current_matrix, vpos);
+  int glyph_num = MATRIX_ROW_USED(w->current_matrix, vpos);
+
+  /* Check all glyphs while looking for fringe tooltips.  */
+
+  /* NOTE: iterating over glyphs can only find text properties coming
+     from visible text.  This means that zero-length overlays and
+     invisibile text are NOT inspected.  */
+  for (;glyph_num; glyph_num--, glyph++)
+    {
+      Lisp_Object pos = make_fixnum(glyph->charpos);
+      Lisp_Object help_echo = Qnil;
+
+      if (STRINGP(glyph->object) || BUFFERP(glyph->object))
+	help_echo = get_char_property_and_overlay (pos, sym, glyph->object, NULL);
+
+      if (STRINGP (help_echo))
+	{
+	  help_echo_string = help_echo;
+	  break;
+	}
+    }
+}
+
 /* EXPORT:
    Take proper action when the mouse has moved to position X, Y on
    frame F with regards to highlighting portions of display that have
@@ -35957,8 +36010,12 @@ note_mouse_highlight (struct frame *f, int x, int y)
       }
     else
       cursor = FRAME_OUTPUT_DATA (f)->nontext_cursor;
-  else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE
-	   || part == ON_VERTICAL_SCROLL_BAR
+  else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE)
+    {
+      cursor = FRAME_OUTPUT_DATA (f)->nontext_cursor;
+      note_fringe_highlight (window, x, y, part);
+    }
+  else if (part == ON_VERTICAL_SCROLL_BAR
 	   || part == ON_HORIZONTAL_SCROLL_BAR)
     cursor = FRAME_OUTPUT_DATA (f)->nontext_cursor;
   else
--
2.34.1

  reply	other threads:[~2024-04-07 11:14 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-19 19:38 [PATCH] User-defined fringe tooltips (a request for review) Vladimir Kazanov
2023-12-20 12:31 ` Eli Zaretskii
2023-12-21 16:51   ` Vladimir Kazanov
2023-12-21 17:37     ` Eli Zaretskii
2023-12-23 13:28       ` Vladimir Kazanov
2023-12-23 13:40         ` Eli Zaretskii
2023-12-24 11:31           ` Vladimir Kazanov
2023-12-24 16:54             ` Eli Zaretskii
2024-03-25 15:55               ` Vladimir Kazanov
2024-03-25 17:11                 ` Eli Zaretskii
2024-03-26 22:16                   ` Vladimir Kazanov
2024-03-27 10:59                     ` Vladimir Kazanov
2024-03-27 11:25                       ` Po Lu
2024-03-27 12:48                         ` Vladimir Kazanov
2024-03-27 11:25                       ` Po Lu
2024-03-31  8:36                       ` Eli Zaretskii
2024-04-07 11:14                         ` Vladimir Kazanov [this message]
2024-04-07 12:44                           ` Eli Zaretskii
2024-04-07 17:07                             ` Vladimir Kazanov
2024-04-07 18:40                               ` Eli Zaretskii
2024-04-08 14:41                                 ` Vladimir Kazanov
2024-04-13  9:14                                   ` Eli Zaretskii
2024-04-13  9:32                                     ` Vladimir Kazanov
2024-04-13 11:21                                       ` Eli Zaretskii
2024-04-13 14:53                                         ` Vladimir Kazanov
2024-04-13 15:47                                           ` Eli Zaretskii
2024-03-27 12:14                     ` Eli Zaretskii
2024-03-27 12:48                       ` Vladimir Kazanov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAAs=0-0pr01+DnHYb0k6DMVDYSUw4bb+BHhtNTSzo41kJUiOEQ@mail.gmail.com' \
    --to=vekazanov@gmail.com \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).