Skip to content

Rewriting completion of function at point using gptel in Emacs

License

Notifications You must be signed in to change notification settings

mwolson/gptel-fn-complete

Repository files navigation

gptel-fn-complete

Rewriting completion of function at point using gptel in Emacs.

This uses the existing gptel-rewrite.el library to perform completion on an entire function, replacing what's already written so far in that function in a way that prefers to complete the end of the function, but may also apply small changes to the original function.

Setup

To use:

  • Install gptel, configure it, and provide the appropriate API keys.
  • Clone this repo to a location like ~/gptel-fn-complete, or install gptel-fn-complete on MELPA.
  • When not using MELPA: Also add the following to your Emacs configuration (typically ~/.emacs.d/init.el or similar):
    (add-to-list 'load-path (expand-file-name "~/gptel-fn-complete"))
    (autoload #'gptel-fn-complete "gptel-fn-complete" "Complete function at point using an LLM." t)
  • Optionally, let gptel-fn-complete and gptel-rewrite automatically apply the code completion from the LLM and skip the extra prompt about it:
    (setopt gptel-rewrite-default-action 'accept)
  • Now choose which key you'd like to bind gptel-fn-complete 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-fn-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-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!

Comparison with other Emacs AI modes

  • aidermacs - aidermacs works with a commandline helper tool named aider which does most of the heavy lifting. It can record system prompts and conversations to files in your project to better remember what needs to be done. It has significantly more capabilities.

    gptel-fn-complete is built on gptel and is very minimally targeted towards just completing a single function, paragraph, or region.

  • elysium - elysium sends either the entire file or a selected region to the LLM. It also shows a window on the side with the LLM response, and includes smerge markers into the buffer with the result from the LLM. It is built on gptel.

    gptel-fn-complete uses a standard gptel-rewrite overlay on the code result instead of using the more visually-busy smerge markers. It can be configured using (setopt gptel-rewrite-default-action 'accept) to automatically skip the gptel-rewrite overlay and directly insert the text. It does not change the window layout to show a chat buffer.

  • minuet - minuet typically does a "fill-in-the-middle" style completion that doesn't modify the code before the point. It also has an optional auto-suggestion capability as you type. It can automatically include additional context lines before or after the function. It is not built on gptel and must be configured separately.

    gptel-fn-complete allows a partial rewrite of the entire function, if the LLM thinks there is stylistic value in the rewrite, and is typically manually triggered by a keybind. It does not have an auto-suggestion mode. It also leverages your existing gptel setup, allowing tricks like using gptel to manually include more file context to advise a better completion.

Notes

  • I've tested this with Claude, Gemini 2.0 Flash (which may still sometimes include unwanted code fences), and a few local LLMs.
  • 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
  • karthink and other gptel contributors may use the code in this repo freely and reassign copyright to themselves as need be if they would like.

About

Rewriting completion of function at point using gptel in Emacs

Resources

License

Stars

Watchers

Forks

Packages

No packages published