From 10e7c76ee3e263a7691745d9384bae475c2f5c86 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 4 Oct 2020 19:31:02 +0100 Subject: [PATCH] Rework semantics of eldoc-echo-are-use-multiline-p Per bug#43543. Now uses logical lines, not visual lines. * lisp/emacs-lisp/eldoc.el (eldoc-echo-area-use-multiline-p): Rework semantics. (eldoc--echo-area-substring): New helper. (eldoc--echo-area-prefer-doc-buffer-p): New helper. (eldoc-display-in-echo-area): Rework using new helpers. --- lisp/emacs-lisp/eldoc.el | 118 ++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index bad9eabe64d..922de18743d 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -96,19 +96,22 @@ Note that this variable has no effect, unless If value is t, never attempt to truncate messages, even if the echo area must be resized to fit. -If value is a number (integer or floating point), it has the -semantics of `max-mini-window-height', constraining the resizing -for ElDoc purposes only. +If the value is a positive number, it is used to calculate a +number of logical lines of documentation that ElDoc is allowed to +put in the echo area. If a positive integer, the number is used +directly, while a float specifies the number of lines as a +proporting of the echo area frame's height. -Any resizing respects `max-mini-window-height'. - -If value is any non-nil symbol other than t, the part of the doc -string that represents the symbol's name may be truncated if it -will enable the rest of the doc string to fit on a single line, -without resizing the echo area. +If value is the symbol `truncate-sym-name-if-fit' t, the part of +the doc string that represents a symbol's name may be truncated +if it will enable the rest of the doc string to fit on a single +line, without resizing the echo area. If value is nil, a doc string is always truncated to fit in a -single line of display in the echo area." +single line of display in the echo area. + +Any resizing of the echo area additionally respects +`max-mini-window-height'." :type '(radio (const :tag "Always" t) (float :tag "Fraction of frame height" 0.25) (integer :tag "Number of lines" 5) @@ -489,6 +492,41 @@ This holds the results of the last documentation request." "*eldoc*"))))) eldoc--doc-buffer) +(defun eldoc--echo-area-substring (available) + "Given AVAILABLE lines, get buffer substring to display in echo area. +Helper for `eldoc-display-in-echo-area'." + (let ((start (prog1 (progn + (goto-char (point-min)) + (skip-chars-forward " \t\n") + (point)) + (goto-char (line-end-position available)) + (skip-chars-backward " \t\n"))) + (truncated (save-excursion + (skip-chars-forward " \t\n") + (not (eobp))))) + (cond ((eldoc--echo-area-prefer-doc-buffer-p truncated) + nil) + ((and truncated + (> available 1) + eldoc-echo-area-display-truncation-message) + (goto-char (line-end-position 0)) + (concat (buffer-substring start (point)) + (format + "\n(Documentation truncated. Use `%s' to see rest)" + (substitute-command-keys "\\[eldoc-doc-buffer]")))) + (t + (buffer-substring start (point)))))) + +(defun eldoc--echo-area-prefer-doc-buffer-p (truncatedp) + "Tell if display in the echo area should be skipped. +Helper for `eldoc-display-in-echo-area'. If TRUNCATEDP the +documentation to potentially appear in the echo are is truncated." + (and (or (eq eldoc-echo-area-prefer-doc-buffer t) + (and truncatedp + (eq eldoc-echo-area-prefer-doc-buffer + 'maybe))) + (get-buffer-window eldoc--doc-buffer))) + (defun eldoc-display-in-echo-area (docs _interactive) "Display DOCS in echo area. Honor `eldoc-echo-area-use-multiline-p' and @@ -517,20 +555,13 @@ Honor `eldoc-echo-area-use-multiline-p' and (available (cl-typecase val (float (truncate (* (frame-height) val))) (integer val) - (t 1))) - single-doc single-doc-sym - (prefer-doc-buffer-p - (lambda (truncated) - (and (or (eq eldoc-echo-area-prefer-doc-buffer t) - (and truncated - (eq eldoc-echo-area-prefer-doc-buffer - 'maybe))) - (get-buffer-window eldoc--doc-buffer))))) + (t 'just-one-line))) + single-doc single-doc-sym) (let ((echo-area-message (cond - (;; To output to the echo area,We handle the + (;; To output to the echo area, we handle the ;; `truncate-sym-name-if-fit' special case first, by - ;; checking if for a lot of special conditions. + ;; checking for a lot of special conditions. (and (eq 'truncate-sym-name-if-fit eldoc-echo-area-use-multiline-p) (null (cdr docs)) @@ -541,49 +572,22 @@ Honor `eldoc-echo-area-use-multiline-p' and (not (string-match "\n" single-doc)) (> (+ (length single-doc) (length single-doc-sym) 2) width)) single-doc) - ((> available 1) - ;; The message takes one extra line, so if we don't - ;; display that, we have one extra line to use. - (unless eldoc-echo-area-display-truncation-message - (setq available (1+ available))) - ;; Else we format the *eldoc* buffer, then use some of - ;; its contents top section. I'm pretty sure smarter - ;; strategies can be used here that don't necessarily - ;; involve composing that entire buffer. + ((and (numberp available) + (cl-plusp available)) + ;; Else, given a positive number of logical lines, we + ;; format the *eldoc* buffer, using as most of its + ;; contents as we know will fit. (with-current-buffer (eldoc--format-doc-buffer docs) - (cl-loop - initially - (goto-char (point-min)) - (goto-char (line-end-position (1+ available))) - for truncated = nil then t - for needed - = (let ((truncate-lines message-truncate-lines)) - (count-screen-lines (point-min) (point) t - (minibuffer-window))) - while (> needed (if truncated (1- available) available)) - do (goto-char (line-end-position (if truncated 0 -1))) - (while (and (not (bobp)) (bolp)) (goto-char (line-end-position 0))) - finally - (unless (funcall prefer-doc-buffer-p truncated) - (cl-return - (concat - (buffer-substring (point-min) (point)) - (and - truncated - (if eldoc-echo-area-display-truncation-message - (format - "\n(Documentation truncated. Use `%s' to see rest)" - (substitute-command-keys "\\[eldoc-doc-buffer]")) - "...")))))))) - ((= available 1) + (eldoc--echo-area-substring available))) + (t ;; this is the "truncate brutally" situation (let ((string (with-current-buffer (eldoc--format-doc-buffer docs) (buffer-substring (goto-char (point-min)) (line-end-position 1))))) (if (> (length string) width) ; truncation to happen - (unless (funcall prefer-doc-buffer-p t) + (unless (eldoc--echo-area-prefer-doc-buffer-p t) (truncate-string-to-width string width)) - (unless (funcall prefer-doc-buffer-p nil) + (unless (eldoc--echo-area-prefer-doc-buffer-p nil) string))))))) (when echo-area-message (eldoc--message echo-area-message))))))) -- 2.39.2