From 41b18aa74cb49bf46f953f8adcf7ad5ff688142d Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Wed, 22 Feb 2023 00:04:16 +0000 Subject: [PATCH] feat(completion/copilot): add accept completion "mods" concept Essentially, if accepted completion string matches a given regexp pattern, text can be inserted both before and after point. This is useful in certain situations where Copilot suggests the opening line to a if statement, for loop, etc., which leads to unbalanced curly brackets. This can help reduce the annoyance of unbalanced brackets. --- modules/completion/siren-copilot.el | 100 ++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 27 deletions(-) diff --git a/modules/completion/siren-copilot.el b/modules/completion/siren-copilot.el index 3ee5822..790465c 100644 --- a/modules/completion/siren-copilot.el +++ b/modules/completion/siren-copilot.el @@ -6,6 +6,8 @@ ;;; Code: +(require 'cl-lib) + (use-package copilot :straight (:host github :repo "zerolfx/copilot.el" :files ("dist" "*.el")) @@ -13,15 +15,16 @@ (prog-mode . copilot-mode) :general - ("C-" 'siren-copilot-accept-completion-dwim) - ("" 'siren-copilot-accept-completion-dwim) - ("M-F" 'siren-copilot-accept-completion-by-word-dwim) - ("M-E" 'siren-copilot-accept-completion-by-line-dwim) + ("C-" 'siren-copilot-dwim-with-mods) + ("" 'siren-copilot-dwim-with-mods) + ("M-F" 'siren-copilot-dwim-by-word) + ("M-E" 'siren-copilot-dwim-by-line) (:keymaps 'copilot-completion-map "M-N" 'copilot-next-completion "M-P" 'copilot-previous-completion) :custom + (copilot-auto-balance t) (copilot-disable-predicates '(siren-copilot-disable-predicate)) :preface @@ -29,41 +32,84 @@ (when buffer-file-name (let ((base (file-name-nondirectory buffer-file-name)) (dir (file-name-directory buffer-file-name))) - (or (string-prefix-p ".env" base))))) + (or (string-prefix-p ".env" base) + (string-match-p "\/\.ansible\/tmp\/ansible-local-.+$" dir))))) - (defun siren-copilot-accept-completion-dwim () - "Accept the current completion or trigger copilot-compilot." + (defun siren-copilot-dwim () + "Trigger or accept completion." (interactive) - (siren-copilot-complete-or-call - 'siren-copilot-accept-completion-with-balanced-brackets)) + (siren-copilot--complete-or-call + 'copilot-accept-completion)) - (defun siren-copilot-accept-completion-by-word-dwim () - "Accept the current completion by word, or trigger copilot-compilot." + (defun siren-copilot-dwim-by-word (n-word) + "Trigger or accept N-WORD words from current completion." + (interactive "p") + (siren-copilot--complete-or-call + 'copilot-accept-completion-by-word n-word)) + + (defun siren-copilot-dwim-by-line (n-line) + "Trigger or accept N-LINE lines from current completion." + (interactive "p") + (siren-copilot--complete-or-call + 'copilot-accept-completion-by-line n-line)) + + (defun siren-copilot-dwim-with-mods () + "Trigger or accept completion." (interactive) - (siren-copilot-complete-or-call 'copilot-accept-completion-by-word 1)) + (if (copilot--overlay-visible) + (siren-copilot-accept-with-mods) + (copilot-complete))) - (defun siren-copilot-accept-completion-by-line-dwim () - "Accept the current completion by word, or trigger copilot-compilot." - (interactive) - (siren-copilot-complete-or-call 'copilot-accept-completion-by-line 1)) - - (defun siren-copilot-complete-or-call (f &rest args) + (defun siren-copilot--complete-or-call (f &rest args) "Trigger copilot-complete or call F." - (if (copilot-current-completion) + (if (copilot--overlay-visible) (apply f args) (copilot-complete))) - (defun siren-copilot-accept-completion-with-balanced-brackets () - "Accept completion, add '}' after point if completion ends with '{'." + (defgroup siren-copilot nil + "Siren: copilot customization." + :group 'copilot) + + (defcustom siren-copilot-accept-mods + '((ruby-mode . ((" do\\( |.+|\\)?" . ("\n" "\nend")))) + (t . (("\{$" . ("\n" "\n}")) + ("\\[$" . ("\n" "\n]")) + ("\($" . ("\n" "\n)"))))) + "List of mods of characters to balance." + :type '(alist :key-type symbol + :value-type (alist :key-type string + :value-type (list string string))) + :group 'siren-copilot) + + (defun siren-copilot-accept-with-mods () + "Accept completion, and add balance text after point if needed." (interactive) - (let ((bracket-open nil)) + (let ((mod nil)) (copilot-accept-completion (lambda (completion) - (setq bracket-open - (string-suffix-p "{" completion)) + (setq mod (siren-copilot--get-mod completion)) completion)) - (when bracket-open - (insert "}") - (backward-char)))) + (siren-copilot--insert-mod mod))) + + (defun siren-copilot--get-mod (text) + (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) + return mod)))) + + (defun siren-copilot--insert-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))))) :config (with-eval-after-load 'company