bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#57163: completing-read not allow cycling of the options by default


From: Jean Louis
Subject: bug#57163: completing-read not allow cycling of the options by default
Date: Tue, 16 Aug 2022 08:24:21 +0300
User-agent: Mutt/+ () (2022-06-11)

* uzibalqa via "Bug reports for GNU Emacs, the Swiss army knife of text editors 
<bug-gnu-emacs@gnu.org> [2022-08-14 19:36]:
> Completion is defined as a feature that fills in the rest of a name
> starting from an abbreviation for it.  Easily leads to confusion
> because one does not commonly associate completion with next
> selection element.

That is why I said that misunderstood words are one of main obstacles
in learning. We have computer terminology, we have English, then other
languages, and then Emacs terminology, and there may be similar
words. We have to be careful to find the right definition of a word in
a right context.

Recommended place in maniual is:

(info "(elisp) Completion")

21.6 Completion
===============

“Completion” is a feature that fills in the rest of a name starting from
an abbreviation for it.  Completion works by comparing the user’s input
against a list of valid names and determining how much of the name is
determined uniquely by what the user has typed.  For example, when you
type ‘C-x b’ (‘switch-to-buffer’) and then type the first few letters of
the name of the buffer to which you wish to switch, and then type <TAB>
(‘minibuffer-complete’), Emacs extends the name as far as it can.

   Standard Emacs commands offer completion for names of symbols, files,
buffers, and processes; with the functions in this section, you can
implement completion for other kinds of names.

   The ‘try-completion’ function is the basic primitive for completion:
it returns the longest determined completion of a given initial string,
with a given set of strings to match against.

   The function ‘completing-read’ provides a higher-level interface for
completion.  A call to ‘completing-read’ specifies how to determine the
list of valid names.  The function then activates the minibuffer with a
local keymap that binds a few keys to commands useful for completion.
Other functions provide convenient simple interfaces for reading certain
kinds of names with completion.

> Have looked at "Variable: minibuffer-local-map" which states that it
> is the default local keymap for reading from the minibuffer. By
> default, it makes the following bindings:
> 
> But that list is not complete because it associates M-n and M-p only
> with history elements.

That is right. History elements do not represent completion
candidates.

IMPORTANT: history elements may be different than completion
candidates. You may come into situation that by choosing a history
element you are not able to choose the true completion candidate, and
by attempting to choose a history element you may not even be able to
accept the candidate because they may be different.

M-p runs the command previous-history-element (found in
minibuffer-local-must-match-map), which is an interactive
byte-compiled Lisp function in ‘simple.el’.

(previous-history-element N)

Puts previous element of the minibuffer history in the minibuffer.
With argument N, it uses the Nth previous element.

Example from real life:

In my personal work and research I am using Hyperscope as database
backed note taking tool. Each note has its name. 

- my completion candidates are automatically choosen from database,
  there are for example note names, such as "My note 1", "My note 2"

- imagine I am doing completion and choose "My note 1", that one
  remains in history.

- Then maybe I rename "My note 1" to "August 2022 Notes"

- Then again I use completion, but it is using history elements, so
  M-n and M-p will rather show me "My note 1" even though it is not
  one of completion candidates any more.

I also understand that some of suggestions for completion candidates
on the mailing list, maybe on GNU Emacs Help, was to use M-n or M-p
but please remember, those are for history elements.

To make history elements more relevant to your completion candidates
you should use history variables.

When there are many various applications of completions it becomes
boring to always define a new history variable and take care of it.

For that reason I have choosen to generate such variables
automatically based on the prompt. If prompt is unique and relevant,
the history variable will be unique and relevant.

Here is the function that I use to generate history variable automatically:

(defun rcd-symbol-if-not-exist (variable &optional value description)
  "Return symbol for VARIABLE string. 

It will generate new VARIABLE if it does not exist."
  (let* ((variable (replace-regexp-in-string "[^[:alnum:]]" "-" (downcase 
variable)))
         (rcd-symbol (intern variable))
         (description (or description (format "Generated variable `%s'" 
variable))))
    (if (boundp rcd-symbol)
        rcd-symbol
      (eval (list 'defvar rcd-symbol value description)))))

(rcd-symbol-if-not-exist "Enter name of person: ") ⇒ enter-name-of-person--

Thus history variable becomes `enter-name-of-person--' for the prompt "Enter 
name of person: ".

Then I have a higher level function that uses `completing-read'
function and automatically generates history variables:

(defun rcd-choose (list &optional prompt predicate initial-input def)
  "Ask user for LIST of choices.
If only one element, function `y-or-n-p' will be used.
For multiple elements `completing-read' is used.

If nothing chosen it will return empty string."
  (let* ((completion-ignore-case t)
         (prompt (or prompt "Choose: "))
         (description (format "History for `%s' completion prompt." prompt))
         (history (rcd-symbol-if-not-exist (concat "rcd-" prompt "-history") 
nil description))
         (input (cond ((length= list 1) (if (y-or-n-p (nth 0 list)) (nth 0 
list) ""))
                      (t (rcd-repeat-until-not-empty-string 'completing-read 
prompt list predicate t initial-input history def t)))))
    input))

Then I can simply say:

(rcd-choose '("One" "Two" "Three")) and I am not using any prompt there. It 
will be automatically "Choose: ". That will generate history variable for the 
prompt "Choose: " and hold various history elements.

But if I am using a prompt:
(rcd-choose '("One" "Two" "Three") "Choose a number: ")

then such prompt"Choose a number: " will automatically result with history 
variable generated for
me, and it will hold those specific elements for that specific
prompt.

That is the way how I completely forget about defining history
variables but I still have them for each and everything.

Helper function to repeat a function until it gives non empty string:

(defun rcd-repeat-until-not-empty-string (function &rest args)
  "Repeat FUNCTION with optional ARGS until result is not empty string."
  (let ((result))
    (while (string-empty-p (setq result (apply function args))))
      result))

Back to "completion cycling":

I use TAB to view completion candidates if necessary and then I start
typing one of them.

If I know any string inside of a completion, I may start typing it
with the wildcard:

Choose: *eth and then by pressing TAB I can see those candidates
matchin *eth which comes very handy to choose the right one.

My completion candidates are dynamically changed and there are many,
often there may be 70,000 candidates.

For you I recomend using some add-on packages such as `ivy-mode' as
that one may visually show you completion candidates and instead of
history elements you may use M-n and M-p to cycle through completion
candidates instead through history elements.

My personal work tells me that I everything works faster and more
efficient by using built-in Emacs completion without add-on packages,
as I have extensive numbers of candidates where the wildcard method
works better for me.

-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/





reply via email to

[Prev in Thread] Current Thread [Next in Thread]