【问题标题】:How to return the value instead of key by completing-read如何通过完成读取返回值而不是键
【发布时间】:2016-02-14 10:29:33
【问题描述】:
(completing-read
 "Complete a foo: "
 '(("foobar1" "~/foobar1/") ("barfoo" "/usr/barfoo/") ("foobaz" "/hello/")))

如上所示,我想提示输入"foobar1""barfoo""foobaz",但返回的是配对目录。

Moverover,如果我有这样的哈希表

(cl-defstruct person ID name)
(setq person-object (make-person :ID 123 :name "foo"))
(setq person-table (make-hash-table))
(pushash (person-ID person-object) person-object person-table)

如何提示输入人员姓名但获得人员 ID 作为回报?

【问题讨论】:

    标签: emacs lisp elisp completion


    【解决方案1】:

    没有办法让completing-read返回值而不是键,所以你必须自己进行查找:

    (let ((completions '(("foobar1" "~/foobar1/") ("barfoo" "/usr/barfoo/") ("foobaz" "/hello/"))))
      (cadr (assoc (completing-read "Complete a foo: " completions) completions)))
    

    对于哈希表,由于名称不是键,您需要遍历哈希表中的每个对象才能找到它,使用maphash。由于在找到所需内容后继续迭代会很浪费,因此您可以使用 catchthrow,如下所示:

    (catch 'found-it
      (maphash
       (lambda (key value)
         (when (equal (person-name value) desired-name)
           (throw 'found-it key)))
       person-table))
    

    这将返回人员 ID,如果没有名称等于 desired-name 的人员,则返回 nil

    【讨论】:

      【解决方案2】:

      @legoscia 提供了一个很好的答案:completing-read 确实 让您访问与它用于完成的键关联的值。例如,对于 alist COLLECTION 参数,它不会让您访问所选 alist 键的 cdr。

      对于 alist,您可以使用 assoc 来获取 first 匹配 alist 元素,对于哈希表,您可以使用 maphash 或执行 get。

      但是这些方法排除了获取与特定选择的键出现相关联的特定值当有 重复 key的,即当多个候选人有相同的key时,或者名字。

      您无法获得第 2 个匹配元素或第 13 个。事实上,vanilla Emacs completing-read 消除了具有相同键(名称)的完成候选者的重复。对于普通 Emacs,alist 条目的 cdr 中的任何信息都被浪费了。为方便起见,您可以使用 alist,如果您已经有一个,但如果没有,那么您最好只使用名称列表(字符串或符号),而不是 conses。

      如果您使用Icicles,则不会浪费 alist 条目。检索 cdr 值没有问题。在completing-read 完成后,您可以轻松获得所选候选人的完整信息。

      Icicles 通过使用属性化字符串作为候选,并通过增强completing-read 来实现这一点,以便它可以返回用户选择的完整字符串、属性和所有内容。您可以从返回的属性化字符串中恢复完整的 alist 条目。

      什么时候重要 能够拥有和使用具有不同关联值的重复键?如果它们是重复的,用户如何区分它们(例如,*Completions*)?

      例子:

      • 具有相同名称但用于不同目标的书签 - 例如,用于不同目录中具有相同相对名称的不同文件。

      • 缓冲区中与模式匹配或包含标记的行或其他文本。这包括Icicles search 中的匹配项,您可以在其中以任何您喜欢的方式定义搜索上下文(不仅仅是行)。它还包括缓冲区(包括限制,也就是狭窄)和缓冲区位置(标记)。

      • 具有相同文本但注释不同的候选人。 (用户输入与*Completions* 中显示的注释不匹配。)

      • 具有相同名称的 Imenu 项,例如,具有相同名称的对象(例如函数)的多个定义。

      • 具有相同名称的标记项(例如函数)。

      • 可以具有相同名称的其他 Lisp 对象(例如框架)的候选对象。

      Icicles中,用户如何从多个同名的补全候选中选择一个?

      • 用户可以控制候选人的顺序(排序),包括动态更改顺序。 *Completions* 按特定顺序向您显示它们。您可以在候选人之间循环或直接选择其中任何一个。你不限于匹配、选择。 (对于重复的候选人,匹配可能不足以让您只找到其中​​一个。)

      • *Completions* 还可以向您显示有关候选人的其他信息,即使他们具有相同的姓名/文本,也可以区分他们。此类信息可能是周围的文本(如果候选匹配缓冲区文本)或候选元数据(例如文件或书签属性)。

      • 您还可以在模式行中查看有关当前候选者(例如在骑行期间)的重要附加信息。

      • 您可以按一个键按需获取有关当前候选人的更多信息(完整的*Help*)。

      你需要做什么,才能在你自己的代码中利用这个 Icicles 功能

      请参阅Defining Tripping Commands,了解如何定义您自己的命令,让用户在(探索)可能具有相关位置或其他导航信息的候选者之间穿行。 (有关预定义的 Icicles 触发命令,请参阅 Tripping。)

      简要概述在您的命令中执行的操作:

      1. 将变量icicle-whole-candidate-as-text-prop-p绑定到非nil

      2. 将变量 icicle-candidates-alist 设置为您传递给 completing-read 的 alist。这具有将整个对应的原始 alist 条目编码为候选显示字符串上的文本属性的效果。

      3. 在调用completing-read 后使用icicle-get-alist-candidate,恢复用户选择的候选者的完整信息,即完整的alist 元素,包括cdr。

      (另见:Note to programmers using Icicles。)

      【讨论】:

      • @legoscia 提供我需要的所有信息。但是,我选择这个答案是因为它提醒我重复问题。
      猜你喜欢
      • 2020-11-01
      • 2016-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-23
      • 1970-01-01
      • 2015-11-20
      • 1970-01-01
      相关资源
      最近更新 更多