unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* Choosing interactively from a list
@ 2014-12-07  2:58 Florian v. Savigny
  2014-12-07  3:33 ` John Mastro
  0 siblings, 1 reply; 7+ messages in thread
From: Florian v. Savigny @ 2014-12-07  2:58 UTC (permalink / raw)
  To: help-gnu-emacs


Hi there everybody,

I would like to do something which seemed easy to me at first glance,
but is now proving mysteriously difficult:

I have a list, say ("A" "B" "C" "D" ... "Z" "a" "b" "c" "d"
... "z"). I also have an index, say 13. I would like to choose an item
from this list in the minibuffer, and be able to go forward and
backwards in this list, starting from the index, i.e. here, 13.

In other words, if the list goes on alphabetically as hinted above, the
element with the index 13 would be the string "N". I would like to
have "N" as the initial input in the minibuffer, and I would like to
go back (i.e. "M", "L", "K" - you name it) with some key and forth
(i.e. "O", "P", "Q" and so on).

I tried to do this with the usual minibuffer functions, and it almost
works, but not completely as I would like it:

(defun choose-from-list (list &optional index)
  "Choose an item from LIST in the minibuffer.
Use a copy of LIST as history list, i.e. do not modify LIST.
Optional arg INDEX means start in the list at index INDEX."
(let ((reverse-list (reverse list))
      (reverse-ind (- (length list) index))
      (history-length t)) 
  (read-from-minibuffer "Choose: "
			(nth index list)
			nil
			nil
			(cons 'reverse-list reverse-ind))))

(setq list
      (list "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
	    "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"))

(choose-from-list list 13)

This does exactly what I want, i.e. hitting M-p gets me one item back
in the list; M-n gets me one item forward. However, I would like to
require that the user (me) cannot change the value from the list, only
pick it. Thus, I have tried completing-read instead of
read-from-minibuffer, because completing-read has REQUIRE-MATCH:

(defun choose-from-list-cmplr (list &optional index)
  "Choose an item from LIST in the minibuffer.
Use a copy of LIST as history list, i.e. do not modify LIST.
Optional arg INDEX means start in the list at index INDEX."
(let ((reverse-list (reverse list))
      (reverse-ind (- (length list) index))
      (history-length t)) 
  (completing-read "Choose: " list
		   nil
		   t
		   (nth index list)
		   (cons 'reverse-list reverse-ind))))


I imagine this should be the same thing as regards the minibuffer
history, but here, the history cycling is somehow different: Although
I get the same list element as initial input, hitting M-n now gives me
the item at the *beginning* of the list ("A"), M-p gives me the item
at the *end*.

Can somebody explain that to me? An important aspect might be that I
am not really looking for completion, but rather rigid cycling through
a fixed list. And the whole approach, i.e. using the history for
something that is not really a history (and is not even supposed to be
modified like a history variable is), reversing it etc, feels very
roundabout and not as it should be.

Many thanks in advance!

Best regards,

Florian

-- 

Florian von Savigny
Melanchthonstr. 41
33615 Bielefeld



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Choosing interactively from a list
  2014-12-07  2:58 Choosing interactively from a list Florian v. Savigny
@ 2014-12-07  3:33 ` John Mastro
  2014-12-07 10:56   ` Choosing interactively from a list (starting off at any position) Florian v. Savigny
  0 siblings, 1 reply; 7+ messages in thread
From: John Mastro @ 2014-12-07  3:33 UTC (permalink / raw)
  To: help-gnu-emacs@gnu.org

Hi,

Florian v. Savigny <florian@fsavigny.de> wrote:
> I have a list, say ("A" "B" "C" "D" ... "Z" "a" "b" "c" "d"
> ... "z"). I also have an index, say 13. I would like to choose an item
> from this list in the minibuffer, and be able to go forward and
> backwards in this list, starting from the index, i.e. here, 13.

I don't know a way off-hand to do that without constructing a modified
version of the list (though I won't be surprised if someone chimes in
with one).

As an alternative, does this do something like what you're looking for?

    (defun rotate-to-index (list index)
      (append (cl-subseq list index)
              (cl-subseq list 0 index)))


    (defun choose-from-list-cmplr (list &optional index)
      (completing-read "Choose: "
                       (if index (rotate-to-index list index) list)
                       nil
                       t))

--
john



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Choosing interactively from a list (starting off at any position)
  2014-12-07  3:33 ` John Mastro
@ 2014-12-07 10:56   ` Florian v. Savigny
       [not found]     ` <CAOj2CQQ45gZpmuQUsMNp=iokkbB1Wz2cWpy6ZKfZ=BzyoSY6xg@mail.gmail.com>
  0 siblings, 1 reply; 7+ messages in thread
From: Florian v. Savigny @ 2014-12-07 10:56 UTC (permalink / raw)
  To: John Mastro; +Cc: help-gnu-emacs


Hi John,

thanks for your ideas!

  > As an alternative, does this do something like what you're looking for?
  > 
  >     (defun rotate-to-index (list index)
  >       (append (cl-subseq list index)
  >               (cl-subseq list 0 index)))
  > 
  > 
  >     (defun choose-from-list-cmplr (list &optional index)
  >       (completing-read "Choose: "
  >                        (if index (rotate-to-index list index) list)
  >                        nil
  >                        t))


Yes, this does work, but only forwards, not backwards. I would like to
go forwards with M-n and backwards (i.e. to the (index - 1)th element
of list) with M-p.

(It's interesting, BTW, that completing-read accepts an anonymous list
instead of a list variable name. It cannot possibly modify this
"history", can it?)

The practical context is that I have a long, long file which contains
a lot of dates in chronological order, some of which are usually past,
one perhaps today's date, and the rest is in the future. I would like
to devise a convenient and orderly method of jumping to any of these
dates, starting off at the most current date, i.e. either today's or
next. (It is actually much like moving back and forth in a calendar or
diary.)

I have written all of that, and with read-from-minibuffer, it works
fine, so there is no pressing need to solve it. (That the user can
enter non-existant dates is not a practical problem because I am the
user, and I know better.) I have just become really curious about why
the two functions seem to work differently with respect to the
minibuffer history.

On a more fundamental note, it has made me start wondering if
minibuffer completion and history might be worth supplementing with
further kinds of user input methods. (Because the minibuffer stuff is
really just a hack; that's not what histories are there for.)

In the problem I am working on, the ever-available completion is very
unhelpful - simply not the natural method of choosing -, because the
dates all start with one of just one, two or three different weekdays,
followed by the day of the month (still not unique). But whether the
date is one, two positions before or after today is almost always
relevant, because I am usually interested in the dates around today.

As Lisp is a list-processing language, it seems to me that an input
method which works like that should come easy to Emacs, and that
somebody might already have written something as basic as that. Does
anybody know of anything ... ?

Best regards!

Florian

-- 

Florian von Savigny
Melanchthonstr. 41
33615 Bielefeld



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Fwd: Choosing interactively from a list (starting off at any position)
       [not found]     ` <CAOj2CQQ45gZpmuQUsMNp=iokkbB1Wz2cWpy6ZKfZ=BzyoSY6xg@mail.gmail.com>
@ 2014-12-08 19:19       ` John Mastro
  2014-12-08 22:51         ` Florian v. Savigny
       [not found]         ` <<87oardah6y.fsf@bertrandrussell.Speedport_W_723V_1_36_000>
  0 siblings, 2 replies; 7+ messages in thread
From: John Mastro @ 2014-12-08 19:19 UTC (permalink / raw)
  To: help-gnu-emacs@gnu.org

Sigh, forgot to include the list when sending the below.

Florian v. Savigny <florian@fsavigny.de> wrote:
> Yes, this does work, but only forwards, not backwards. I would like to
> go forwards with M-n and backwards (i.e. to the (index - 1)th element
> of list) with M-p.

Ah, indeed. It only appeared to work because of the completion packages
I'm using (see below).

> (It's interesting, BTW, that completing-read accepts an anonymous list
> instead of a list variable name. It cannot possibly modify this
> "history", can it?)

Indeed, the history needs to be something it can modify. But it won't
modify the list of choices. So, how about this?

    (defvar choose-from-list-history nil)

    (defun choose-from-list-cmplr (list &optional index)
      (setq choose-from-list-history list)
      (completing-read "Choose: "
                       list
                       nil
                       t
                       (nth index list)
                       (cons 'choose-from-list-history index)))

> In the problem I am working on, the ever-available completion is very
> unhelpful - simply not the natural method of choosing -, because the
> dates all start with one of just one, two or three different weekdays,
> followed by the day of the month (still not unique). But whether the
> date is one, two positions before or after today is almost always
> relevant, because I am usually interested in the dates around today.

Have you tried `ido' and the related packages out there? I'm using
`ido', `ido-ubiquitous', `flx-ido', and `ido-vertical-mode'. I find it
quite helpful even in situations like you describe, since you can type
just the part(s) that are likely to matter.

-- 
john



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Fwd: Choosing interactively from a list (starting off at any position)
  2014-12-08 19:19       ` Fwd: " John Mastro
@ 2014-12-08 22:51         ` Florian v. Savigny
       [not found]         ` <<87oardah6y.fsf@bertrandrussell.Speedport_W_723V_1_36_000>
  1 sibling, 0 replies; 7+ messages in thread
From: Florian v. Savigny @ 2014-12-08 22:51 UTC (permalink / raw)
  To: John Mastro; +Cc: help-gnu-emacs



Hi John,


  > Indeed, the history needs to be something it can modify. But it won't
  > modify the list of choices. So, how about this?
  > 
  >     (defvar choose-from-list-history nil)
  > 
  >     (defun choose-from-list-cmplr (list &optional index)
  >       (setq choose-from-list-history list)
  >       (completing-read "Choose: "
  >                        list
  >                        nil
  >                        t
  >                        (nth index list)
  >                        (cons 'choose-from-list-history index)))

This comes indeed closer, although - can you explain why? Did it have
to do with the history variable???? (I actually had not made any such
connection myself.)

I changed two aspects:

(defun choose-from-list-cmplr (list &optional index)
  (setq choose-from-list-history (reverse list))
  ;;                             ^^^^^^^^
  (completing-read "Choose: "
		   list
		   nil
		   t
		   (nth index list)
		   (cons 'choose-from-list-history (1- index))))
  ;;                                               ^^^

because without the reverse, M-n and M-p work counter-intuitively, and
the 1- because the index that completing-read uses in the history is
1-based, not 0-based, like in lists. (But then, why did I subtract 1,
rather than add 1?)

  > Have you tried `ido' and the related packages out there? I'm using
  > `ido', `ido-ubiquitous', `flx-ido', and `ido-vertical-mode'. I find it
  > quite helpful even in situations like you describe, since you can type
  > just the part(s) that are likely to matter.

No, I haven't, but I use icicles, which provides a gazillion methods
of doing completion with less keystrokes. (I have understood one or
two of them so far.) I am not sure if ido is basically different.

But my point is that I do not want to type ANY part of the date I am
looking for; rather, I want to choose according to a logic of "it's
before the date offered" and "it's after the date offered". Or
perhaps, "I want the first date" or "I want the last date". The parts
of dates are not like the strings you usually look for, but, apart
from numbers you can easily get wrong, weekdays which occur in many of
the dates. Thus, although each date is unique, this uniqueness is very
difficult to spot for a human because identical parts are only mixed
differently. (Spelled-out months would make choosing easier, but the
usual German date format uses the numbers 1 to 12 for them.) And a
helpful feature they DO have, in contrast, is a strict (chronlogical)
ORDER.

But your solution works perfectly - thanks a lot for your ideas!! I
would still like to understand why it works, though. ;-)

-- 

Florian von Savigny
Melanchthonstr. 41
33615 Bielefeld



^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: Fwd: Choosing interactively from a list (starting off at any position)
       [not found]         ` <<87oardah6y.fsf@bertrandrussell.Speedport_W_723V_1_36_000>
@ 2014-12-09  2:20           ` Drew Adams
  2014-12-09 19:52             ` John Mastro
  0 siblings, 1 reply; 7+ messages in thread
From: Drew Adams @ 2014-12-09  2:20 UTC (permalink / raw)
  To: Florian v. Savigny, John Mastro; +Cc: help-gnu-emacs

> But your solution works perfectly - thanks a lot for your ideas!! I
> would still like to understand why it works, though. ;-)

It works for the reason you conjectured: you are supplying the same
list for the completion candidates and for the history.  And as you
mentioned, the history should be a variable (a symbol), in this case
`choose-from-list-history'.  There's nothing else to understand.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Fwd: Choosing interactively from a list (starting off at any position)
  2014-12-09  2:20           ` Drew Adams
@ 2014-12-09 19:52             ` John Mastro
  0 siblings, 0 replies; 7+ messages in thread
From: John Mastro @ 2014-12-09 19:52 UTC (permalink / raw)
  To: help-gnu-emacs@gnu.org, Drew Adams, Florian v. Savigny

Drew Adams <drew.adams@oracle.com> wrote:
>> But your solution works perfectly - thanks a lot for your ideas!! I
>> would still like to understand why it works, though. ;-)
>
> It works for the reason you conjectured: you are supplying the same
> list for the completion candidates and for the history.  And as you
> mentioned, the history should be a variable (a symbol), in this case
> `choose-from-list-history'.  There's nothing else to understand.

But (info "(elisp) Variable Scoping") may be of interest.

-- 
john



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-12-09 19:52 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-07  2:58 Choosing interactively from a list Florian v. Savigny
2014-12-07  3:33 ` John Mastro
2014-12-07 10:56   ` Choosing interactively from a list (starting off at any position) Florian v. Savigny
     [not found]     ` <CAOj2CQQ45gZpmuQUsMNp=iokkbB1Wz2cWpy6ZKfZ=BzyoSY6xg@mail.gmail.com>
2014-12-08 19:19       ` Fwd: " John Mastro
2014-12-08 22:51         ` Florian v. Savigny
     [not found]         ` <<87oardah6y.fsf@bertrandrussell.Speedport_W_723V_1_36_000>
2014-12-09  2:20           ` Drew Adams
2014-12-09 19:52             ` John Mastro

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).