5 Stimmen

Emacs-Vervollständigung-am-Punkt-Funktionen

Ich schreibe einen abgeleiteten Modus, der auf dem comint-mode basiert. Der Modus ist eine Schnittstelle zu einem Kommandozeilenprogramm (GRASS gis), und die Vervollständigung des comint-Modus funktioniert für die Programme. Ich versuche, Unterstützung für die Vervollständigung der Argumente für das Programm hinzuzufügen, über completion-at-point-functions . Ein Beispiel ist ein Spielzeug:

(setq my-commands 
      '(("ls"
         ("my-completion-1")
         ("my-completion-2"))
        ("mv"
         ("my-completion-3")
         ("my-completion-4"))))

(defun my-completion-at-point ()
  (interactive)
  (let ((pt (point)) ;; collect point
        start end)

    (save-excursion ;; collect the program name
      (comint-bol)
      (re-search-forward "\\(\\S +\\)\\s ?"))
    (if (and (>= pt (match-beginning 1))
             (<= pt (match-end 1)))
        () ;; if we're still entering the command, pass completion on to
      ;; comint-completion-at-point by returning nil

      (let ((command (match-string-no-properties 1)))
        (when (member* command my-commands :test 'string= :key 'car)
          ;; If the command is one of my-commands, use the associated completions 
          (goto-char pt)
          (re-search-backward "\\S *")
          (setq start (point))
          (re-search-forward "\\S *")
          (setq end (point))
          (list start end (cdr (assoc command my-commands)) :exclusive 'no))))))

(push 'my-completion-at-point completion-at-point-functions)

Das funktioniert fast. Ich erhalte eine normale Vervollständigung der Programmnamen. Wenn ich jedoch eingegeben habe ls in der Befehlszeile, mit der Tabulatortaste wird my-completion- und bietet die beiden Optionen nicht an. Erneutes Drücken von Tabulator fügt ein my-completion- ein zweites Mal, so dass ich jetzt ls my-completion-mycompletion- .

Mein aktueller Code enthält ein paar Zeilen, um auf mehrzeilige Befehle zu prüfen, nimmt aber keine Änderungen am Vervollständigungscode vor. Bei dieser Version des Codes drücke ich die Tabulatortaste in einer Zeile, die mit einem der Programmnamen in my-commands Ich erhalte eine Liste der möglichen Argumente, mit denen ich den Befehl vervollständigen kann, aber es wird nichts in den Puffer eingefügt, und die Liste wird nicht eingegrenzt, wenn ich die ersten Buchstaben eines Arguments eingebe.

Ich habe mir das Handbuch angesehen, aber ich kann nicht herausfinden, wie man eine completion-at-point Funktion. Hat jemand eine Idee, was ich übersehe?

Ich habe kurz nachgeschaut pcomplete aber sie haben die "Dokumentation" nicht wirklich verstanden und sind nicht weitergekommen.

8voto

Das Problem scheint in der Art und Weise zu liegen, wie Sie die start y end um die Grenzen des Arguments bei Punkt zurückzugeben. Ich habe nicht lange genug mit der Fehlersuche verbracht, um mir über die Details sicher zu sein, aber ich denke, wenn Sie die Funktion interaktiv aufrufen, werden Sie sehen, dass sie den gleichen Wert zurückgibt für start y end und das bedeutet, dass die Vervollständigungsschnittstelle nicht weiß, dass sie das Argument am Punkt verwenden soll, um aus der Vervollständigungstabelle auszuwählen, die Sie ihr übergeben haben.

Die Änderung des letzten Teils Ihrer Funktion in die folgende scheint eine Lösung zu sein:

(when (member* command my-commands :test 'string= :key 'car)
  ;; If the command is one of my-commands, use the associated completions 
  (goto-char pt)
  (let ((start
         (save-excursion
           (skip-syntax-backward "^ ")
           (point))))

    (list start pt (cdr (assoc command my-commands)) :exclusive 'no)))))))

Dies führt zu den erwarteten Ergebnissen, wenn es als ein Element von completion-at-point-functions .

Hier habe ich verwendet skip-syntax-backward anstelle der Regexp-Suche, die meiner Meinung nach etwas idiomatischer für diese Art von Dingen ist. Es sagt einfach, dass der Punkt rückwärts über alles bewegt werden soll, was nicht in der Syntaxklasse "Leerraum" ist. Die Skip-Syntax-Funktionen geben den Abstand zurück, den sie zurückgelegt haben, und nicht den Wert von point, also müssen wir einen Aufruf an point am Ende des Speicherausflugs.

Wenn Sie Regexp-Suchen in einer Funktion wie dieser verwenden, ist es normalerweise eine gute Idee, die t für das vierte Argument, noerror so dass es keine Fehler an den Benutzer weitergibt, wenn es nicht passt. Dies bedeutet jedoch, dass Sie selbst prüfen müssen, ob der Rückgabewert nil Allerdings.

Und schließlich, anstelle von push um die Vervollständigungsfunktion hinzuzufügen, können Sie Folgendes verwenden add-hook wie folgt:

(add-hook 'completion-at-point-functions 'my-completion-at-point nil t)

Diese Funktion erfüllt zwei nützliche Aufgaben: Sie prüft, ob Ihre Funktion bereits im Hook enthalten ist, bevor sie hinzugefügt wird, und (durch Übergabe von t für das vierte Argument, local ), fügt es die Funktion nur der Puffer-Lokal Wert des Abschluss-am-Punkt-Hakens. Das ist fast sicher das, was Sie wollen, da Sie diese Vervollständigungen nicht in jedem anderen Emacs-Puffer verwenden wollen, wenn Sie die TAB-Taste drücken.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X