Come faccio a scrivere una semplice funzione "completamento-a-punto-funzioni"?


9

Sto pensando di scrivere una modalità importante per l'editing di mazzi di Magic: the Gathering.

La maggior parte sembra abbastanza semplice ma ho una domanda. Ci sono circa 15.000 carte Magic uniche disponibili (carte con nomi univoci cioè). Vorrei essere in grado di completare contro di loro scrivendo una funzione di completamento nel punto. Ho cercato un semplice esempio di base di una funzione capf che si completa con una serie di parole su cui basare la mia modalità, ma finora non sono riuscito a trovare nulla. Conosci qualche buon esempio per iniziare? E credi che sarebbe facile ottenere buone prestazioni o dovrei scrivere la mia struttura di dati (sto forse pensando a un Trie).

Ovviamente avrei bisogno di trovare un modo per sincronizzarmi con nuove carte ecc. E in futuro forse potrei anche essere in grado di cercare carte per altre caratteristiche oltre al solo nome della carta, ma che può aspettare.

Risposte:


17

Documentazione

La funzione di completamento dell'API al punto è disponibile nella documentazione di completion-at-point-functions

Ogni funzione su questo hook viene chiamata a turno senza alcun argomento e dovrebbe restituire zero per indicare che non è applicabile al punto, o una funzione di nessun argomento per eseguire il completamento (scoraggiato) o un elenco del modulo (INIZIA COLLEZIONE FINE . PROPS) dove START e END delimitano il completamento dell'entità e dovrebbero includere un punto, COLLECTION è la tabella di completamento da utilizzare per completarla e PROPS è un elenco di proprietà per ulteriori informazioni.

start, endE propssono evidenti, ma penso che il formato del collectionnon è definito in modo corretto. Per questo è possibile consultare la documentazione di try-completionoall-completions

Se la COLLEZIONE è una lista, le chiavi (macchine degli elementi) sono i possibili completamenti. Se un elemento non è una cella contro, allora l'elemento stesso è il possibile completamento. Se COLLECTION è una tabella hash, tutte le chiavi che sono stringhe o simboli sono i possibili completamenti. Se COLLECTION è un obarray, i nomi di tutti i simboli nell'obarray sono i possibili completamenti.

La COLLEZIONE può anche essere una funzione per eseguire il completamento stesso. Riceve tre argomenti: i valori STRING, PREDICATE e zero. Qualunque cosa ritorni diventa il valore di "try-completamento".

Esempio

Di seguito è riportato un semplice esempio di completamento nella funzione punto che utilizza le parole definite in /etc/dictionaries-common/wordsper completare le parole nel buffer

(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))))))))

La funzione di completamento cerca la parola al punto (la libreria thingatptviene utilizzata per trovare i limiti della parola) e la completa in base alle parole nel /etc/dictionaries-common/wordsfile, la proprietà :exclusiveè impostata in nomodo tale che emacs possa usare altre funzioni capf in caso di errore. Infine, sono state impostate alcune proprietà aggiuntive per migliorare l'integrazione in modalità azienda.

Prestazione

Il file di parole sul mio sistema aveva 99171 voci ed emacs è stato in grado di completarle senza problemi, quindi immagino che 15000 voci non dovrebbero essere un problema.

Integrazione con la modalità azienda

La modalità Azienda si integra molto bene con l' completion-at-point-functionsutilizzo del company-capfback - end, quindi dovrebbe funzionare per te, ma puoi migliorare i completamenti offerti dalla società restituendo ulteriori propsrisultati nel risultato della funzione capf. Gli oggetti di scena attualmente supportati sono

:company-doc-buffer - Utilizzato dalla società per visualizzare i metadati per il candidato corrente

:company-docsig - Utilizzato dalla compagnia per echeggiare i metadati sul candidato nel minibuffer

:company-location - Utilizzato dalla società per passare alla posizione del candidato corrente


Oh mio! Grazie per la risposta esaustiva! Lo proverò un po 'e lo accetterò dopo. Un ringraziamento extra per i suggerimenti dell'azienda (che attualmente sto usando).
Mattias Bengtsson,

Grazie, è davvero utile ora posso configurare facilmente i completamenti personalizzati :)
clemera,

Sono contento di poterti aiutare :)
Iqbal Ansari,

0

@Iqbal Ansari ha dato un'ottima risposta. Ecco una risposta supplementare, spero che ti sia d'aiuto.

Ecco un'implementazione che utilizza il meccanismo di completamento classico di emacs, 2009.

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

Di seguito è riportato il codice che esegue il completamento.

(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")))))

Di seguito è un'implementazione che utilizza l'interfaccia ido-mode. Molto più semplice

(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)))

Dovrai definire xyz-kwdList come un elenco delle tue parole.


2
-1 per reinventare l'interfaccia di completamento in un modo peggiore, andando nulloltre note usando identificatori camelcased e simboli greci che hanno senso solo nelle tue modalità.
wasamasa,

3
-1 per non aver risposto alla domanda che riguardava completion-at-point-functions(non sono d'accordo con @wasamasa sulla cosa nullvs not).
npostavs,

3
@XahLee Le funzioni in completion-at-point-functionsdovrebbero restituire i dati di completamento, non eseguire il completamento da soli. Quindi le funzioni nella tua risposta non sono utilizzabili come voci in completion-at-point-functions.
npostavs,

1
@npostavs ah capisco. hai ragione. Grazie!
Xah Lee,

4
@npostavs Questo tipo di funzione funzionerebbe ancora, ma in effetti scrivere una funzione di completamento in questo modo è contro l'interfaccia documentata ed è fortemente scoraggiato.
Dmitry,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.