如何编写一个简单的“完成点函数”功能?


9

我正在考虑编写一种用于编辑Magic的主要模式:Gathering卡座。

大部分看起来很简单,但是我有一个问题。大约有15,000张独特的魔术卡(即具有唯一名称的卡)。我希望能够通过编写点完成函数来完成对它们的操作。我一直在寻找一个简单的capf函数的基本示例,该函数仅针对一组单词即可完成,以作为我的模式的基础,但到目前为止却找不到任何东西。您知道有什么很好的例子可以开始吗?并且您认为获得良好的性能还是容易的,还是我必须编写自己的数据结构(也许我想像的是Trie)。

显然,我需要找到一种与新卡等进行同步的方法,将来也许甚至可以通过除卡名之外的其他特征来搜索卡,但可以等待。

Answers:


17

文献资料

API完成点功能可以在以下文档中找到 completion-at-point-functions

依次调用此钩子上的每个函数,不带任何参数,并且应返回nil表示不适用于该点,或者返回不带参数的函数来执行完成(不建议使用),或者返回形式列表(START END COLLECTION) 。(PROPS),其中START和END界定要完成的实体,并应包含点,COLLECTION是用于完成它的完成表,而PROPS是其他信息的属性列表。

startend而且props很明显,但是我认为的格式collection定义不正确。为此,您可以查看try-completion或的文档all-completions

如果COLLECTION是清单,则键(元素的车)可能是补全。如果元素不是约束单元,则元素本身就是可能的补全。如果COLLECTION是哈希表,则所有字符串或符号键都是可能的补全。如果COLLECTION是一个obarray,则obarray中所有符号的名称都是可能的补全。

COLLECTION也可以是完成本身的功能。它接收三个参数:值STRING,PREDICATE和nil。无论返回什么,都将成为“ try-completion”的值。

以下是点函数完成的简单示例,该函数使用中定义的单词/etc/dictionaries-common/words来完成缓冲区中的单词

(defvar words (split-string (with-temp-buffer
                              (insert-file-contents-literally "/etc/dictionaries-common/words")
                              (buffer-string))
                            "\n"))

(defun words-completion-at-point ()
  (let ((bounds (bounds-of-thing-at-point 'word)))
    (when bounds
      (list (car bounds)
            (cdr bounds)
            words
            :exclusive 'no
            :company-docsig #'identity
            :company-doc-buffer (lambda (cand)
                                  (company-doc-buffer (format "'%s' is defined in '/etc/dictionaries-common/words'" cand)))
            :company-location (lambda (cand)
                                (with-current-buffer (find-file-noselect "/etc/dictionaries-common/words")
                                  (goto-char (point-min))
                                  (cons (current-buffer) (search-forward cand nil t))))))))

补全功能会在某个位置查找单词(使用库thingatpt来查找单词的边界),并针对/etc/dictionaries-common/words文件中的单词来完成该功能,该属性:exclusive设置为,no以便在我们失败时emacs可以使用其他capf函数。最后,设置一些其他属性以增强公司模式集成。

性能

我系统上的word文件有99171个条目,而emacs能够完整地完成它们,所以我想15000个条目应该不是问题。

与公司模式整合

公司模式与completion-at-point-functions使用company-capf后端很好地集成在一起,因此它应该为您方便地使用,但是您可以通过返回propscapf函数结果中的其他内容来增强公司提供的完成功能。目前支持的道具是

:company-doc-buffer -公司用于显示当前候选人的元数据

:company-docsig -由公司用于回传有关迷你缓冲区中候选人的元数据

:company-location -公司用于跳转到当前候选人的位置


天啊!感谢您的彻底回答!我会尝试一下,然后接受。特别感谢公司的提示(我实际上正在使用)。
Mattias Bengtsson

谢谢,这真的很有帮助,现在我可以轻松配置自定义
补全了

很高兴我可以提供帮助:)
Iqbal Ansari

0

@Iqbal Ansari给出了一个很好的答案。这是一个补充性的答案,希望对您有所帮助。

这是使用emacs经典完成机制2009的实现。

;; this is your lang's keywords
(setq xyz-kwdList
      '("touch"
       "touch_start"
       "touch_end"
       "for"
       "foreach"
       "forall"
       ))

以下是完成代码。

(defun xyz-complete-symbol ()
  "Perform keyword completion on word before cursor."
  (interactive)
  (let ((posEnd (point))
        (meat (thing-at-point 'symbol))
        maxMatchResult)

    ;; when nil, set it to empty string, so user can see all lang's keywords.
    ;; if not done, try-completion on nil result lisp error.
    (when (not meat) (setq meat ""))
    (setq maxMatchResult (try-completion meat xyz-kwdList))

    (cond ((eq maxMatchResult t))
          ((null maxMatchResult)
           (message "Can't find completion for “%s”" meat)
           (ding))
          ((not (string= meat maxMatchResult))
           (delete-region (- posEnd (length meat)) posEnd)
           (insert maxMatchResult))
          (t (message "Making completion list…")
             (with-output-to-temp-buffer "*Completions*"
               (display-completion-list 
                (all-completions meat xyz-kwdList)
                meat))
             (message "Making completion list…%s" "done")))))

以下是使用ido-mode接口的实现。简单得多。

(defun abc-complete-symbol ()
  "Perform keyword completion on current symbol.
This uses `ido-mode' user interface for completion."
  (interactive)
  (let* (
         (bds (bounds-of-thing-at-point 'symbol))
         (p1 (car bds))
         (p2 (cdr bds))
         (current-sym
          (if  (or (null p1) (null p2) (equal p1 p2))
              ""
            (buffer-substring-no-properties p1 p2)))
         result-sym)
    (when (not current-sym) (setq current-sym ""))
    (setq result-sym
          (ido-completing-read "" xyz-kwdList nil nil current-sym ))
    (delete-region p1 p2)
    (insert result-sym)))

您需要将xyz-kwdList定义为单词列表。


2
-1用于以更差的方式重新构造完成界面,null反复not使用仅在您自己的模式下才有意义的驼峰式标识符和希腊符号。
wasamasa

3
-1未回答completion-at-point-functions与之有关的问题(我与@wasamasa不同意nullvs的not问题)。
npostavs 2015年

3
@XahLee中的函数completion-at-point-functions应该返回完成数据,而不是自己执行完成。因此,答案中的功能不能用作中的条目completion-at-point-functions
npostavs

1
@npostavs啊,我明白了。你是对的。谢谢!
Xah Lee 2015年

4
@npostavs这种功能仍然可以使用,但是确实以这种方式编写完成功能违反了已记录的接口,因此强烈建议不要这样做。
德米特里(Dmitry)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.