Make `C-h b' indentation more regular (and avoid continuation lines)

* lisp/help.el (help--describe-command): Don't do any indentation.
(describe-map): Store data about each section.
(describe-map--align-section): New function to do indentation on a
per-block basis.
(describe-map--fill-columns): Helper function.
This commit is contained in:
Lars Ingebrigtsen 2021-11-02 02:36:49 +01:00
parent 8b74649407
commit d530f3f9ff
2 changed files with 85 additions and 44 deletions

View file

@ -1328,44 +1328,25 @@ Return nil if the key sequence is too long."
value)) value))
(t value)))) (t value))))
(defvar help--previous-description-column 0)
(defun help--describe-command (definition &optional translation) (defun help--describe-command (definition &optional translation)
;; Converted from describe_command in keymap.c. (cond ((symbolp definition)
;; If column 16 is no good, go to col 32; (insert-text-button (symbol-name definition)
;; but don't push beyond that--go to next line instead. 'type 'help-function
(let* ((column (current-column)) 'help-args (list definition))
(description-column (cond ((> column 30) (insert "\n"))
(insert "\n") ((or (stringp definition) (vectorp definition))
32) (if translation
((or (> column 14) (insert (key-description definition nil) "\n")
(and (> column 10) (insert "Keyboard Macro\n")))
(= help--previous-description-column 32))) ((keymapp definition)
32) (insert "Prefix Command\n"))
(t 16)))) ((byte-code-function-p definition)
;; Avoid using the `help-keymap' face. (insert "[byte-code]\n"))
(let ((op (point))) ((and (consp definition)
(indent-to description-column 1) (memq (car definition) '(closure lambda)))
(set-text-properties op (point) '( face nil (insert (format "[%s]\n" (car definition))))
font-lock-face nil))) (t
(setq help--previous-description-column description-column) (insert "??\n"))))
(cond ((symbolp definition)
(insert-text-button (symbol-name definition)
'type 'help-function
'help-args (list definition))
(insert "\n"))
((or (stringp definition) (vectorp definition))
(if translation
(insert (key-description definition nil) "\n")
(insert "Keyboard Macro\n")))
((keymapp definition)
(insert "Prefix Command\n"))
((byte-code-function-p definition)
(insert "[byte-code]\n"))
((and (consp definition)
(memq (car definition) '(closure lambda)))
(insert (format "[%s]\n" (car definition))))
(t
(insert "??\n")))))
(define-obsolete-function-alias 'help--describe-translation (define-obsolete-function-alias 'help--describe-translation
#'help--describe-command "29.1") #'help--describe-command "29.1")
@ -1395,12 +1376,22 @@ TRANSL, PARTIAL, SHADOW, NOMENU, MENTION-SHADOW are as in
(map (keymap-canonicalize map)) (map (keymap-canonicalize map))
(tail map) (tail map)
(first t) (first t)
(describer #'help--describe-command)
done vect) done vect)
(while (and (consp tail) (not done)) (while (and (consp tail) (not done))
(cond ((or (vectorp (car tail)) (char-table-p (car tail))) (cond ((or (vectorp (car tail)) (char-table-p (car tail)))
(help--describe-vector (car tail) prefix describer partial (let ((columns ()))
shadow map mention-shadow)) (help--describe-vector
(car tail) prefix
(lambda (def)
(let ((start-line (line-beginning-position))
(end-key (point))
(column (current-column)))
(help--describe-command def transl)
(push (list column start-line end-key (1- (point)))
columns)))
partial shadow map mention-shadow)
(when columns
(describe-map--align-section columns))))
((consp (car tail)) ((consp (car tail))
(let ((event (caar tail)) (let ((event (caar tail))
definition this-shadowed) definition this-shadowed)
@ -1443,7 +1434,9 @@ TRANSL, PARTIAL, SHADOW, NOMENU, MENTION-SHADOW are as in
(push (cons tail prefix) help--keymaps-seen))))) (push (cons tail prefix) help--keymaps-seen)))))
(setq tail (cdr tail))) (setq tail (cdr tail)))
;; If we found some sparse map events, sort them. ;; If we found some sparse map events, sort them.
(let ((vect (sort vect 'help--describe-map-compare))) (let ((vect (sort vect 'help--describe-map-compare))
(columns ())
line-start key-end column)
;; Now output them in sorted order. ;; Now output them in sorted order.
(while vect (while vect
(let* ((elem (car vect)) (let* ((elem (car vect))
@ -1469,19 +1462,22 @@ TRANSL, PARTIAL, SHADOW, NOMENU, MENTION-SHADOW are as in
;; Don't output keymap prefixes. ;; Don't output keymap prefixes.
(not (keymapp definition))) (not (keymapp definition)))
(when first (when first
(setq help--previous-description-column 0)
(insert "\n") (insert "\n")
(setq first nil)) (setq first nil))
;; Now START .. END is the range to describe next. ;; Now START .. END is the range to describe next.
;; Insert the string to describe the event START. ;; Insert the string to describe the event START.
(setq line-start (point))
(insert (help--key-description-fontified (vector start) prefix)) (insert (help--key-description-fontified (vector start) prefix))
(when (not (eq start end)) (when (not (eq start end))
(insert " .. " (help--key-description-fontified (vector end) (insert " .. " (help--key-description-fontified (vector end)
prefix))) prefix)))
(setq key-end (point)
column (current-column))
;; Print a description of the definition of this character. ;; Print a description of the definition of this character.
;; Called function will take care of spacing out far enough ;; Called function will take care of spacing out far enough
;; for alignment purposes. ;; for alignment purposes.
(help--describe-command definition transl) (help--describe-command definition transl)
(push (list column line-start key-end (1- (point))) columns)
;; Print a description of the definition of this character. ;; Print a description of the definition of this character.
;; elt_describer will take care of spacing out far enough for ;; elt_describer will take care of spacing out far enough for
;; alignment purposes. ;; alignment purposes.
@ -1490,7 +1486,52 @@ TRANSL, PARTIAL, SHADOW, NOMENU, MENTION-SHADOW are as in
(insert "\n (this binding is currently shadowed)") (insert "\n (this binding is currently shadowed)")
(goto-char (min (1+ (point)) (point-max)))))) (goto-char (min (1+ (point)) (point-max))))))
;; Next item in list. ;; Next item in list.
(setq vect (cdr vect)))))) (setq vect (cdr vect)))
(when columns
(describe-map--align-section columns)))))
(defun describe-map--align-section (columns)
(save-excursion
(let ((max-key (apply #'max (mapcar #'car columns))))
(cond
;; It's fine to use the minimum, so just do it, but quantize to
;; two different widths, because having each block align slightly
;; differently looks untidy.
((< max-key 16)
(describe-map--fill-columns columns 16))
((< max-key 24)
(describe-map--fill-columns columns 24))
((< max-key 32)
(describe-map--fill-columns columns 32))
;; We have some really wide ones in this block.
(t
(let ((window-width (window-width))
(max-def (apply #'max (mapcar
(lambda (elem)
(- (nth 3 elem) (nth 2 elem)))
columns))))
(if (< (+ max-def (max 16 max-key)) window-width)
;; Can we do the block without continuation lines? Then do that.
(describe-map--fill-columns columns (1+ (max 16 max-key)))
;; No, do continuation lines for some definitions.
(dolist (elem columns)
(goto-char (caddr elem))
(if (< (+ (car elem) (- (nth 3 elem) (nth 2 elem))) window-width)
;; Indent.
(insert-char ?\s (- (1+ max-key) (car elem)))
;; Continuation.
(insert "\n")
(insert-char ?\t 2))))))))))
(defun describe-map--fill-columns (columns width)
(dolist (elem columns)
(goto-char (caddr elem))
(let ((tabs (- (/ width tab-width)
(/ (car elem) tab-width))))
(insert-char ?\t tabs)
(insert-char ?\s (if (zerop tabs)
(- width (car elem))
(mod width tab-width))))))
;;;; This Lisp version is 100 times slower than its C equivalent: ;;;; This Lisp version is 100 times slower than its C equivalent:
;; ;;

View file

@ -318,7 +318,7 @@ Key Binding
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
C-a foo C-a foo
<menu-bar> <foo> foo <menu-bar> <foo> foo
"))))) ")))))
(ert-deftest help-tests-describe-map-tree/mention-shadow-t () (ert-deftest help-tests-describe-map-tree/mention-shadow-t ()