From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: tofu-help-mode (was: Suggest installing more fonts?) Date: Wed, 21 Oct 2020 12:03:58 -0400 Message-ID: References: <87wnzqa1be.fsf@gnus.org> <83y2k6v378.fsf@gnu.org> <87eely5mof.fsf@gnus.org> <83o8l2utb5.fsf@gnu.org> <874kmt1icl.fsf@gnus.org> <83o8l1teo3.fsf@gnu.org> <87tuusklki.fsf@gnus.org> <83tuurr24j.fsf@gnu.org> <87y2k2fwgu.fsf@gnus.org> <83pn5ep8x0.fsf@gnu.org> <87zh4hi43l.fsf@gnus.org> <83eeltnf3b.fsf@gnu.org> <87sga7kg9s.fsf@gnus.org> <87mu0fx1ca.fsf@gmx.de> <83sga7mxym.fsf@gnu.org> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="13976"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed Oct 21 18:07:28 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kVGe8-0003UJ-69 for ged-emacs-devel@m.gmane-mx.org; Wed, 21 Oct 2020 18:07:28 +0200 Original-Received: from localhost ([::1]:36114 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kVGe7-00079n-7x for ged-emacs-devel@m.gmane-mx.org; Wed, 21 Oct 2020 12:07:27 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:51736) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kVGay-0003Zz-7c for emacs-devel@gnu.org; Wed, 21 Oct 2020 12:04:12 -0400 Original-Received: from mailscanner.iro.umontreal.ca ([132.204.25.50]:2164) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kVGav-0001I6-1Y for emacs-devel@gnu.org; Wed, 21 Oct 2020 12:04:11 -0400 Original-Received: from pmg3.iro.umontreal.ca (localhost [127.0.0.1]) by pmg3.iro.umontreal.ca (Proxmox) with ESMTP id BAC1D440697; Wed, 21 Oct 2020 12:04:07 -0400 (EDT) Original-Received: from mail01.iro.umontreal.ca (unknown [172.31.2.1]) by pmg3.iro.umontreal.ca (Proxmox) with ESMTP id C9E4A440520; Wed, 21 Oct 2020 12:04:05 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=iro.umontreal.ca; s=mail; t=1603296245; bh=hWxsmLFAlCTw1frFqwHtt8vUKrzGaqel/+Kg/mNnAS4=; h=From:To:Subject:References:Date:In-Reply-To:From; b=FCRIBkGbqTRYSqpvesyH2Fhfa1MOThlPu6eRXtceuExaMDyMMyX9xOG8o20s+i2Zd U1uxm5uklw171FA+SIgkLsNWNFIN5hSMzAXC26n9vT8D/znHSHWYvmSQIoMeupSnMs xaXLG1QHIIZPeooDIr5YnYCYcNIyVFMz1j0lGmWs7WxacITBYDRFvR5So13fSMGGG8 W61blqBfrJXPoaxLPXDRgyoj9ND7hnG91J83+PI0MR5l/aoEt4DbukDQvTr1USr2IH 9DTVbChDB6chNOQ+rJ1CIa2hES/PmA+WkUysRCSKfbhJtAo7jWpMQfOY/ZrmL8Hciu Fh1DCA5ns/lLA== Original-Received: from alfajor (unknown [157.52.9.240]) by mail01.iro.umontreal.ca (Postfix) with ESMTPSA id A465C1203B9; Wed, 21 Oct 2020 12:04:05 -0400 (EDT) In-Reply-To: <83sga7mxym.fsf@gnu.org> (Eli Zaretskii's message of "Wed, 21 Oct 2020 17:54:09 +0300") Received-SPF: pass client-ip=132.204.25.50; envelope-from=monnier@iro.umontreal.ca; helo=mailscanner.iro.umontreal.ca X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/21 12:04:07 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -42 X-Spam_score: -4.3 X-Spam_bar: ---- X-Spam_report: (-4.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:258235 Archived-At: BTW, for those interested, here's a proof-of-concept. I don't intend to work much more on this (except maybe for the `post-redisplay-functions` part which might be useful on its own), so I'd encourage someone else to take it over from here if they'd like to see it turn into something usable. Stefan diff --git a/lisp/simple.el b/lisp/simple.el index ef519aa2cb..647ffd7320 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -6342,6 +6342,48 @@ redisplay--pre-redisplay-functions (add-function :before pre-redisplay-function #'redisplay--pre-redisplay-functions) +(defvar post-redisplay-functions nil + "Hook run just after redisplay. +It is called in each window that has been redisplayed. It takes one argument, +which is the window that was redisplayed. When run, the `current-buffer' +is set to the buffer displayed in that window.") + +(defun redisplay--post-redisplay-functions (windows) + (with-demoted-errors "redisplay--post-redisplay-functions: %S" + (if (null windows) + (with-current-buffer (window-buffer (selected-window)) + (run-hook-with-args 'post-redisplay-functions (selected-window))) + (dolist (win (if (listp windows) windows (window-list-1 nil nil t))) + (with-current-buffer (window-buffer win) + (run-hook-with-args 'post-redisplay-functions win)))))) + +(add-function :before post-redisplay-function + #'redisplay--post-redisplay-functions) + +(defun tofu-help--post-redisplay (_window) + (declare-function describe-char-display "descr-text" (pos char)) + (while (consp redisplay-tofu) + (let* ((pos (pop redisplay-tofu)) + (char (if (< pos (point-max)) (char-after pos)))) + ;; Don't hide pre-existing help-echo. + (unless (or (null char) + (get-text-property pos 'help-echo) + (describe-char-display pos char)) + (with-silent-modifications + (put-text-property pos (1+ pos) 'help-echo + (or (get-char-code-property char 'name) + (get-char-code-property char 'old-name) + "This is unknown TOFU!"))))))) + +(define-minor-mode tofu-help-mode + "Add help-echo on TOFU chars." + :lighter nil + (kill-local-variable 'redisplay-tofu) + (remove-hook 'post-redisplay-functions #'tofu-help--post-redisplay t) + (when tofu-help-mode + (require 'descr-text) ;For describe-char-display + (setq-local redisplay-tofu nil) + (add-hook 'post-redisplay-functions #'tofu-help--post-redisplay nil t))) (defvar-local mark-ring nil "The list of former marks of the current buffer, most recent first.") diff --git a/src/xdisp.c b/src/xdisp.c index 4086eef9d0..e5559774b8 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -7333,6 +7333,18 @@ #define CHAR_COMPOSED_P(IT,CHARPOS,BYTEPOS,END_CHARPOS) \ (IT)->face_id), \ (IT)->string))) +static void +record_tofu (struct it *it) +{ + if (!EQ (Vredisplay_tofu, Qt)) + { + Lisp_Object pos = make_fixnum (IT_CHARPOS (*it)); + /* FIXME: If the user sets `redisplay-tofu' to a value that's + neither t nor a proper list, this signals an error! */ + if (NILP (Fmemq (pos, Vredisplay_tofu))) + Vredisplay_tofu = Fcons (pos, Vredisplay_tofu); + } +} /* Lookup the char-table Vglyphless_char_display for character C (-1 if we want information for no-font case), and return the display @@ -7382,7 +7394,10 @@ lookup_glyphless_char_display (int c, struct it *it) else if (EQ (glyphless_method, Qempty_box)) it->glyphless_method = GLYPHLESS_DISPLAY_EMPTY_BOX; else if (EQ (glyphless_method, Qhex_code)) - it->glyphless_method = GLYPHLESS_DISPLAY_HEX_CODE; + { + record_tofu (it); + it->glyphless_method = GLYPHLESS_DISPLAY_HEX_CODE; + } else if (STRINGP (glyphless_method)) it->glyphless_method = GLYPHLESS_DISPLAY_ACRONYM; else @@ -15514,6 +15529,7 @@ #define RESUME_POLLING \ static int redisplay_window_wcounter; static int redisplay_window_bcounter; static int redisplay_window_fcounter; +static Lisp_Object redisplayed_windows; /* Perhaps in the future avoid recentering windows if it is not necessary; currently that causes some problems. */ @@ -16016,9 +16032,13 @@ #define AINC(a,i) \ redisplay_window_bcounter = 0; redisplay_window_fcounter = 0; redisplay_window_wcounter = 0; + redisplayed_windows = Qt; if (consider_all_windows_p) { + if (REDISPLAY_SOME_P ()) + redisplayed_windows = Qnil; + FOR_EACH_FRAME (tail, frame) XFRAME (frame)->updated_p = false; @@ -16328,6 +16348,10 @@ #define AINC(a,i) \ request_sigio (); RESUME_POLLING; + if (FUNCTIONP (Vpost_redisplay_function)) + safe__call1 (true, Vpost_redisplay_function, + consider_all_windows_p ? redisplayed_windows : Qnil); + /* If a frame has become visible which was not before, redisplay again, so that we display it. Expose events for such a frame (which it gets when becoming visible) don't call the parts of @@ -18422,6 +18446,9 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) && BUF_PT (buffer) == w->last_point) return; + if (!EQ (redisplayed_windows, Qt)) + redisplayed_windows = Fcons (window, redisplayed_windows); + if (w->redisplay) redisplay_window_wcounter++; if (f->redisplay) @@ -29696,7 +29723,7 @@ compute_relative_width (struct it *it, Lisp_Object prop) it2 = *it; if (it->multibyte_p) - it2.c = it2.char_to_display = string_char_and_length (p, it2.len); + it2.c = it2.char_to_display = string_char_and_length (p, &it2.len); else { it2.c = it2.char_to_display = *p, it2.len = 1; @@ -34683,6 +34710,9 @@ syms_of_xdisp (void) Vmessage_stack = Qnil; staticpro (&Vmessage_stack); + redisplayed_windows = Qt; + staticpro (&redisplayed_windows); + /* Non-nil means don't actually do any redisplay. */ DEFSYM (Qinhibit_redisplay, "inhibit-redisplay"); @@ -35544,6 +35574,13 @@ syms_of_xdisp (void) or t (meaning all windows). */); Vpre_redisplay_function = intern ("ignore"); + DEFVAR_LISP ("post-redisplay-function", Vpost_redisplay_function, + doc: /* Function run just after redisplay. +It is called with one argument, which is the set of windows that have been +redisplayed. This set can be nil (meaning, only the selected window), +or t (meaning all windows). */); + Vpost_redisplay_function = intern ("ignore"); + /* Symbol for the purpose of Vglyphless_char_display. */ DEFSYM (Qglyphless_char_display, "glyphless-char-display"); Fput (Qglyphless_char_display, Qchar_table_extra_slots, make_fixnum (1)); @@ -35614,6 +35651,10 @@ syms_of_xdisp (void) doc: /* */); Vredisplay__touched_fcounts = Fmake_hash_table (0, NULL); + DEFVAR_LISP ("redisplay-tofu", Vredisplay_tofu, + doc: /* */); + Vredisplay_tofu = Qt; + DEFVAR_BOOL ("redisplay--inhibit-bidi", redisplay__inhibit_bidi, doc: /* Non-nil means it is not safe to attempt bidi reordering for display. */); /* Initialize to t, since we need to disable reordering until