diff options
| -rw-r--r-- | README.org | 19 | ||||
| -rw-r--r-- | cape.el | 76 |
2 files changed, 92 insertions, 3 deletions
@@ -31,6 +31,19 @@ packages or configurations, since it completes elisp symbols anywere. On the more experimental side, Cape has the super power to transform Company backends into Capfs and merge multiple Capfs into a Super-Capf! +* Available Capfs + +* ~cape-dabbrev~: Complete word from current buffers +* ~cape-file~: Complete file name +* ~cape-keyword~: Complete programming language keyword +* ~cape-symbol~: Complete Elisp symbol +* ~cape-abbrev~: Complete abbreviation (~add-global-abbrev~, ~add-mode-abbrev~) +* ~cape-ispell~: Complete word from Ispell dictionary +* ~cape-dict~: Complete word from dictionary file +* ~cape-line~: Complete entire line from file +* ~cape-tex~: Complete unicode char from TeX command, e.g. ~\hbar~, +* ~cape-sgml~: Complete unicode char from Sgml entity, e.g., ~&alpha~. + * Configuration Cape is available from MELPA. In the long term some of the Capfs provided by @@ -55,12 +68,16 @@ this package should be upstreamed into Emacs itself. ("C-c p a" . cape-abbrev) ("C-c p i" . cape-ispell) ("C-c p l" . cape-line) - ("C-c p w" . cape-dict)) + ("C-c p w" . cape-dict) + ("C-c p \\" . cape-tex) + ("C-c p &" . cape-sgml)) :init ;; Add `completion-at-point-functions', used by `completion-at-point'. (add-to-list 'completion-at-point-functions #'cape-file) + (add-to-list 'completion-at-point-functions #'cape-tex) (add-to-list 'completion-at-point-functions #'cape-dabbrev) (add-to-list 'completion-at-point-functions #'cape-keyword) + ;;(add-to-list 'completion-at-point-functions #'cape-sgml) ;;(add-to-list 'completion-at-point-functions #'cape-abbrev) ;;(add-to-list 'completion-at-point-functions #'cape-ispell) ;;(add-to-list 'completion-at-point-functions #'cape-dict) @@ -567,6 +567,71 @@ If INTERACTIVE is nil the function acts like a capf." ,(cape--table-with-properties (cape--dict-words) :category 'cape-dict) :exclusive no ,@cape--dict-properties)))) +;;;;; cape-tex and cape-sgml + +(defmacro cape--quail-define (name method prefix) + "Define quail translation variable with NAME. +METHOD is the input method. +PREFIX is the prefix regular expression." + (describe-input-method method) + (let ((capf (intern (format "cape-%s" name))) + (list (intern (format "cape--%s-list" name))) + (ann (intern (format "cape--%s-annotation" name))) + (exit (intern (format "cape--%s-exit" name))) + (properties (intern (format "cape--%s-properties" name))) + (translation + (with-current-buffer "*Help*" + (let ((str (replace-regexp-in-string + "\n\n\\(\n\\|.\\)*" "" + (replace-regexp-in-string + "\\`\\(\n\\|.\\)*?----\n" "" + (replace-regexp-in-string + "\\`\\(\n\\|.\\)*?KEY SEQUENCE\n-+\n" "" + (buffer-substring-no-properties (point-min) (point-max)))))) + (pos 0) + (list nil) + (regexp (format "\\(%s[^ \t\n]+\\)[ \t\n]+\\([^ \t\n]+\\)" prefix))) + (while (string-match regexp str pos) + (let ((char (match-string 2 str)) + (name (if (equal method "sgml") + (string-remove-suffix ";" (match-string 1 str)) + (match-string 1 str)))) + (push (cons name char) list) + (setq pos (match-end 0)))) + (kill-buffer-and-window) + (sort list (lambda (x y) (string< (car x) (car y)))))))) + `(progn + (defvar ,list ',translation) + (defun ,ann (name) + (concat " " (cdr (assoc name ,list)))) + (defun ,exit (name status) + (unless (eq status 'exact) + (when-let (str (cdr (assoc name ,list))) + (delete-region (- (point) (length name)) (point)) + (insert str)))) + (defvar ,properties + (list :annotation-function #',ann + :exit-function #',exit + :company-kind (lambda (_) 'text))) + (defun ,capf (&optional interactive) + (interactive (list t)) + (if interactive + ;; NOTE: Disable cycling since replacement breaks it. + (let (completion-cycle-threshold) + (cape--interactive #',capf)) + (require 'thingatpt) + (let ((bounds (if (thing-at-point-looking-at ,(format "%s[^ \n\t]*" prefix)) + (cons (match-beginning 0) (match-end 0)) + (cons (point) (point))))) + (append + (list (car bounds) (cdr bounds) + (cape--table-with-properties ,list :category ',capf) + :exclusive 'no) + ,properties))))))) + +(cape--quail-define tex "TeX" "[\\\\^_]") +(cape--quail-define sgml "sgml" "&") + ;;;;; cape-abbrev (defun cape--abbrev-list () @@ -583,9 +648,14 @@ If INTERACTIVE is nil the function acts like a capf." (abbrev--symbol abbrev global-abbrev-table))) 30 0 nil t))) +(defun cape--abbrev-exit (_str status) + "Expand expansion if STATUS is not exact." + (unless (eq status 'exact) + (expand-abbrev))) + (defvar cape--abbrev-properties (list :annotation-function #'cape--abbrev-annotation - :exit-function (lambda (&rest _) (expand-abbrev)) + :exit-function #'cape--abbrev-exit :company-kind (lambda (_) 'snippet)) "Completion extra properties for `cape-abbrev'.") @@ -595,7 +665,9 @@ If INTERACTIVE is nil the function acts like a capf." If INTERACTIVE is nil the function acts like a capf." (interactive (list t)) (if interactive - (cape--interactive #'cape-abbrev) + ;; NOTE: Disable cycling since abbreviation replacement breaks it. + (let (completion-cycle-threshold) + (cape--interactive #'cape-abbrev)) (when-let (abbrevs (cape--abbrev-list)) (let ((bounds (cape--bounds 'symbol))) `(,(car bounds) ,(cdr bounds) |
