gptel-manual-complete: AI function completion in Emacs
This is an example of how the existing gptel-rewrite.el file can be used to
perform completion on an entire function, replacing what’s already written so
far in that function.
Setup
To use:
-
Install gptel↗, configure it, and provide the appropriate API keys
-
Install gptel-fn-complete↗
-
Now choose which key you’d like to bind it to. I typically add something like this to my Emacs config:
(defvar my-xref-map (let ((map (make-sparse-keymap))) (define-key map (kbd "c") #'gptel-manual-complete) (define-key map (kbd ".") #'xref-find-definitions) (define-key map (kbd ",") #'xref-go-back) (define-key map (kbd "/") #'xref-find-references) map) "My key customizations for AI and xref.") (global-set-key (kbd "C-c .") my-xref-map) -
Restart Emacs
Usage
If you’ve used the above keybinds, they work like this (the only with AI is the first one):
- C-c . c to complete the code at point using Claude AI; if you have a comment near the end, that will better inform the completion
- C-c . . to visit the definition of the thing at point
- C-c . , to return to the original point after visiting something
- C-c . / to find references to the thing at point
Example
When I write this code in a sample.el file:
(defun my-code ()
"AI should not modify this."
(message "Sample 1"))
(defun my-say-hello
;; print a welcoming message in a window off to the right
)
(defun my-other-code ()
"AI should not modify this either."
(message "Sample 2"))
Move the cursor into the body of my-hello and hit C-c . c then
gptel will rewrite that my-hello function to something like this, without
touching the other functions or deleting lines around it (results may vary, I
used Claude 3.5 Sonnet in this example):
(defun my-hello ()
"Print a welcoming message in a window off to the right."
(let ((buf (get-buffer-create "*Hello*")))
(with-current-buffer buf
(erase-buffer)
(insert "Welcome to Emacs!\n\nHave a productive session."))
(display-buffer buf
'((display-buffer-reuse-window
display-buffer-in-side-window)
(side . right)
(window-width . 40)))))
From here, you can use the standard gptel-rewrite keys like C-c C-a
on that code to accept it and remove the overlay on it.
Note that the function must have balanced parentheses, otherwise the code will throw an error. This is to make it easier to locate the beginning and end of the function to send to gptel’s context.
Inspiration
After adding a function to gptel’s context, I was using gptel-rewrite and
accidentally hit Enter twice. This resulted in just the basic “Rewrite: ” text
being sent, and to my surprise that was very effective at having Claude fix the
problem I was going to ask about.
I decided to see if Claude could also do code completions this way, with a very
terse kind of prompt on top of the standard gptel-rewrite prompt, and it turns
out that it can!
Notes
- For automatically identifying the entire current function to complete, you may have the best luck with either Emacs Lisp or files with major modes that have a tree-sitter grammar installed, as otherwise we have to guess. In general it should err on the side of sending too little rather than too much.
- My Emacs setup is available at https://github.com/mwolson/emacs-shared↗ which
has this and other features
- Note that the install doc might take a while to get through, and may have opinionated settings
- The additional AI features which have more bindings on C-c . than in the above example are described here↗