emacs/lisp/tmm.el

570 lines
24 KiB
EmacsLisp
Raw Permalink Normal View History

;;; tmm.el --- text mode access to menu-bar -*- lexical-binding: t -*-
1995-03-11 03:57:25 +00:00
;; Copyright (C) 1994-1996, 2000-2025 Free Software Foundation, Inc.
1995-03-11 03:57:25 +00:00
;; Author: Ilya Zakharevich <ilya@math.mps.ohio-state.edu>
;; Maintainer: emacs-devel@gnu.org
;; Keywords: convenience
1995-03-11 03:57:25 +00:00
1995-03-11 03:58:31 +00:00
;; This file is part of GNU Emacs.
1995-03-11 03:57:25 +00:00
;; GNU Emacs is free software: you can redistribute it and/or modify
1995-03-11 03:57:25 +00:00
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
1995-03-11 03:57:25 +00:00
;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
1995-03-11 03:57:25 +00:00
1996-01-14 07:34:30 +00:00
;;; Commentary:
1995-03-11 03:57:25 +00:00
;; This package provides text mode access to the menu bar.
1995-03-11 03:57:25 +00:00
1996-01-14 07:34:30 +00:00
;;; Code:
1995-03-11 03:57:25 +00:00
(require 'electric)
(require 'text-property-search)
1995-03-11 03:57:25 +00:00
1998-03-07 18:19:38 +00:00
(defgroup tmm nil
"Text mode access to menu-bar."
:prefix "tmm-"
:group 'menu)
1995-03-11 03:57:25 +00:00
;;; The following will be localized, added only to pacify the compiler.
(defvar tmm-short-cuts)
(defvar tmm-old-mb-map nil)
(defvar tmm-c-prompt nil)
1995-03-11 03:57:25 +00:00
(defvar tmm-km-list)
(defvar tmm-next-shortcut-digit)
1995-03-11 03:57:25 +00:00
(defvar tmm-table-undef)
1995-08-28 00:15:59 +00:00
;;;###autoload (define-key global-map "\M-`" 'tmm-menubar)
1995-03-11 03:57:25 +00:00
;;;###autoload
(defun tmm-menubar (&optional x-position)
1995-03-11 03:57:25 +00:00
"Text-mode emulation of looking and choosing from a menubar.
See the documentation for `tmm-prompt'.
X-POSITION, if non-nil, specifies a horizontal position within the menu bar;
we make that menu bar item (the one at that position) the default choice.
Note that \\[menu-bar-open] by default drops down TTY menus; if you want it
to invoke `tmm-menubar' instead, customize the variable
`tty-menu-open-use-tmm' to a non-nil value."
1995-03-11 03:57:25 +00:00
(interactive)
(run-hooks 'menu-bar-update-hook)
(if isearch-mode
(isearch-tmm-menubar)
(let ((menu-bar (menu-bar-keymap))
(menu-bar-item-cons (and x-position
(menu-bar-item-at-x x-position))))
(tmm-prompt menu-bar
nil
(and menu-bar-item-cons (car menu-bar-item-cons))))))
;;;###autoload
(defun tmm-menubar-mouse (event)
"Text-mode emulation of looking and choosing from a menubar.
This command is used when you click the mouse in the menubar
on a console which has no window system but does have a mouse.
See the documentation for `tmm-prompt'."
(interactive "e")
(tmm-menubar (car (posn-x-y (event-start event)))))
1995-03-11 03:57:25 +00:00
1998-03-07 18:19:38 +00:00
(defcustom tmm-mid-prompt "==>"
"String to insert between shortcut and menu item.
If nil, there will be no shortcuts. It should not consist only of spaces,
1998-03-07 18:19:38 +00:00
or else the correct item might not be found in the `*Completions*' buffer."
:type '(choice (const :tag "No shortcuts" nil)
string))
1995-03-11 03:57:25 +00:00
(defcustom tmm-completion-prompt
"Press M-v/PageUp key to reach this buffer from the minibuffer.
Alternatively, You can use Up/Down keys (or your History keys) to change
the item in the minibuffer, and press RET when you are done, or press
the %s to pick up your choice.
Type ^ to go to the parent menu. Type C-g or ESC ESC ESC to cancel.
1995-03-11 03:57:25 +00:00
"
"Help text to insert on the top of the completion buffer.
To save space, you can set this to nil,
1998-03-07 18:19:38 +00:00
in which case the standard introduction text is deleted too."
:type '(choice string (const nil)))
1998-03-07 18:19:38 +00:00
(defcustom tmm-shortcut-style '(downcase upcase)
"What letters to use as menu shortcuts.
Must be either one of the symbols `downcase' or `upcase',
1998-03-07 18:19:38 +00:00
or else a list of the two in the order you prefer."
:type '(choice (const downcase)
(const upcase)
(repeat (choice (const downcase) (const upcase)))))
1998-03-07 18:19:38 +00:00
(defcustom tmm-shortcut-words 2
"How many successive words to try for shortcuts, nil means all.
If you use only one of `downcase' or `upcase' for `tmm-shortcut-style',
1998-03-07 18:19:38 +00:00
specify nil for this variable."
:type '(choice integer (const nil)))
1995-03-11 03:57:25 +00:00
(defcustom tmm-shortcut-inside-entry nil
"Highlight the shortcut character in the menu entry's string.
When non-nil, the first menu-entry's character that acts as a shortcut
is displayed with the `highlight' face to help identify it. The
`tmm-mid-prompt' string is not used then."
:type 'boolean)
(defface tmm-inactive
'((t :inherit shadow))
"Face used for inactive menu items.")
(defvar tmm--history nil)
1995-03-11 03:57:25 +00:00
;;;###autoload
(defun tmm-prompt (menu &optional in-popup default-item no-execute path)
1995-03-11 03:57:25 +00:00
"Text-mode emulation of calling the bindings in keymap.
Creates a text-mode menu of possible choices. You can access the elements
in the menu in two ways:
*) via history mechanism from minibuffer;
1995-03-11 03:57:25 +00:00
*) Or via completion-buffer that is automatically shown.
The last alternative is currently a hack, you cannot use mouse reliably.
MENU is like the MENU argument to `x-popup-menu': either a
keymap or an alist of alists.
DEFAULT-ITEM, if non-nil, specifies an initial default choice.
Its value should be an event that has a binding in MENU.
NO-EXECUTE, if non-nil, means to return the command the user selects
instead of executing it.
PATH is a stack that keeps track of your path through sub-menus. It
is used to go back through those sub-menus."
;; If the optional argument IN-POPUP is t,
;; then MENU is an alist of elements of the form (STRING . VALUE).
;; That is used for recursive calls only.
(let ((gl-str "Menu bar") ;; The menu bar itself is not a menu keymap
; so it doesn't have a name.
tmm-km-list out history-len tmm-table-undef tmm-c-prompt
tmm-old-mb-map tmm-short-cuts
chosen-string choice
(not-menu (not (keymapp menu))))
1995-03-11 03:57:25 +00:00
(run-hooks 'activate-menubar-hook)
;; Compute tmm-km-list from MENU.
;; tmm-km-list is an alist of (STRING . MEANING).
;; It has no other elements.
;; The order of elements in tmm-km-list is the order of the menu bar.
(if (not not-menu)
(map-keymap (lambda (k v) (tmm-get-keymap (cons k v))) menu)
(dolist (elt menu)
(cond
((stringp elt) (setq gl-str elt))
((listp elt) (tmm-get-keymap elt not-menu))
((vectorp elt)
(dotimes (i (length elt))
(tmm-get-keymap (cons i (aref elt i)) not-menu))))))
;; Choose an element of tmm-km-list; put it in choice.
(if (and not-menu (= 1 (length tmm-km-list)))
;; If this is the top-level of an x-popup-menu menu,
;; and there is just one pane, choose that one silently.
;; This way we only ask the user one question,
;; for which element of that pane.
(setq choice (cdr (car tmm-km-list)))
(unless tmm-km-list
(error "Empty menu reached"))
(and tmm-km-list
(let ((index-of-default 0))
(setq tmm-km-list
(if tmm-mid-prompt
(tmm-add-shortcuts tmm-km-list)
;; tmm-add-shortcuts reverses tmm-km-list internally.
(reverse tmm-km-list)))
;; Find the default item's index within the menu bar.
;; We use this to decide the initial minibuffer contents
;; and initial history position.
(if default-item
(let ((tail menu) visible)
(while (and tail
(not (eq (car-safe (car tail)) default-item)))
;; Be careful to count only the elements of MENU
;; that actually constitute menu bar items.
(if (and (consp (car tail))
(or (stringp (car-safe (cdr (car tail))))
(and
(eq (car-safe (cdr (car tail))) 'menu-item)
(progn
(setq visible
(plist-get
(nthcdr 4 (car tail)) :visible))
(or (not visible) (eval visible))))))
(setq index-of-default (1+ index-of-default)))
(setq tail (cdr tail)))))
(let ((prompt
(concat "^"
(if (and (stringp tmm-mid-prompt)
(not tmm-shortcut-inside-entry))
(concat "."
(regexp-quote tmm-mid-prompt))))))
(setq tmm--history
(reverse (delq nil
(mapcar
(lambda (elt)
(if (string-match prompt (car elt))
(car elt)))
tmm-km-list)))))
(setq history-len (length tmm--history))
(setq tmm-c-prompt (nth (- history-len 1 index-of-default)
tmm--history))
(setq out
(if default-item
(car (nth index-of-default tmm-km-list))
New customization variable `completion-eager-display' The customization option can be set to t or nil, to respectively always or never show the *Completions* buffer eagerly at the beginning of a completion session. Furthermore the option can be set to the value auto. In this case the *Completions* buffer will only be shown if requested by the completion table. Completion tables can use the `eager-display' completion metadata to do so. (Bug#74616, Bug#74617) * lisp/minibuffer.el (completion-eager-display): New customization variable. (completion-metadata): Update docstring, document the new `eager-display' completion metadata. (completion-extra-properties): Update docstring, document the new `:eager-display' completion metadata. (completion-category-overrides): Add `eager-display' to the custom type specification. (completing-read-default): Handle the `completion-eager-display' customization variable and the `eager-display' completion metadata. (completion-table-with-metadata): New function to create a completion table with metadata. (minibuffer-complete-defaults, minibuffer-complete-history): Use it. * lisp/ffap.el (ffap-menu-ask): Add `ffap-menu' completion category and `eager-display' completion metadata. Use `completion-table-with-metadata'. * lisp/imenu.el (imenu-eager-completion-buffer): Correct docstring, which had been inverted. (imenu--completion-buffer): Add `eager-display' completion metadata. Use `completion-table-with-metadata'. * lisp/tmm.el (tmm-prompt): Add `tmm' completion category and `eager-display' completion metadata. Use `completion-table-with-metadata'. Add keymap setup. (tmm-add-prompt): Remove keymap setup. (tmm-goto-completions): Call `tmm-add-prompt' to ensure that a *Completions* buffer is shown. (tmm--completion-table): Remove unused internal function. * etc/NEWS: Announce the change.
2024-12-08 20:05:07 +01:00
(minibuffer-with-setup-hook
(lambda ()
(setq tmm-old-mb-map (tmm-define-keys t)))
;; tmm-km-list is reversed, because history
;; needs it in LIFO order. But default list
;; needs it in non-reverse order, so that the
;; menu items are displayed by M-n as default
;; values in the order they are shown on
;; the menu bar. So pass the DEFAULT arg the
;; reversed copy of the list.
(completing-read-default
(concat gl-str
" (up/down to change, PgUp to menu): ")
New customization variable `completion-eager-display' The customization option can be set to t or nil, to respectively always or never show the *Completions* buffer eagerly at the beginning of a completion session. Furthermore the option can be set to the value auto. In this case the *Completions* buffer will only be shown if requested by the completion table. Completion tables can use the `eager-display' completion metadata to do so. (Bug#74616, Bug#74617) * lisp/minibuffer.el (completion-eager-display): New customization variable. (completion-metadata): Update docstring, document the new `eager-display' completion metadata. (completion-extra-properties): Update docstring, document the new `:eager-display' completion metadata. (completion-category-overrides): Add `eager-display' to the custom type specification. (completing-read-default): Handle the `completion-eager-display' customization variable and the `eager-display' completion metadata. (completion-table-with-metadata): New function to create a completion table with metadata. (minibuffer-complete-defaults, minibuffer-complete-history): Use it. * lisp/ffap.el (ffap-menu-ask): Add `ffap-menu' completion category and `eager-display' completion metadata. Use `completion-table-with-metadata'. * lisp/imenu.el (imenu-eager-completion-buffer): Correct docstring, which had been inverted. (imenu--completion-buffer): Add `eager-display' completion metadata. Use `completion-table-with-metadata'. * lisp/tmm.el (tmm-prompt): Add `tmm' completion category and `eager-display' completion metadata. Use `completion-table-with-metadata'. Add keymap setup. (tmm-add-prompt): Remove keymap setup. (tmm-goto-completions): Call `tmm-add-prompt' to ensure that a *Completions* buffer is shown. (tmm--completion-table): Remove unused internal function. * etc/NEWS: Announce the change.
2024-12-08 20:05:07 +01:00
(completion-table-with-metadata
tmm-km-list '((category . tmm)
(eager-display . tmm-add-prompt)
(display-sort-function . identity)
(cycle-sort-function . identity)))
nil t nil
'tmm--history (reverse tmm--history)))))))
(if (and (stringp out) (string= "^" out))
;; A fake choice to please the destructuring later.
(setq choice (cons out out))
(setq choice (cdr (assoc out tmm-km-list)))
(and (null choice)
(string-prefix-p tmm-c-prompt out)
(setq out (substring out (length tmm-c-prompt))
choice (cdr (assoc out tmm-km-list))))
(and (null choice) out
(setq out (try-completion out tmm-km-list)
choice (cdr (assoc out tmm-km-list))))))
;; CHOICE is now (STRING . MEANING). Separate the two parts.
(setq chosen-string (car choice))
(setq choice (cdr choice))
(cond ((and (stringp choice) (string= "^" choice))
;; User wants to go up: do it first.
(if path (tmm-prompt (pop path) in-popup nil nil path)))
(in-popup
;; We just did the inner level of a -popup menu.
choice)
;; We just did the outer level. Do the inner level now.
(not-menu (tmm-prompt choice t nil no-execute (cons menu path)))
;; We just handled a menu keymap and found another keymap.
((keymapp choice)
(if (symbolp choice)
(setq choice (indirect-function choice)))
(condition-case nil
(require 'mouse)
(error nil))
(tmm-prompt choice nil nil no-execute (cons menu path)))
;; We just handled a menu keymap and found a command.
(choice
(if chosen-string
(if no-execute choice
(setq last-command-event chosen-string)
(call-interactively choice))
choice)))))
1995-03-11 03:57:25 +00:00
(defun tmm-add-shortcuts (list)
"Add shortcuts to cars of elements of the list.
1995-03-11 03:57:25 +00:00
Takes a list of lists with a string as car, returns list with
shortcuts added to these cars.
Stores a list of all the shortcuts in the free variable `tmm-short-cuts'."
(let ((tmm-next-shortcut-digit ?0))
(mapcar #'tmm-add-one-shortcut (reverse list))))
1995-03-11 03:57:25 +00:00
(defun tmm--shorten-space-width (str)
"Shorten the width between the menu entry and the keybinding by 2 spaces."
(let* ((start (next-single-property-change 0 'display str))
(n (length str))
(end (previous-single-property-change n 'display str))
(curr-width (and start
(plist-get (get-display-property start 'space str) :width))))
(when curr-width
(put-text-property start end 'display (cons 'space (list :width (- curr-width 2))) str))
str))
(defsubst tmm-add-one-shortcut (elt)
;; uses the free vars tmm-next-shortcut-digit and tmm-short-cuts
(cond
((eq (cddr elt) 'ignore)
(cons (concat " " (make-string (length tmm-mid-prompt) ?\-)
(car elt))
(cdr elt)))
(t
(let* ((str (car elt))
Use string-search instead of string-match[-p] `string-search` is easier to understand, less error-prone, much faster, does not pollute the regexp cache, and does not mutate global state. Use it where applicable and obviously safe (erring on the conservative side). * admin/authors.el (authors-canonical-file-name) (authors-scan-change-log): * lisp/apropos.el (apropos-command) (apropos-documentation-property, apropos-symbols-internal): * lisp/arc-mode.el (archive-arc-summarize) (archive-zoo-summarize): * lisp/calc/calc-aent.el (math-read-factor): * lisp/calc/calc-ext.el (math-read-big-expr) (math-format-nice-expr, math-format-number-fancy): * lisp/calc/calc-forms.el (math-read-angle-brackets): * lisp/calc/calc-graph.el (calc-graph-set-range): * lisp/calc/calc-keypd.el (calc-keypad-press): * lisp/calc/calc-lang.el (tex, latex, math-read-big-rec): * lisp/calc/calc-prog.el (calc-fix-token-name) (calc-user-define-permanent, math-define-exp): * lisp/calc/calc.el (calc-record, calcDigit-key) (calc-count-lines): * lisp/calc/calcalg2.el (calc-solve-for, calc-poly-roots) (math-do-integral): * lisp/calc/calcalg3.el (calc-find-root, calc-find-minimum) (calc-get-fit-variables): * lisp/cedet/ede/speedbar.el (ede-tag-expand): * lisp/cedet/semantic/java.el (semantic-java-expand-tag): * lisp/cedet/semantic/sb.el (semantic-sb-show-extra) (semantic-sb-expand-group): * lisp/cedet/semantic/wisent/python.el (semantic-python-instance-variable-p): * lisp/cus-edit.el (get): * lisp/descr-text.el (describe-text-sexp): * lisp/dired-aux.el (dired-compress-file): * lisp/dired-x.el (dired-make-relative-symlink): * lisp/dired.el (dired-glob-regexp): * lisp/dos-fns.el (dos-convert-standard-filename, dos-8+3-filename): * lisp/edmacro.el (edmacro-format-keys): * lisp/emacs-lisp/eieio-opt.el (eieio-sb-expand): * lisp/emacs-lisp/eieio-speedbar.el (eieio-speedbar-object-expand): * lisp/emacs-lisp/lisp-mnt.el (lm-keywords-list): * lisp/emacs-lisp/warnings.el (display-warning): * lisp/emulation/viper-ex.el (viper-ex-read-file-name) (ex-print-display-lines): * lisp/env.el (read-envvar-name, setenv): * lisp/epa-mail.el (epa-mail-encrypt): * lisp/epg.el (epg--start): * lisp/erc/erc-backend.el (erc-parse-server-response): * lisp/erc/erc-dcc.el (erc-dcc-member): * lisp/erc/erc-speedbar.el (erc-speedbar-expand-server) (erc-speedbar-expand-channel, erc-speedbar-expand-user): * lisp/erc/erc.el (erc-send-input): * lisp/eshell/em-glob.el (eshell-glob-entries): * lisp/eshell/esh-proc.el (eshell-needs-pipe-p): * lisp/eshell/esh-util.el (eshell-convert): * lisp/eshell/esh-var.el (eshell-envvar-names): * lisp/faces.el (x-resolve-font-name): * lisp/ffap.el (ffap-file-at-point): * lisp/files.el (wildcard-to-regexp, shell-quote-wildcard-pattern): * lisp/forms.el (forms--update): * lisp/frameset.el (frameset-filter-unshelve-param): * lisp/gnus/gnus-art.el (article-decode-charset): * lisp/gnus/gnus-kill.el (gnus-kill-parse-rn-kill-file): * lisp/gnus/gnus-mlspl.el (gnus-group-split-fancy): * lisp/gnus/gnus-msg.el (gnus-summary-resend-message-insert-gcc) (gnus-inews-insert-gcc): * lisp/gnus/gnus-rfc1843.el (rfc1843-decode-article-body): * lisp/gnus/gnus-search.el (gnus-search-indexed-parse-output) (gnus-search--complete-key-data): * lisp/gnus/gnus-spec.el (gnus-parse-simple-format): * lisp/gnus/gnus-sum.el (gnus-summary-refer-article): * lisp/gnus/gnus-util.el (gnus-extract-address-components) (gnus-newsgroup-directory-form): * lisp/gnus/gnus-uu.el (gnus-uu-grab-view): * lisp/gnus/gnus.el (gnus-group-native-p, gnus-short-group-name): * lisp/gnus/message.el (message-check-news-header-syntax) (message-make-message-id, message-user-mail-address) (message-make-fqdn, message-get-reply-headers, message-followup): * lisp/gnus/mm-decode.el (mm-dissect-buffer): * lisp/gnus/nnheader.el (nnheader-insert): * lisp/gnus/nnimap.el (nnimap-process-quirk) (nnimap-imap-ranges-to-gnus-ranges): * lisp/gnus/nnmaildir.el (nnmaildir--ensure-suffix): * lisp/gnus/nnmairix.el (nnmairix-determine-original-group-from-path): * lisp/gnus/nnrss.el (nnrss-match-macro): * lisp/gnus/nntp.el (nntp-find-group-and-number): * lisp/help-fns.el (help--symbol-completion-table-affixation): * lisp/help.el (help-function-arglist): * lisp/hippie-exp.el (he-concat-directory-file-name): * lisp/htmlfontify.el (hfy-relstub): * lisp/ido.el (ido-make-prompt, ido-complete, ido-copy-current-word) (ido-exhibit): * lisp/image/image-converter.el (image-convert-p): * lisp/info-xref.el (info-xref-docstrings): * lisp/info.el (Info-toc-build, Info-follow-reference) (Info-backward-node, Info-finder-find-node) (Info-speedbar-expand-node): * lisp/international/mule-diag.el (print-fontset-element): * lisp/language/korea-util.el (default-korean-keyboard): * lisp/linum.el (linum-after-change): * lisp/mail/ietf-drums.el (ietf-drums-parse-address): * lisp/mail/mail-utils.el (mail-dont-reply-to): * lisp/mail/rfc2047.el (rfc2047-encode-1, rfc2047-decode-string): * lisp/mail/rfc2231.el (rfc2231-parse-string): * lisp/mail/rmailkwd.el (rmail-set-label): * lisp/mail/rmailsum.el (rmail-header-summary): * lisp/mail/smtpmail.el (smtpmail-maybe-append-domain) (smtpmail-user-mail-address): * lisp/mail/uce.el (uce-reply-to-uce): * lisp/man.el (Man-default-man-entry): * lisp/mh-e/mh-alias.el (mh-alias-gecos-name) (mh-alias-minibuffer-confirm-address): * lisp/mh-e/mh-comp.el (mh-forwarded-letter-subject): * lisp/mh-e/mh-speed.el (mh-speed-parse-flists-output): * lisp/mh-e/mh-utils.el (mh-collect-folder-names-filter) (mh-folder-completion-function): * lisp/minibuffer.el (completion--make-envvar-table) (completion-file-name-table, completion-flex-try-completion) (completion-flex-all-completions): * lisp/mpc.el (mpc--proc-quote-string, mpc-cmd-special-tag-p) (mpc-constraints-tag-lookup): * lisp/net/ange-ftp.el (ange-ftp-send-cmd) (ange-ftp-allow-child-lookup): * lisp/net/mailcap.el (mailcap-mime-types): * lisp/net/mairix.el (mairix-search-thread-this-article): * lisp/net/pop3.el (pop3-open-server): * lisp/net/soap-client.el (soap-decode-xs-complex-type): * lisp/net/socks.el (socks-filter): * lisp/nxml/nxml-outln.el (nxml-highlighted-qname): * lisp/nxml/rng-cmpct.el (rng-c-expand-name, rng-c-expand-datatype): * lisp/nxml/rng-uri.el (rng-uri-file-name-1): * lisp/obsolete/complete.el (partial-completion-mode) (PC-do-completion): * lisp/obsolete/longlines.el (longlines-encode-string): * lisp/obsolete/nnir.el (nnir-compose-result): * lisp/obsolete/terminal.el (te-quote-arg-for-sh): * lisp/obsolete/tpu-edt.el (tpu-check-search-case): * lisp/obsolete/url-ns.el (isPlainHostName): * lisp/pcmpl-unix.el (pcomplete/scp): * lisp/play/dunnet.el (dun-listify-string2, dun-get-path) (dun-unix-parse, dun-doassign, dun-cat, dun-batch-unix-interface): * lisp/progmodes/ebnf2ps.el: (ebnf-eps-header-footer-comment): * lisp/progmodes/gdb-mi.el (gdb-var-delete) (gdb-speedbar-expand-node, gdbmi-bnf-incomplete-record-result): * lisp/progmodes/gud.el (gud-find-expr): * lisp/progmodes/idlw-help.el (idlwave-do-context-help1): * lisp/progmodes/idlw-shell.el (idlwave-shell-mode) (idlwave-shell-filter-hidden-output, idlwave-shell-filter): * lisp/progmodes/idlwave.el (idlwave-skip-label-or-case) (idlwave-routine-info): * lisp/progmodes/octave.el (inferior-octave-completion-at-point): * lisp/progmodes/sh-script.el (sh-add-completer): * lisp/progmodes/sql.el (defun): * lisp/progmodes/xscheme.el (xscheme-process-filter): * lisp/replace.el (query-replace-compile-replacement) (map-query-replace-regexp): * lisp/shell.el (shell--command-completion-data) (shell-environment-variable-completion): * lisp/simple.el (display-message-or-buffer): * lisp/speedbar.el (speedbar-dired, speedbar-tag-file) (speedbar-tag-expand): * lisp/subr.el (split-string-and-unquote): * lisp/tar-mode.el (tar-extract): * lisp/term.el (term-command-hook, serial-read-name): * lisp/textmodes/bibtex.el (bibtex-print-help-message): * lisp/textmodes/ispell.el (ispell-lookup-words, ispell-filter) (ispell-parse-output, ispell-buffer-local-parsing): * lisp/textmodes/reftex-cite.el (reftex-do-citation): * lisp/textmodes/reftex-parse.el (reftex-notice-new): * lisp/textmodes/reftex-ref.el (reftex-show-entry): * lisp/textmodes/reftex.el (reftex-compile-variables): * lisp/textmodes/tex-mode.el (tex-send-command) (tex-start-tex, tex-append): * lisp/thingatpt.el (thing-at-point-url-at-point): * lisp/tmm.el (tmm-add-one-shortcut): * lisp/transient.el (transient-format-key): * lisp/url/url-auth.el (url-basic-auth) (url-digest-auth-directory-id-assoc): * lisp/url/url-news.el (url-news): * lisp/url/url-util.el (url-parse-query-string): * lisp/vc/vc-cvs.el (vc-cvs-parse-entry): * lisp/wid-browse.el (widget-browse-sexp): * lisp/woman.el (woman-parse-colon-path, woman-mini-help) (WoMan-getpage-in-background, woman-negative-vertical-space): * lisp/xml.el: * test/lisp/emacs-lisp/check-declare-tests.el (check-declare-tests-warn): * test/lisp/files-tests.el (files-tests-file-name-non-special-dired-compress-handler): * test/lisp/net/network-stream-tests.el (server-process-filter): * test/src/coding-tests.el (ert-test-unibyte-buffer-dos-eol-decode): Use `string-search` instead of `string-match` and `string-match-p`.
2021-08-09 11:20:00 +02:00
(paren (string-search "(" str))
(word 0) pos char)
(catch 'done ; ??? is this slow?
(while (and (or (not tmm-shortcut-words) ; no limit on words
(< word tmm-shortcut-words)) ; try n words
(setq pos (string-match "\\w+" str pos)) ; get next word
(not (and paren (> pos paren)))) ; don't go past "(binding.."
(if (or (= pos 0)
(/= (aref str (1- pos)) ?.)) ; avoid file extensions
(dolist (shortcut-style ; try upcase and downcase variants
(if (listp tmm-shortcut-style) ; convert to list
tmm-shortcut-style
(list tmm-shortcut-style)))
(setq char (funcall shortcut-style (aref str pos)))
(if (not (memq char tmm-short-cuts)) (throw 'done char))))
(setq word (1+ word))
(setq pos (match-end 0)))
;; A nil value for pos means that the shortcut is not inside the
;; string of the menu entry.
(setq pos nil)
(while (<= tmm-next-shortcut-digit ?9) ; no letter shortcut, pick a digit
(setq char tmm-next-shortcut-digit)
(setq tmm-next-shortcut-digit (1+ tmm-next-shortcut-digit))
(if (not (memq char tmm-short-cuts)) (throw 'done char)))
(setq char nil))
(if char (setq tmm-short-cuts (cons char tmm-short-cuts)))
(cons
(if tmm-shortcut-inside-entry
(if char
(if pos
;; A character inside the menu entry.
(let ((res (copy-sequence str)))
(aset res pos char)
(add-text-properties pos (1+ pos) '(face highlight) res)
res)
;; A fallback digit character: place it in front of the
;; menu entry. We need to shorten the spaces between
;; the menu entry and the keybinding by two spaces
;; because we added two characters at the front (one
;; digit and one space) and this would cause a
2025-01-19 13:59:13 +01:00
;; misalignment otherwise.
(tmm--shorten-space-width
(concat (propertize (char-to-string char) 'face 'highlight)
" " str)))
(make-string 2 ?\s))
(concat (if char (concat (char-to-string char) tmm-mid-prompt)
;; Keep them lined up in columns.
(make-string (1+ (length tmm-mid-prompt)) ?\s))
str))
(cdr elt))))))
(defun tmm-clear-self-insert-and-exit ()
"Clear the minibuffer contents then self insert and exit."
(interactive)
(delete-minibuffer-contents)
(self-insert-and-exit))
;; This returns the old map.
(defun tmm-define-keys (minibuffer)
(let ((map (make-sparse-keymap)))
(suppress-keymap map t)
(dolist (c tmm-short-cuts)
(if (listp tmm-shortcut-style)
(define-key map (char-to-string c) 'tmm-shortcut)
;; only one kind of letters are shortcuts, so map both upcase and
;; downcase input to the same
(define-key map (char-to-string (downcase c)) 'tmm-shortcut)
(define-key map (char-to-string (upcase c)) 'tmm-shortcut)))
(when minibuffer
(define-key map [pageup] 'tmm-goto-completions)
(define-key map [prior] 'tmm-goto-completions)
(define-key map "\ev" 'tmm-goto-completions)
(define-key map "\C-n" 'next-history-element)
(define-key map "\C-p" 'previous-history-element)
;; Previous menu shortcut (see `tmm-prompt').
(define-key map "^" 'tmm-clear-self-insert-and-exit))
(prog1 (current-local-map)
(use-local-map (append map (current-local-map))))))
(defun tmm-completion-delete-prompt ()
(with-current-buffer standard-output
(goto-char (point-min))
(let* (;; First candidate: first string with mouse-face
(menu-start-1 (or (and (get-text-property (point) 'mouse-face) (point))
(next-single-char-property-change (point) 'mouse-face)))
;; Second candidate: an inactive menu item with tmm-inactive face
(tps-result (save-excursion
(text-property-search-forward 'face 'tmm-inactive t)))
(menu-start-2 (and tps-result (prop-match-beginning tps-result))))
(or (and (null menu-start-1) (null menu-start-2))
(delete-region (point)
;; Use the smallest position of the two candidates.
(or (and menu-start-1 menu-start-2
(min menu-start-1 menu-start-2))
;; Otherwise use the one that is non-nil.
menu-start-1
menu-start-2))))))
(defun tmm-remove-inactive-mouse-face ()
"Remove the mouse-face property from inactive menu items."
(let ((inhibit-read-only t)
(inactive-string
(concat " " (make-string (length tmm-mid-prompt) ?\-)))
next)
(save-excursion
(goto-char (point-min))
(while (not (eobp))
(setq next (next-single-char-property-change (point) 'mouse-face))
(when (looking-at inactive-string)
Fix usage of remove-text-properties * lisp/allout-widgets.el (allout-decorate-item-icon): * lisp/emacs-lisp/chart.el (chart-goto-xy): * lisp/forms.el (forms--make-format) (forms--make-format-elt-using-text-properties): * lisp/htmlfontify.el (hfy-unmark-trailing-whitespace): * lisp/net/newst-plainview.el (newsticker-hide-entry) (newsticker-show-entry): * lisp/nxml/nxml-mode.el (nxml-cleanup): * lisp/obsolete/longlines.el (longlines-unshow-hard-newlines) (longlines-encode-region): * lisp/org/ob-exp.el (org-babel-exp-process-buffer): * lisp/org/org-agenda.el (org-agenda-show-new-time): * lisp/progmodes/cc-defs.el (c-clear-char-property-with-value-function) (c-clear-char-property-with-value-on-char-function): * lisp/progmodes/ebrowse.el (ebrowse--hide): * lisp/progmodes/gdb-mi.el (gdb-send): * lisp/progmodes/idlw-shell.el (idlwave-retrieve-expression-from-level): * lisp/progmodes/make-mode.el (makefile-fill-paragraph): * lisp/progmodes/prog-mode.el (prettify-symbols--post-command-hook): * lisp/progmodes/ruby-mode.el (ruby-syntax-propertize): * lisp/tmm.el (tmm-remove-inactive-mouse-face): Always pass an explicit plist to remove-text-properties. * lisp/dired.el (dired--unhide): * lisp/facemenu.el (facemenu-add-face): * lisp/htmlfontify.el (hfy-fontify-buffer): * lisp/iimage.el (iimage-mode-buffer): * lisp/image-file.el (image-file-yank-handler): * lisp/progmodes/prog-mode.el (prettify-symbols--compose-symbol): * lisp/textmodes/tex-mode.el (latex-env-before-change): * test/src/undo-tests.el (undo-test0): Use remove-list-of-text-properties in place of remove-text-properties where appropriate.
2019-08-01 15:59:46 +03:00
(remove-text-properties (point) next '(mouse-face nil))
(add-text-properties (point) next '(face tmm-inactive)))
(goto-char next)))
(set-buffer-modified-p nil)))
1995-03-11 03:57:25 +00:00
(defun tmm-add-prompt ()
(unless tmm-c-prompt
(error "No active menu entries"))
(or tmm-completion-prompt
(add-hook 'completion-setup-hook
#'tmm-completion-delete-prompt 'append))
(unwind-protect
(minibuffer-completion-help)
(remove-hook 'completion-setup-hook #'tmm-completion-delete-prompt))
(with-current-buffer "*Completions*"
2011-01-15 12:03:38 -08:00
(tmm-remove-inactive-mouse-face)
(when tmm-completion-prompt
Add code for "preserving" window sizes. * frame.c (frame_windows_min_size): New argument IGNORE. (adjust_frame_size): When called from change_frame_size call frame_windows_min_size with IGNORE Qt so we can ignore size restrictions. * dired.el (dired-pop-to-buffer): Call fit-window-to-buffer with `preserve-size' t. (dired-mark-pop-up): Preserve size of window showing marked files. * electric.el (Electric-pop-up-window): * help.el (resize-temp-buffer-window): Call fit-window-to-buffer with `preserve-size' t. * minibuffer.el (minibuffer-completion-help): Use `resize-temp-buffer-window' instead of `fit-window-to-buffer' (Bug#19355). Preserve size of completions window. * register.el (register-preview): Preserve size of register preview window. * tmm.el (tmm-add-prompt): Call fit-window-to-buffer with `preserve-size' t (Bug#1291). * window.el (with-displayed-buffer-window): Add calls to `window-preserve-size'. (window-min-pixel-size, window--preservable-size) (window-preserve-size, window-preserved-size) (window--preserve-size, window--min-size-ignore-p): New functions. (window-min-size, window-min-delta, window--resizable) (window--resize-this-window, split-window-below) (split-window-right): Amend doc-string. (adjust-window-trailing-edge): Handle preserving window sizes. Signal user-error instead of an error when there's no window above or below. (window--min-size-1, window-sizable, window--size-fixed-1) (window-size-fixed-p, window--min-delta-1) (frame-windows-min-size, window--max-delta-1, window-resize) (window--resize-child-windows, window--resize-siblings) (enlarge-window, shrink-window, split-window): Handle preserving window sizes. (window--state-put-2): Handle horizontal scroll bars. (window--display-buffer): Call `preserve-size' if asked for. (display-buffer): Mention `preserve-size' alist member in doc-string. (fit-window-to-buffer): New argument PRESERVE-SIZE.
2014-12-18 18:12:24 +01:00
(let ((inhibit-read-only t)
(window (get-buffer-window "*Completions*")))
(goto-char (point-min))
(insert
(if tmm-shortcut-inside-entry
(format tmm-completion-prompt
(concat (propertize "highlighted" 'face 'highlight) " character"))
(format tmm-completion-prompt
(concat "character right before '" tmm-mid-prompt "' "))))
Add code for "preserving" window sizes. * frame.c (frame_windows_min_size): New argument IGNORE. (adjust_frame_size): When called from change_frame_size call frame_windows_min_size with IGNORE Qt so we can ignore size restrictions. * dired.el (dired-pop-to-buffer): Call fit-window-to-buffer with `preserve-size' t. (dired-mark-pop-up): Preserve size of window showing marked files. * electric.el (Electric-pop-up-window): * help.el (resize-temp-buffer-window): Call fit-window-to-buffer with `preserve-size' t. * minibuffer.el (minibuffer-completion-help): Use `resize-temp-buffer-window' instead of `fit-window-to-buffer' (Bug#19355). Preserve size of completions window. * register.el (register-preview): Preserve size of register preview window. * tmm.el (tmm-add-prompt): Call fit-window-to-buffer with `preserve-size' t (Bug#1291). * window.el (with-displayed-buffer-window): Add calls to `window-preserve-size'. (window-min-pixel-size, window--preservable-size) (window-preserve-size, window-preserved-size) (window--preserve-size, window--min-size-ignore-p): New functions. (window-min-size, window-min-delta, window--resizable) (window--resize-this-window, split-window-below) (split-window-right): Amend doc-string. (adjust-window-trailing-edge): Handle preserving window sizes. Signal user-error instead of an error when there's no window above or below. (window--min-size-1, window-sizable, window--size-fixed-1) (window-size-fixed-p, window--min-delta-1) (frame-windows-min-size, window--max-delta-1, window-resize) (window--resize-child-windows, window--resize-siblings) (enlarge-window, shrink-window, split-window): Handle preserving window sizes. (window--state-put-2): Handle horizontal scroll bars. (window--display-buffer): Call `preserve-size' if asked for. (display-buffer): Mention `preserve-size' alist member in doc-string. (fit-window-to-buffer): New argument PRESERVE-SIZE.
2014-12-18 18:12:24 +01:00
(when window
;; Try to show everything just inserted and preserve height of
;; *Completions* window. This should fix a behavior described
;; in Bug#1291.
(fit-window-to-buffer window nil nil nil nil t))))))
1995-03-11 03:57:25 +00:00
(defun tmm-shortcut ()
"Choose the shortcut that the user typed."
1995-03-11 03:57:25 +00:00
(interactive)
(let ((c last-command-event) s)
(if (symbolp tmm-shortcut-style)
(setq c (funcall tmm-shortcut-style c)))
(if (memq c tmm-short-cuts)
(if (equal (buffer-name) "*Completions*")
(progn
(goto-char (point-min))
(re-search-forward
(concat "\\(^\\|[ \t]\\)" (char-to-string c) tmm-mid-prompt))
(choose-completion))
;; In minibuffer
(delete-region (minibuffer-prompt-end) (point-max))
(dolist (elt tmm-km-list)
(let ((str (car elt))
(index 0))
(when tmm-shortcut-inside-entry
(if (get-char-property 0 'face str)
(setq index 0)
(let ((next (next-single-char-property-change 0 'face str)))
(setq index (if (= (length str) next) 0 next)))))
(if (= (aref str index) c)
(setq s str))))
(insert s)
(exit-minibuffer)))))
1995-03-11 03:57:25 +00:00
(defun tmm-goto-completions ()
"Jump to the completions buffer."
1995-03-11 03:57:25 +00:00
(interactive)
New customization variable `completion-eager-display' The customization option can be set to t or nil, to respectively always or never show the *Completions* buffer eagerly at the beginning of a completion session. Furthermore the option can be set to the value auto. In this case the *Completions* buffer will only be shown if requested by the completion table. Completion tables can use the `eager-display' completion metadata to do so. (Bug#74616, Bug#74617) * lisp/minibuffer.el (completion-eager-display): New customization variable. (completion-metadata): Update docstring, document the new `eager-display' completion metadata. (completion-extra-properties): Update docstring, document the new `:eager-display' completion metadata. (completion-category-overrides): Add `eager-display' to the custom type specification. (completing-read-default): Handle the `completion-eager-display' customization variable and the `eager-display' completion metadata. (completion-table-with-metadata): New function to create a completion table with metadata. (minibuffer-complete-defaults, minibuffer-complete-history): Use it. * lisp/ffap.el (ffap-menu-ask): Add `ffap-menu' completion category and `eager-display' completion metadata. Use `completion-table-with-metadata'. * lisp/imenu.el (imenu-eager-completion-buffer): Correct docstring, which had been inverted. (imenu--completion-buffer): Add `eager-display' completion metadata. Use `completion-table-with-metadata'. * lisp/tmm.el (tmm-prompt): Add `tmm' completion category and `eager-display' completion metadata. Use `completion-table-with-metadata'. Add keymap setup. (tmm-add-prompt): Remove keymap setup. (tmm-goto-completions): Call `tmm-add-prompt' to ensure that a *Completions* buffer is shown. (tmm--completion-table): Remove unused internal function. * etc/NEWS: Announce the change.
2024-12-08 20:05:07 +01:00
(tmm-add-prompt)
(setq tmm-c-prompt (buffer-substring (minibuffer-prompt-end) (point-max)))
;; Clear minibuffer old contents before using *Completions* buffer for
;; selection.
(delete-minibuffer-contents)
(switch-to-buffer-other-window "*Completions*")
1995-03-11 03:57:25 +00:00
(search-forward tmm-c-prompt)
(search-backward tmm-c-prompt))
(defun tmm-get-keymap (elt &optional in-x-menu)
"Prepend (DOCSTRING EVENT BINDING) to free variable `tmm-km-list'.
1995-03-11 03:57:25 +00:00
The values are deduced from the argument ELT, that should be an
element of keymap, an `x-popup-menu' argument, or an element of
1995-03-11 03:57:25 +00:00
`x-popup-menu' argument (when IN-X-MENU is not-nil).
This function adds the element only if it is not already present.
It uses the free variable `tmm-table-undef' to keep undefined keys."
(let (km str plist filter visible enable (event (car elt)))
1995-03-11 03:57:25 +00:00
(setq elt (cdr elt))
(if (eq elt 'undefined)
(setq tmm-table-undef (cons (cons event nil) tmm-table-undef))
(unless (assoc event tmm-table-undef)
(cond ((or (functionp elt) (keymapp elt))
(setq km elt))
((or (keymapp (cdr-safe elt)) (functionp (cdr-safe elt)))
(setq km (cdr elt))
(and (stringp (car elt)) (setq str (car elt))))
((or (keymapp (cdr-safe (cdr-safe elt)))
(functionp (cdr-safe (cdr-safe elt))))
(setq km (cddr elt))
(and (stringp (car elt)) (setq str (car elt))))
((eq (car-safe elt) 'menu-item)
;; (menu-item TITLE COMMAND KEY ...)
1998-06-14 18:46:20 +00:00
(setq plist (cdr-safe (cdr-safe (cdr-safe elt))))
(when (consp (car-safe plist))
(setq plist (cdr-safe plist)))
(setq km (nth 2 elt))
(setq str (eval (nth 1 elt)))
1998-06-14 18:46:20 +00:00
(setq filter (plist-get plist :filter))
(if filter
(setq km (funcall filter km)))
(setq visible (plist-get plist :visible))
(if visible
(setq km (and (eval visible) km)))
(setq enable (plist-get plist :enable))
(if enable
(setq km (if (eval enable) km 'ignore))))
((or (keymapp (cdr-safe (cdr-safe (cdr-safe elt))))
(functionp (cdr-safe (cdr-safe (cdr-safe elt)))))
; New style of easy-menu
(setq km (cdr (cddr elt)))
(and (stringp (car elt)) (setq str (car elt))))
((stringp event) ; x-popup or x-popup element
(setq str event)
(setq event nil)
(setq km (if (or in-x-menu (stringp (car-safe elt)))
elt (cons 'keymap elt)))))
2011-01-15 12:03:38 -08:00
(unless (or (eq km 'ignore) (null str))
(let ((binding (where-is-internal km nil t)))
(when binding
(setq binding (key-description binding))
;; Try to align the keybindings.
(let* ((window (get-buffer-window "*Completions*"))
(colwidth (min 30 (- (/ (if window
(window-width window)
(frame-width))
2)
10)))
(nspaces (max 2 (- colwidth
(string-width str)
(string-width binding)))))
(setq str
(concat str
(propertize (make-string nspaces ?\s)
'display
(cons 'space (list :width nspaces)))
binding)))))))
1995-03-11 03:57:25 +00:00
(and km (stringp km) (setq str km))
;; Verify that the command is enabled;
;; if not, don't mention it.
(when (and km (symbolp km) (get km 'menu-enable))
(setq km (if (eval (get km 'menu-enable)) km 'ignore)))
1995-03-11 03:57:25 +00:00
(and km str
(or (assoc str tmm-km-list)
(push (cons str (cons event km)) tmm-km-list))))))
1995-03-11 03:57:25 +00:00
(provide 'tmm)
;;; tmm.el ends here