Как мне написать простую функцию «завершение в точке»?


9

Я подумываю написать основной режим для редактирования Magic: сбор колоды.

Большая часть этого кажется довольно простой, но у меня есть один вопрос. Доступно около 15 000 уникальных карт Magic (карты с уникальными именами). Я хотел бы иметь возможность завершить против них, написав функцию завершения в точке. Я искал какой-то простой, базовый пример функции capf, которая просто завершает набор слов, на котором основан мой режим, но до сих пор не нашла ничего. Вы знаете какой-нибудь хороший пример для этого, чтобы начать? И вы верите, что было бы легко получить хорошую производительность, или мне пришлось бы написать свою собственную структуру данных (я думаю, что, может быть, Trie).

Очевидно, мне нужно будет найти способ синхронизации с новыми карточками и т. Д., И в будущем, возможно, я даже смогу искать карточки по другим характеристикам, а не только по названию карточки, но это может подождать.

Ответы:


17

Документация

Функция завершения API в точке может быть найдена в документации completion-at-point-functions

Каждая функция в этом хуке вызывается по очереди без какого-либо аргумента и должна возвращать либо ноль, чтобы означать, что она не применима в данный момент, либо функцию без аргумента для выполнения завершения (не рекомендуется), или список формы (START END COLLECTION . PROPS), где START и END разграничивают объект для завершения и должны включать точку, COLLECTION - это таблица завершения, которую нужно использовать для ее завершения, а PROPS - это список свойств для дополнительной информации.

start, endИ propsочевидны, но я думаю , что формат collectionне определен правильно. Для этого вы можете увидеть документацию try-completionилиall-completions

Если COLLECTION - это список, ключи (машины элементов) являются возможными дополнениями. Если элемент не является cons-ячейкой, то сам элемент является возможным завершением. Если COLLECTION является хеш-таблицей, все ключи, которые являются строками или символами, являются возможными дополнениями. Если COLLECTION является obarray, имена всех символов в obarray являются возможными дополнениями.

COLLECTION также может быть функцией для выполнения самого завершения. Он получает три аргумента: значения STRING, PREDICATE и nil. Все, что он возвращает, становится значением `try-complete '.

пример

Ниже приведен простой пример функции завершения в точке, которая использует слова, определенные в /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 в случае сбоя. Наконец, некоторые дополнительные свойства установлены для улучшения интеграции в режиме компании.

Представление

Файл слов в моей системе содержал 99171 записей, и emacs смог завершить их без каких-либо проблем, поэтому я думаю, 15000 записей не должно быть проблемой.

Интеграция с режимом компании

Режим компании очень хорошо интегрируется с completion-at-point-functionsиспользованием company-capfбэкэнда, поэтому он должен работать «из коробки» для вас, но вы можете улучшить дополнения, предлагаемые компанией, возвращая дополнительные propsв результате функции capf. В настоящее время поддерживаются реквизиты

:company-doc-buffer - Используется компанией для отображения метаданных для текущего кандидата

:company-docsig - Используется компанией для вывода метаданных о кандидате в минибуфер

:company-location - Используется компанией для перехода к местоположению текущего кандидата


Боже мой! Спасибо за подробный ответ! Я попробую это немного и приму после этого. Дополнительное спасибо за подсказки Компании (которые я фактически использую).
Маттиас Бенгтссон

Спасибо, это действительно полезно, теперь я могу легко настраивать пользовательские дополнения :)
clemera

Рад, что смог помочь :)
Икбал Ансари

0

@Икбал Ансари дал отличный ответ. Вот дополнительный ответ, надеюсь, это поможет.

Вот реализация, использующая классический механизм завершения 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и используя camelcased идентификаторов и греческие символы , которые только имеют смысл в ваших собственных режимах.
Васамаса

3
-1 за то, что не ответил на вопрос, который был о completion-at-point-functions(я не согласен с @wasamasa насчет вещи nullпротив not).
npostavs

3
@XahLee Функции в completion-at-point-functionsдолжны возвращать данные завершения, а не выполнять их самостоятельно. Таким образом, функции в вашем ответе не могут использоваться как записи в completion-at-point-functions.
npostavs

1
@npostavs ах, я вижу. вы правы. Спасибо!
Xah Lee

4
@npostavs Этот тип функции все еще будет работать, но на самом деле написание функции завершения таким образом противоречит документированному интерфейсу, и это настоятельно не рекомендуется.
Дмитрий
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.