From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: martin rudalics Newsgroups: gmane.emacs.bugs Subject: bug#43609: 28.0.50; eldoc-documentation-function Date: Wed, 30 Sep 2020 19:33:16 +0200 Message-ID: <3fa6b315-7fc0-06ee-81e9-b68d164aec1b@gmx.at> References: <2e610c3f-6e5f-c7dd-af2e-aeb5e20d8664@gmx.at> <87r1qjjppu.fsf@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------0F520401EB024689D5EF3989" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="20491"; mail-complaints-to="usenet@ciao.gmane.io" Cc: 43609@debbugs.gnu.org To: =?UTF-8?Q?Jo=C3=A3o_?= =?UTF-8?Q?T=C3=A1vora?= Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Wed Sep 30 19:35:20 2020 Return-path: Envelope-to: geb-bug-gnu-emacs@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 1kNg0d-0005BI-OT for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 30 Sep 2020 19:35:20 +0200 Original-Received: from localhost ([::1]:47688 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kNg0c-0006Us-J6 for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 30 Sep 2020 13:35:18 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:51960) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kNfzO-0006Pg-RB for bug-gnu-emacs@gnu.org; Wed, 30 Sep 2020 13:34:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:49703) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1kNfzO-0003HP-G2 for bug-gnu-emacs@gnu.org; Wed, 30 Sep 2020 13:34:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1kNfzN-0004eB-VW for bug-gnu-emacs@gnu.org; Wed, 30 Sep 2020 13:34:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: martin rudalics Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 30 Sep 2020 17:34:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 43609 X-GNU-PR-Package: emacs Original-Received: via spool by 43609-submit@debbugs.gnu.org id=B43609.160148720817810 (code B ref 43609); Wed, 30 Sep 2020 17:34:01 +0000 Original-Received: (at 43609) by debbugs.gnu.org; 30 Sep 2020 17:33:28 +0000 Original-Received: from localhost ([127.0.0.1]:33013 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kNfyp-0004dB-4r for submit@debbugs.gnu.org; Wed, 30 Sep 2020 13:33:28 -0400 Original-Received: from mout.gmx.net ([212.227.15.19]:36105) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kNfym-0004cx-2Y for 43609@debbugs.gnu.org; Wed, 30 Sep 2020 13:33:25 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1601487198; bh=Q0Md5zknBo7hBSF00bAljxw/niR2YPNoqWWa7l2J5hw=; h=X-UI-Sender-Class:Subject:To:Cc:References:From:Date:In-Reply-To; b=QL37x7/oZLx3q4h8716sAJhIBbajcPhd6XV8benAOqvH6uobpY4OxaMcpPzw0t7v0 KyQMsfNiISbNsT05CJ9lt4fG/3oZ8KC8gyyOJ0VOAQnHYNzTi+zMX9soDzwVp3QYcA f/i/iPmfZrX/RzFX3LP5ahhvHrTusnRA7VxBcHjs= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Original-Received: from [192.168.1.101] ([46.125.249.105]) by mail.gmx.com (mrgmx004 [212.227.17.190]) with ESMTPSA (Nemesis) id 1Mplc7-1kkyZc2ePV-00qC8F; Wed, 30 Sep 2020 19:33:17 +0200 In-Reply-To: <87r1qjjppu.fsf@gmail.com> Content-Language: en-US X-Provags-ID: V03:K1:ddtSa/JRTo9hay6SYj9z9/BGUF52fY04LRKcSajdCrHuCjCpAH4 zT4y44oI0PMV0Kd4rhST+yVh+yEdBX+uxvnJWvK+9g1PLZc0w+brDN5QylsRSffA9U57gqj 2bbsoWOVgEUr/dAYvfTDnmY+3npmSbpet6/DotFIEjH6RImEogzWsuOt90gFBahzKsbOgsq EewdtYFArbyRJKn9XhjkA== X-UI-Out-Filterresults: notjunk:1;V03:K0:gpljkcXsZAg=:Q0bx5uJxDVAyTiHyea5dXY fKapvlyzbZDv5f85yZUSVuyUCAe66l2JjM4sg+COUFHzsVGmDyauHKNLsDfscPYKGTWIYrGTY +ATGzeHj2e6HUPJliWb1zNUkKbeAARQ2DCSf2dfZb1+rE+HloJgh1tsqJP8h2OnsC4rhQp/h0 +FpTc2VYH8b8DIFarzBjLG8GbC+eKA9K9T/W1iFeQeaRfjmQGIkbyGTRwwa3iQf8dgVjZ+tag 5slbxSeex2FR9D9D64u70R4OXqHs8oksve+dFQv1JLnfs5xAYot1T5lWEYzs21GhHmyR52kGB 6+tCG67p/KS9Q+5jtSj6f2XHZW8uBoi4zzuWAT8dZtl7/ssFZdes9nI5bMXWocr6J/L6aPTb0 yMR6XB/fR1u1sMIr3K9eB5vi9A+OsxYOfp6LT6KZDbuNei76GRz2aqt+ccj3GIg3wiag+AQR/ fmOujJOmSG6mLOJL/JN2sQulUzbWuuKa+WsNSbFXLTQ7EJKoTPC0avr+Gg8rIPE0Zf6vDJAjA HnWIvxD9Gm7U3tF2MuvBIx0TXjeJ/IwKBmWHTlbnQlltVC6gsuu7jtAFUSP5rtk4HKf1OlMgm YO0xuTjWUzD27emV247RzkxX56aQ0T4Jqn4bc7ixRg6cTaSH/21blebaxXwl/9OjOVdjcbvqc j1NNoUa+WzAgluQmzq8578fAXJ/JT/It5JW1Jee3LnnxSk6dfxo5RfScKWDwmY0LRJoWA6/yQ kojknLGSrsG2QgcrvDumH17Rsd5RS+dBvr7JC60/OAV5y4rUwDo1WXV0aLtEtADjguSFzuSm X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:189410 Archived-At: This is a multi-part message in MIME format. --------------0F520401EB024689D5EF3989 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: quoted-printable >> M-: (funcall eldoc-documentation-function) > > You're not supposed to call the that function in your programs and > neither were you in Emacs 27, much in the same way you normally don't > call, say, adaptive-fill-function, add-log-file-name-function or many > others. That you _could_ do it in your special circumstances was > incidental, though apparently useful for your third-party extension, > which I wasn't aware of. > > Furthermore, calling eldoc-documentation-function directly in Emacs 27= > simply doesn't work with a lot of major-modes/extensions that use > `eldoc-mode': ElPy, SLIME, SLY, Eldoc, and probably many others. If yo= u > call the function directly in those modes, it will quite likely return= > something other than the desired string, which will potentially appear= > in the echo area only some time after. Citing again the Emacs 27 doc-string for 'eldoc-documentation-function' Function to call to return doc string. The function of no args should return a one-line string for displaying= doc about a function etc. appropriate to the context around point. It should return nil if there=E2=80=99s no doc appropriate for the con= text. Typically doc is returned if point is on a function-like name or in it= s arg list. The result is used as is, so the function must explicitly handle the variables =E2=80=98eldoc-argument-case=E2=80=99 and =E2=80=98eldoc= -echo-area-use-multiline-p=E2=80=99, and the face =E2=80=98eldoc-highlight-function-argument=E2=80=99, if t= hey are to have any effect. so if it did not work for the modes you cite, the doc-string should have warned about that fact earlier. While this is certainly not your fault, changing the semantics of that variable for elisp-mode with the argument that it did not work for other modes was not a user-friendly step. Personally I use eldoc for two major modes only: 'emacs-lisp-mode' and 'c-mode' (in a crippled way via 'c-eldoc' but here nobody ever bothered to write an 'eldoc-documentation-function' function for one of the two major languages used to implement Emacs). And as far as the former is concerned, I now cannot use even 'elisp-eldoc-documentation-function' directly either because you changed its return value too. > That is becasue these modes (which all work in Emacs 26, 27 and master= ) > set eldoc-documentation-function to fetch their docstrings from > asynchronous sources. Therefore, calling the function won't return th= e > immediate value you expect, since ElDoc in Emacs 27 doesn't have any > concept of "async". It is true that in Elisp mode (and maybe some oth= er > modes) you get away with it becasue it doesn't have asynchronous sourc= es > (by default, at least, and mostly becasue it doesn't need to). This i= s > why your technique worked, under very special conditions. > > This is to clarify that the "direct call" protocol of Emacs 27's > eldoc.el was _never_ "a thing". At any rate it was never something yo= u > could rely on generally. At the time "el" in eldoc stood for elisp it was. But many things changed since then, admittedly. > Anyway, eldoc-documentation-function is consulted by the Eldoc framewo= rk > to provide documentation of the thing at point. The default value of > that variable has changed and it follows the "new" protocol. The > documentation is telling you how to craft values that you assign to th= e > varible, not how your application should interpret them. > > If you need a direct call, "give me the string" entry point to the > eldoc.el library, one can be added. I think we should do that and provide it as compatibility layer for people like me who need it. > However, its semantics depends on > your use case: > > - Do you want to have a return value handy for the docstrings that are= > immediately available from the sources that respond synchronously? Definitely. > - Do you want to wait actively until all sources have reported back an= d > then get a return value? In this case, do you need a timeout? If we can provide an option for that, yes. > - Independent of your choice above, or do you want to get the return > value as list of strings? Or as a single string, maybe concatenate= d > and propertized, exactly the way it is display I'd prefer a list of strings. > But maybe we are putting the cart ahead of ourselves? Would you mind > explaining exactly what you are trying to do? I suppose it's: > >> I am using a package that displays the string produced by that >> function in a tooltip near point. > > Is this supposed to work only for Elisp mode or in general for every > mode that uses Eldoc, such as the ones I listed above? I explained that above. I attach a copy of eldoc-tooltip.el here (I have two other packages to display tooltips either in a separate window or in the header line but I have not used them for years). As mentioned above, I use eldoc for elisp and c only. For the former I currently use (cond ((fboundp 'eldoc-tooltip-mode) (when (fboundp 'global-eldoc-mode) (global-eldoc-mode -1)) (eldoc-tooltip-mode 1)) because eldoc-tooltip-mode was written some time before 'global-eldoc-mode' was added. > If the former, you can probably do this (or some variation): > > (defun martin () > "CAUTION: Only works in default Emacs Lisp mode or modes with all-s= ync > docstring generating functions. If some functions calls the > callback afterwards, that result is discarded." > (let (res) > (run-hook-with-args 'eldoc-documentation-functions > (cl-function > (lambda (doc &key thing face &allow-other-ke= ys) > (push (format "%s: %s" > (propertize > (format "%s" thing) > 'face face) > doc) > res)))) > (mapconcat #'identity res "\n"))) > Works without problems for elisp-mode. Many thanks. Now for c-mode I use (set (make-local-variable 'eldoc-documentation-function) 'c-eldoc-print-current-symbol-info) What can I do here? The same? > If the latter, I suggest you look at the code I have in the > scratch/eldoc-display-functions branch, which seems to match your > intentions/use case very closely. The docstring of the new > eldoc-display-functions variable could be of use (let me know if it's > insuficcient). This means your advanced tooltip-displaying technology= > could now work with every Eldoc mode that uses the "new" protocol > (including, of course, Elisp mode). OK. I will look into that later. > As a side note, I would take the opinions of your other interlocutor > here so far with a grain of salt or two. They're not always grounded = in > reality. My other interlocutor here was Dmitry Gutov. Please refer to him with his name. And I highly appreciate the fact that he was the only person to answer my bug report within a day or two. > Finally, I understand the documentation for the new ElDoc framework is= > not very good yet: I will update it soon. Again, I apologize for the > delay in answering this bug report, but I am extremely busy as of late= =2E > Next time, if you can remember, please X-Debbugs-CC: me in your fresh > bug report on this matter, so that the message reaches me immediately.= I'll do that. Many thanks, martin --------------0F520401EB024689D5EF3989 Content-Type: text/x-emacs-lisp; name="eldoc-tooltip.el" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="eldoc-tooltip.el" ;;; eldoc-tooltip.el --- show ElDoc as tooltips -*- lexical-binding:t -*- ;; Copyright (C) 2015 Free Software Foundation, Inc. ;; Time-stamp: "2016-01-11 08:55:41 martin" ;; Author: Martin Rudalics ;; Keywords: ElDoc, tooltips ;; Version: 1.0 ;; eldoc-tooltip.el is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 3, or (at ;; your option) any later version. ;; eldoc-tooltip.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; ElDoc tooltip mode is a minor mode to show the function arglist or ;; variable docstring provided by `eldoc-documentation-function' in a ;; tooltip window. ;; To turn on this mode automatically (and simultaneously turn off ;; showing tooltips in the echo area) put ;; ;; (eldoc-tooltip-mode 1) ;; (global-eldoc-mode -1) ;; ;; into your .emacs. ;; Eldoc tooltip mode requires Emacs 25 or higher for its handling of ;; toolbar window positioning. It requires `eldoc' only to (1) get ;; access to `eldoc-documentation-function' and (2) override the option ;; `eldoc-echo-area-use-multiline-p' in invocations of the former. ;;; Code: (defgroup eldoc-tooltip nil "Show ElDoc in tooltips." :version "25.1" :group 'extensions) ;;;###autoload (define-minor-mode eldoc-tooltip-mode "Toggle ElDoc tooltip mode on or off." :group 'eldoc-tooltip (if eldoc-tooltip-mode (progn (set-frame-parameter nil 'eldoc-focus t) (add-hook 'focus-in-hook 'eldoc-tooltip--focus-in) (add-hook 'focus-out-hook 'eldoc-tooltip--focus-out) (add-hook 'window-configuration-change-hook 'eldoc-tooltip--hide-tip) (add-hook 'window-size-change-functions 'eldoc-tooltip--hide-tip) (unless (memq eldoc-tooltip-idle-timer timer-idle-list) (setq eldoc-tooltip-idle-timer (run-with-idle-timer eldoc-tooltip-delay t (if (fboundp 'window-absolute-body-pixel-edges) 'eldoc-tooltip--make-2 'eldoc-tooltip--make))))) (when eldoc-tooltip-idle-timer (cancel-timer eldoc-tooltip-idle-timer) (setq eldoc-tooltip-idle-timer nil)) (remove-hook 'focus-in-hook 'eldoc-tooltip--focus-in) (remove-hook 'focus-out-hook 'eldoc-tooltip--focus-out) (remove-hook 'window-configuration-change-hook 'eldoc-tooltip--hide-tip) (remove-hook 'window-size-change-functions 'eldoc-tooltip--hide-tip))) (defgroup eldoc-tooltip nil "Show function arglist or variable docstring in tooltip." :group 'eldoc) (defcustom eldoc-tooltip-delay 1.0 "Number of seconds of idle time to wait before showing eldoc tooltip. If user input arrives before this interval of time has elapsed after the last input, no documentation will be shown. If this variable is set to 0, no idle time is required." :type 'number :group 'eldoc-tooltip) (defcustom eldoc-tooltip-duration 60 "Number of seconds to show eldoc tooltip. If user input arrives before this time has elapsed, the tooltip will be hidden." :type 'number :group 'eldoc-tooltip) (defcustom eldoc-tooltip-location 'eols "Where to show ElDoc tooltip. Options are: `above' - over text on line above point `below' - over text on line below point `eols' - at ends of lines near point `top' on top of selected window `bottom' - on bottom of selected window" :type '(choice (const :tag "on line above point" above) (const :tag "on line below point" below) (const :tag "at line ends near point" eols) (const :tag "on top of selected window" top) (const :tag "on bottom of selected window" bottom)) :group 'eldoc-tooltip) (defcustom eldoc-tooltip-x-offset-alist '((above . 2) (current . 2) (below . 2) (top . 2) (bottom . 2)) "Offsets to adjust x-position of tooltips. These pixel offsets are added to the x-position of tooltips that respectively appear on the line above the current line (`above'), the current line (`current'), the line below the current line (`below'), the top edge of the window (`top') and the bottom edge of the window (`bottom')." :type '(alist :key-type (symbol :tag "Location") :value-type integer) :group 'eldoc-tooltip) (defcustom eldoc-tooltip-indent-above-below t "Non-nil means to show tooltips at indent of current line. This options takes affect only when tooltips shown at the beginning of a line, that is when `eldoc-tooltip-location' equals `above' or `below'. When this option is nil, such tooltips start at the visual beginning of the respective line." :type 'boolean :group 'eldoc-tooltip) (defcustom eldoc-tooltip-current-eol-extra-x-offset t "Extra offset for tooltip at end of current line. If non-nil this adds an extra offset of one character's width to avoid that the tooltip window overlays a block cursor at the end of the current line. If nil the offset is entirely determined by the value of `eldoc-tooltip-x-offsets'. Tooltips appearing above or below the current line are not affected by this option." :type 'boolean :group 'eldoc-tooltip) (defcustom eldoc-tooltip-y-offset-alist '((above . 0) (current . -2) (below . -2) (top . 2) (bottom . -2)) "Alist of offsets to adjust y-position of tooltips. These pixel offsets are added to the y-position of tooltips that respectively appear on the line above the current line (`above'), the current line (`current'), the line below the current line (`below'), the top edge of the window (`top') and the bottom edge of the window (`bottom')." :type '(alist :key-type (symbol :tag "Location") :value-type integer) :group 'eldoc-tooltip) (defcustom eldoc-tooltip-max-size '(120 . 1) "Maximimum size of ElDoc tooltips. A cons of rows and columns." :type '(cons (integer :tag "Columns") (integer :tag "Lines")) :group 'eldoc-tooltip) (defcustom eldoc-tooltip-frame-parameters '((background-color . "honeydew") (alpha . 60)) "Frame parameter alist used for ElDoc tooltips. The list of frame parameters passed to `x-show-tip' is built by appending to this a list built from the `left' and `top'/`bottom' parameters as produced by `eldoc-tooltip-make' and the value of `tooltip-frame-parameters'." :type '(alist :key-type symbol :value-type sexp) :group 'tooltip) (defvar eldoc-tooltip-idle-timer nil "ElDoc tooltip timer.") (defvar eldoc-tooltip-debug nil "Non-nil means display message about position of tooltip window.") (defun eldoc-tooltip--focus-in () "ElDoc tooltip mode function when selected frame gains focus." (set-frame-parameter nil 'eldoc-focus t)) ;; In the following two we should check that we own the tooltip. (defun eldoc-tooltip--focus-out () "ElDoc tooltip mode function when selected frame loses focus." (set-frame-parameter nil 'eldoc-focus nil) (x-hide-tip)) (defun eldoc-tooltip--hide-tip (&optional _ignore) "Hide ElDoc tooltip." (x-hide-tip)) (defun eldoc-tooltip--text () "Return text string for ElDoc tooltip, nil if there's none." (save-excursion (goto-char (window-point)) (when (boundp 'eldoc-documentation-function) ;; Alwasy try to get full string. (let ((eldoc-echo-area-use-multiline-p t)) (funcall eldoc-documentation-function))))) (defun eldoc-tooltip--current-line-wrapped-p () "Return non-nil when current line is wrapped." (save-excursion (< (progn (beginning-of-line) (vertical-motion 1) (point)) (progn (forward-line) (point))))) (defun eldoc-tooltip--make () "Make ElDoc tooltip." (let* ((pos-point (pos-visible-in-window-p (point) nil t)) ;; We make a tooltip iff `point' is visible in the selected ;; window, the frame has focus and we get a suitable text from ;; the corresponding eldoc function. Remember that ;; `pos-visible-in-window-p' may return non-nil even when POS ;; is scrolled off horizontally. (text (and eldoc-tooltip-mode pos-point (frame-parameter nil 'eldoc-focus) (eldoc-tooltip--text)))) (when text (let* ((edges (window-inside-pixel-edges)) (frame-geometry (frame-geometry)) ;; (x-frame-geometry) (frame-left-position (or (cadr (assq 'frame-position frame-geometry)) (cadr (assq 'outer-position frame-geometry)) (nth 1 (assq 'outer-edges frame-geometry)))) (frame-top-position (or (cddr (assq 'frame-position frame-geometry)) (cddr (assq 'outer-position frame-geometry)) (nth 2 (assq 'outer-edges frame-geometry)))) (frame-left (let ((edge (frame-parameter nil 'left))) (if (numberp edge) edge 0))) (left (+ frame-left ;; Count left border iff frame's left edge is on ;; screen (this should catch frame maximation by ;; moving the border off-display tricks). (if (< frame-left-position 0) 0 (cadr (assq 'external-border-size frame-geometry))) (nth 0 edges) ;; Count tool bar when it's on the left. (or (and (cdr (assq 'tool-bar-external frame-geometry)) (eq (cdr (assq 'tool-bar-position frame-geometry)) 'left) (cddr (assq 'tool-bar-size frame-geometry))) 0) ;; Count vertical scroll bar when it's on the ;; left. Don't care about fringes or margins yet. (if (eq (car (window-current-scroll-bars)) 'left) (window-scroll-bar-width) 0))) (frame-top (let ((edge (frame-parameter nil 'top))) (if (numberp edge) edge 0))) (top (+ frame-top ;; Count top border iff frame's top edge is on screen ;; (to catch frame maximation by moving the border ;; off-display tricks). Also, apparently ns counts the ;; top border in the title height already. (if (or (< frame-top-position 0) (eq (window-system) 'ns)) 0 (cddr (assq 'external-border-size frame-geometry))) ;; Add heights of title, menu and tool bar but only if ;; they are external (an "internal" tool or menu bar is ;; already counted by `window-pixel-edges'). (or (cdr (assq 'title-height frame-geometry)) (cddr (assq 'title-bar-size frame-geometry)) 0) (or (and (cdr (assq 'menu-bar-external frame-geometry)) (cddr (assq 'menu-bar-size frame-geometry))) 0) (or (and (cdr (assq 'tool-bar-external frame-geometry)) (eq (cdr (assq 'tool-bar-position frame-geometry)) 'top) (cddr (assq 'tool-bar-size frame-geometry))) 0) (if (eq eldoc-tooltip-location 'bottom) ;; Don't obscure mode line. (- (nth 3 edges) (window-mode-line-height) (window-bottom-divider-width)) (nth 1 edges)))) (x-max-tooltip-size eldoc-tooltip-max-size) parameters) (pcase eldoc-tooltip-location ((or `above `below) (let ((x-adjust (or (cdr (assq eldoc-tooltip-location eldoc-tooltip-x-offset-alist)) 0)) (y-adjust (or (cdr (assq eldoc-tooltip-location eldoc-tooltip-y-offset-alist)) 0)) (pos-x (if eldoc-tooltip-indent-above-below (save-excursion (beginning-of-line) (skip-chars-forward " \t") (nth 0 (pos-visible-in-window-p (point) nil t))) 0)) (pos-y (+ (nth 1 pos-point) (if (eq eldoc-tooltip-location 'above) 0 ;; `window-line-height' returns nil when ;; display is not up-to-date. (or (car (window-line-height)) (frame-char-height)))))) (when eldoc-tooltip-debug (message "%s %s %s %s [x: %s %s %s] [y: %s %s %s] -> %s" (if (or (< frame-top 0) (eq (window-system) 'ns)) 0 (cddr (assq 'external-border-size frame-geometry))) (or (cdr (assq 'title-height frame-geometry)) (cddr (assq 'title-bar-size frame-geometry)) 0) (or (and (cdr (assq 'menu-bar-external frame-geometry)) (cddr (assq 'menu-bar-size frame-geometry))) 0) (or (and (cdr (assq 'tool-bar-external frame-geometry)) (eq (cdr (assq 'tool-bar-position frame-geometry)) 'top) (cddr (assq 'tool-bar-size frame-geometry))) 0) left pos-x x-adjust top pos-y y-adjust (cons (+ left 0 x-adjust) (+ top pos-y y-adjust)))) (setq parameters (list (cons 'left (+ left pos-x x-adjust)) (if (eq eldoc-tooltip-location 'above) (cons 'bottom (+ top pos-y y-adjust)) (cons 'top (+ top pos-y y-adjust))))))) (`eols (let (where pos-above pos-this pos-below pos-x pos-y x-adjust y-adjust) (setq pos-this (pos-visible-in-window-p (line-end-position) nil t)) ;; Try current line first. (when pos-this (setq where 'current) (setq pos-x (nth 0 pos-this)) (setq pos-y (nth 1 pos-this))) ;; Try line above next. (when (and (setq pos-above (and (/= (line-beginning-position) (point-min)) (pos-visible-in-window-p (line-end-position 0) nil t))) (or (not pos-x) (< (nth 0 pos-above) pos-x))) (setq where 'above) (setq pos-x (nth 0 pos-above)) (setq pos-y (if truncate-lines ;; When lines are truncated use top ;; of the current line. (nth 1 pos-point) ;; Otherwise use top of beginning of ;; current line. (or (nth 1 (pos-visible-in-window-p (line-beginning-position) nil t)) 0)))) ;; Try line below last. (when (and (/= (line-end-position) (point-max)) (or truncate-lines (save-excursion (forward-line) (not (eldoc-tooltip--current-line-wrapped-p)))) (setq pos-below (pos-visible-in-window-p (line-end-position 2) nil t)) (or (not pos-x) (< (nth 0 pos-below) pos-x))) (setq where 'below) (setq pos-x (nth 0 pos-below)) (setq pos-y (nth 1 pos-below))) ;; If we didn't get a result till now simulate `above'. (unless pos-x (setq where 'above) (setq pos-x 0) (setq pos-y (nth 1 pos-point))) ;; If the window is scrolled horizontally, make sure the ;; tooltip doesn't start on the left of it. (setq pos-x (max 0 pos-x)) ;; Adjust offsets now. (setq x-adjust (or (cdr (assq where eldoc-tooltip-x-offset-alist)) 0)) (setq y-adjust (or (cdr (assq where eldoc-tooltip-y-offset-alist)) 0)) (when (and eldoc-tooltip-current-eol-extra-x-offset (or (= (point) (point-max)) (looking-at "\n"))) ;; Don't obscure block pointer at EOL. (setq x-adjust (+ x-adjust (frame-char-width)))) (when eldoc-tooltip-debug (message "%s %s %s %s - %s / %s / %s / %s -> %s [x: %s %s %s] [y: %s %s %s] -> %s" (if (or (< frame-top 0) (eq (window-system) 'ns)) 0 (cddr (assq 'external-border-size frame-geometry))) (or (cdr (assq 'title-height frame-geometry)) (cddr (assq 'title-bar-size frame-geometry)) 0) (or (and (cdr (assq 'menu-bar-external frame-geometry)) (cddr (assq 'menu-bar-size frame-geometry))) 0) (or (and (cdr (assq 'tool-bar-external frame-geometry)) (eq (cdr (assq 'tool-bar-position frame-geometry)) 'top) (cddr (assq 'tool-bar-size frame-geometry))) 0) pos-above pos-point pos-this pos-below where left pos-x x-adjust top pos-y y-adjust (cons (+ left pos-x x-adjust) (+ top pos-y y-adjust)))) (setq parameters (list (cons 'left (+ left pos-x x-adjust)) (if (eq where 'above) (cons 'bottom (+ top pos-y y-adjust)) (cons 'top (+ top pos-y y-adjust))))))) (`top (let* ((x-adjust (cdr (assq 'top eldoc-tooltip-x-offset-alist))) (y-adjust (cdr (assq 'top eldoc-tooltip-y-offset-alist)))) (when eldoc-tooltip-debug (message "[x: %s %s] [y: %s %s] -> %s" left x-adjust top y-adjust (cons (+ left x-adjust) (+ top y-adjust)))) (setq parameters (list (cons 'left (+ left x-adjust)) (cons 'bottom (+ top y-adjust)))))) (`bottom (let* ((x-adjust (cdr (assq 'top eldoc-tooltip-x-offset-alist))) (y-adjust (cdr (assq 'top eldoc-tooltip-y-offset-alist)))) (when eldoc-tooltip-debug (message "[x: %s %s] [y: %s %s] -> %s" left x-adjust top y-adjust (cons (+ left x-adjust) (+ top y-adjust)))) (setq parameters (list (cons 'left (+ left x-adjust)) (cons 'bottom (+ top y-adjust))))))) ;; Show tip. (when parameters (x-show-tip text (selected-frame) (append eldoc-tooltip-frame-parameters parameters tooltip-frame-parameters) eldoc-tooltip-duration 0 0)))))) (defun eldoc-tooltip--make-2 () "Make ElDoc tooltip. `window-absolute-body-pixel-edges' is needed for this." (let* ((pos-point (pos-visible-in-window-p (point) nil t)) ;; We make a tooltip iff `point' is visible in the selected ;; window, the frame has focus and we get a suitable text from ;; the corresponding eldoc function. Remember that ;; `pos-visible-in-window-p' may return non-nil even when POS ;; is scrolled off horizontally. (text (and eldoc-tooltip-mode pos-point (frame-parameter nil 'eldoc-focus) (eldoc-tooltip--text))) old-consed) ;; Optional. (when (boundp 'mode-line-operation-consed) (setq old-consed cons-cells-consed)) (when text (let* ((edges (and (fboundp 'window-absolute-body-pixel-edges) (window-absolute-body-pixel-edges))) (left (nth 0 edges)) (top (nth 1 edges)) (x-max-tooltip-size eldoc-tooltip-max-size) parameters) (pcase eldoc-tooltip-location ((or `above `below) (let ((x-adjust (or (cdr (assq eldoc-tooltip-location eldoc-tooltip-x-offset-alist)) 0)) (y-adjust (or (cdr (assq eldoc-tooltip-location eldoc-tooltip-y-offset-alist)) 0)) (pos-x (if eldoc-tooltip-indent-above-below (save-excursion (beginning-of-line) (skip-chars-forward " \t") (nth 0 (pos-visible-in-window-p (point) nil t))) 0)) (pos-y (+ (nth 1 pos-point) (if (eq eldoc-tooltip-location 'above) 0 ;; `window-line-height' returns nil when ;; display is not up-to-date. (or (car (window-line-height)) (frame-char-height)))))) (setq parameters (list (cons 'left (+ left pos-x x-adjust)) (if (eq eldoc-tooltip-location 'above) (cons 'bottom (+ top pos-y y-adjust)) (cons 'top (+ top pos-y y-adjust))))))) (`eols (let (where pos-above pos-this pos-below pos-x pos-y x-adjust y-adjust) (setq pos-this (pos-visible-in-window-p (line-end-position) nil t)) ;; Try current line first. (when pos-this (setq where 'current) (setq pos-x (nth 0 pos-this)) (setq pos-y (nth 1 pos-this))) ;; Try line above next. (when (and (setq pos-above (and (/= (line-beginning-position) (point-min)) (pos-visible-in-window-p (line-end-position 0) nil t))) (or (not pos-x) (< (nth 0 pos-above) pos-x))) (setq where 'above) (setq pos-x (nth 0 pos-above)) (setq pos-y (if truncate-lines ;; When lines are truncated use top ;; of the current line. (nth 1 pos-point) ;; Otherwise use top of beginning of ;; current line. (or (nth 1 (pos-visible-in-window-p (line-beginning-position) nil t)) 0)))) ;; Try line below last. (when (and (/= (line-end-position) (point-max)) (or truncate-lines (save-excursion (forward-line) (not (eldoc-tooltip--current-line-wrapped-p)))) (setq pos-below (pos-visible-in-window-p (line-end-position 2) nil t)) (or (not pos-x) (< (nth 0 pos-below) pos-x))) (setq where 'below) (setq pos-x (nth 0 pos-below)) (setq pos-y (nth 1 pos-below))) ;; If we didn't get a result till now simulate `above'. (unless pos-x (setq where 'above) (setq pos-x 0) (setq pos-y (nth 1 pos-point))) ;; If the window is scrolled horizontally, make sure the ;; tooltip doesn't start on the left of it. (setq pos-x (max 0 pos-x)) ;; Adjust offsets now. (setq x-adjust (or (cdr (assq where eldoc-tooltip-x-offset-alist)) 0)) (setq y-adjust (or (cdr (assq where eldoc-tooltip-y-offset-alist)) 0)) (when (and eldoc-tooltip-current-eol-extra-x-offset (eq where 'current) (or (= (point) (point-max)) (looking-at "\n"))) ;; Don't obscure block pointer at EOL. (setq x-adjust (+ x-adjust (frame-char-width)))) (setq parameters (list (cons 'left (+ left pos-x x-adjust)) (if (eq where 'above) (cons 'bottom (+ top pos-y y-adjust)) (cons 'top (+ top pos-y y-adjust))))))) (`top (let* ((x-adjust (cdr (assq 'top eldoc-tooltip-x-offset-alist))) (y-adjust (cdr (assq 'top eldoc-tooltip-y-offset-alist)))) (setq parameters (list (cons 'left (+ left x-adjust)) (cons 'top (+ top y-adjust)))))) (`bottom (let* ((x-adjust (cdr (assq 'bottom eldoc-tooltip-x-offset-alist))) (y-adjust (cdr (assq 'bottom eldoc-tooltip-y-offset-alist)))) (setq parameters (list (cons 'left (+ left x-adjust)) (cons 'bottom (+ (nth 3 edges) y-adjust))))))) (when parameters ;; Show tip first. (x-show-tip text (selected-frame) (append eldoc-tooltip-frame-parameters parameters tooltip-frame-parameters) eldoc-tooltip-duration 0 0) ;; If necessary, move mouse pointer away afterwards. (let* ((buffer (get-buffer " *tip*")) (window (and buffer (get-buffer-window buffer t))) (frame (and window (window-frame window))) (tip-edges (and frame (frame-edges frame 'outer))) (tip-left (nth 0 tip-edges)) (tip-top (nth 1 tip-edges)) (tip-right (nth 2 tip-edges)) (tip-bottom (nth 3 tip-edges)) (mouse-position (mouse-absolute-pixel-position)) (mouse-x (car mouse-position)) (mouse-y (cdr mouse-position))) (when (and tip-left tip-right mouse-x (<= tip-left mouse-x) (<= mouse-x tip-right) tip-top tip-bottom mouse-y (<= tip-top mouse-y) (<= mouse-y tip-bottom)) (let* ((window-edges (window-edges nil t t t)) (window-top (nth 1 window-edges))) ;; (message "frame: %s tip-left: %s tip-top: %s tip-right: %s tip-bottom: %s" ;; frame tip-left tip-top tip-right tip-bottom) (set-mouse-absolute-pixel-position mouse-x ;; If there's enough space within the seelcted window, ;; move mouse pointer two pixels above top of tooltip, ;; otherwise move it one pixel below bottom of tooltip. (if (< (+ window-top 2) tip-top) (- tip-top 2) (1+ tip-bottom))))))))) ;; Optional. (when (boundp 'mode-line-operation-consed) (setq mode-line-operation-consed (- cons-cells-consed old-consed))) )) (provide 'eldoc-tooltip) ;;; eldoc-tooltip.el ends here --------------0F520401EB024689D5EF3989--