diff --git a/modules/completion/siren-copilot.el b/modules/completion/siren-copilot.el index 2d4f6dc..502a419 100644 --- a/modules/completion/siren-copilot.el +++ b/modules/completion/siren-copilot.el @@ -58,9 +58,8 @@ (defun siren-copilot-dwim-with-mods () "Trigger or accept completion." (interactive) - (if (copilot--overlay-visible) - (siren-copilot-accept-with-mods) - (copilot-complete))) + (siren-copilot--complete-or-call + 'siren-copilot-accept-with-mods)) (defun siren-copilot--complete-or-call (f &rest args) "Trigger copilot-complete or call F." @@ -73,45 +72,72 @@ :group 'copilot) (defcustom siren-copilot-accept-mods - '((ruby-mode . ((" do\\( |.+|\\)?" . ("\n" "\nend")))) - (t . (("\{$" . ("\n" "\n}")) - ("\\[$" . ("\n" "\n]")) - ("\($" . ("\n" "\n)"))))) + '((ruby-mode . ((:match "\\([^\s]+\s+\\)do\\(?: |.+|\\)?\\'" + :replace "\\1") + (:match "\\`\s*do\\( |.+|\\)?\\'" + :before "\n" :after "\nend"))) + (t . (;; Strip opening "{" from end of completion. + (:match "\\([^\s]+\s*\\)\{\\'" :replace "\\1") + ;; Inject closing "}" on newline if completion is only "{" or " {". + (:match "\\`\s*\{\\'" :before "\n" :after "\n}") + ;; Strip opening "[" from end of completion. + (:match "\\([^\s]+\s*\\)\\[\\'" :replace "\\1") + ;; Inject closing "]" on newline if completion is only "[" or " [". + (:match "\\`\s*\\[\\'" :before "\n" :after "\n]") + ;; Strip opening "(" from end of completion. + (:match "\\([^\s]+\s*\\)\(\\'" :replace "\\1") + ;; Inject closing ")" on newline if completion is only "(" or " (". + (:match "\\`\s*\(\\'" :before "\n" :after "\n)")))) "List of mods of characters to balance." + :group 'siren-copilot :type '(alist :key-type symbol - :value-type (alist :key-type string - :value-type (list string string))) - :group 'siren-copilot) + :value-type (repeat (plist :key-type symbol + :value-type string)))) - (defun siren-copilot-accept-with-mods () + (defun siren-copilot-accept-with-mods (&optional transform-fn) "Accept completion, and add balance text after point if needed." (interactive) - (let ((mod nil)) - (copilot-accept-completion (lambda (completion) - (setq mod (siren-copilot--get-mod completion)) - completion)) - (siren-copilot--insert-mod mod))) + (let ((active-mod nil)) + (copilot-accept-completion + (lambda (completion) + (let* ((t-completion (funcall (or transform-fn #'identity) completion)) + (mod (siren-copilot--get-mod t-completion))) + (setq active-mod mod) + (siren-copilot--replace-mod mod t-completion)))) + (siren-copilot--inject-mod active-mod))) - (defun siren-copilot--get-mod (text) + (defun siren-copilot--get-mod (completion) (let ((mods (append (cdr (assoc major-mode siren-copilot-accept-mods)) (cdr (assoc t siren-copilot-accept-mods))))) (when (length> mods 0) - (cl-loop for (open . mod) in mods - when (string-match-p open text) + (cl-loop for mod in mods + when (string-match-p (plist-get mod :match) completion) return mod)))) - (defun siren-copilot--insert-mod (mod) + (defun siren-copilot--replace-mod (mod completion) + (let ((match (plist-get mod :match)) + (replace (plist-get mod :replace))) + (if (and match replace) + (replace-regexp-in-string match replace completion) + completion))) + + (defun siren-copilot--inject-mod (mod) (when mod - (let ((before (if (length> mod 1) (car mod))) - (after (if (length> mod 1) (cadr mod) (car mod)))) - (let ((start (point)) - (end (point))) - (if before (insert before)) - (save-excursion - (insert after) - (setq end (point))) - (indent-region start end) - (indent-according-to-mode))))) + (let ((before (plist-get mod :before)) + (after (plist-get mod :after)) + (indent (not (plist-get mod :no-indent))) + (start (point)) + (end (point))) + (when (or before after) + (when before + (insert before)) + (when after + (save-excursion + (insert after) + (setq end (point)))) + (when indent + (indent-region start end) + (indent-according-to-mode)))))) :config (with-eval-after-load 'company