Last active
May 30, 2024 07:03
Revisions
-
mbrock revised this gist
Feb 16, 2024 . 1 changed file with 0 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -144,6 +144,4 @@ Using `pipx' is recommended to avoid dependency conflicts"))) (provide 'hole-mode) ;;; hole-mode.el ends here -
mbrock revised this gist
Feb 16, 2024 . 1 changed file with 37 additions and 11 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,10 +1,30 @@ ;;; hole-mode.el --- fill holes with GPT-4 -*- lexical-binding: t -*- ;; Author: Mikael Brockman <mikael@brockman.se> ;; Version: 1.0 ;;; Commentary: ;; This package provides a minor mode for filling holes in code with AI. ;; ;; It is designed to work with the `llm' command-line tool, which is a ;; thin wrapper around OpenAI's GPT-4 API. ;; ;; Put holes in your code like this: ;; ;; (defun double-plus-one (x) ;; ":<docstring for double-plus-one>" ;; (+ :<a> :<b>)) ;; ;; Then run `M-x hole-query-replace' to fill in the holes. ;; ;; The `llm' command must be installed and available in your PATH. ;; ;; See https://llm.datasette.io/ for installation instructions. ;;; Code: (defconst hole-system-prompt "Fill in the holes marked with tags like :<x>, :<blog post title>, etc. Output a JSON object where field \"x\" is your best candidate for the :<x> hole, etc. @@ -19,16 +39,16 @@ whenever that is obvious from the context.") (defun hole-enable-highlighting () "Enable custom highlighting for `hole-mode'." (font-lock-add-keywords nil `((,hole-pattern (0 'widget-single-line-field prepend))) t)) (defun hole-disable-highlighting () "Disable custom highlighting for `hole-mode'." (font-lock-remove-keywords nil `((,hole-pattern (0 'widget-single-line-field prepend))))) (define-minor-mode hole-mode "Minor mode for filling holes with AI." nil " :<>" nil (if hole-mode (progn @@ -40,7 +60,7 @@ whenever that is obvious from the context.") (font-lock-ensure))) (defun hole-replacement-function (data count) "Replace holes in the buffer with values from the DATA alist." (let* ((string (match-string 1)) (matched-key (intern string)) (replacement (cdr (assoc matched-key data)))) @@ -83,17 +103,17 @@ whenever that is obvious from the context.") See https://llm.datasette.io/ for installation instructions. Using `pipx' is recommended to avoid dependency conflicts"))) (defun hole-query-replace (start end) "Query the user to fill in the holes in the selected region." (interactive "r") (hole-check-presence-of-llm-command) (let ((code (buffer-substring start end)) (json-buffer (get-buffer-create "*Hole LLM Output*"))) (shell-command-on-region start end (concat "llm -m 4t -o json_object true -s " (shell-quote-argument hole-system-prompt)) json-buffer nil shell-command-default-error-buffer t) (save-excursion @@ -103,6 +123,7 @@ Using `pipx' is recommended to avoid dependency conflicts."))) (hole-do-query-replace start end replacements))))) (defun hole-git-commit-edit-hook () "Insert a placeholder for a commit message in a `git commit' buffer." (when (string-match-p "COMMIT_EDITMSG" (buffer-name)) (hole-insert "commit title") (move-end-of-line 1) @@ -115,9 +136,14 @@ Using `pipx' is recommended to avoid dependency conflicts."))) (delete-other-windows))) (defun hole-magit-commit () "Start a `git commit' operation with holes to fill." (interactive) (add-hook 'find-file-hook 'hole-git-commit-edit-hook) (magit-commit-create '("--verbose" "--all")) (message "Select the entire buffer and run `M-x hole-query-replace'")) (provide 'hole-mode) (provide 'hole-mode) ;;; hole-mode.el ends here -
mbrock revised this gist
Feb 16, 2024 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -77,7 +77,7 @@ whenever that is obvious from the context.") ;; We could easily do without the llm command by using the API directly... "Check if the `llm' command is available." (interactive) (if (executable-find "llm") t (error "You need the `llm' command. -
mbrock revised this gist
Feb 16, 2024 . 1 changed file with 18 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -102,4 +102,22 @@ Using `pipx' is recommended to avoid dependency conflicts."))) (json-read)))) (hole-do-query-replace start end replacements))))) (defun hole-git-commit-edit-hook () (when (string-match-p "COMMIT_EDITMSG" (buffer-name)) (hole-insert "commit title") (move-end-of-line 1) (newline 2) (hole-insert "commit message") (move-end-of-line 1) (newline 1) (goto-char (point-min)) (auto-fill-mode) (delete-other-windows))) (defun hole-magit-commit () (interactive) (add-hook 'find-file-hook 'hole-git-commit-edit-hook) (magit-commit-create '("--verbose" "--all")) (message "Select the entire buffer and run `M-x hole-query-replace'")) (provide 'hole-mode) -
mbrock created this gist
Feb 16, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,105 @@ ;;; -*- lexical-binding: t -*- ;;; hole-mode.el --- fill holes with GPT-4 ;; Author: Mikael Brockman <mikael@brockman.se> ;; Version: 1.0 (defconst hole-system-prompt "Fill in the holes marked with tags like :<x>, :<blog post title>, etc. Output a JSON object where field \"x\" is your best candidate for the :<x> hole, etc. Insertions should be syntactically valid in their context. For example, in Lisp they will often, but not always, be wrapped in parens. Try to ignore holes that are themselves mere examples of the hole feature, whenever that is obvious from the context.") (defvar hole-pattern ":<\\([a-zA-Z -]+\\)>") (defun hole-enable-highlighting () "Enable custom highlighting for `hole-mode'." (font-lock-add-keywords nil `((,hole-pattern (0 'widget-single-line-field prepend))) t)) (defun hole-disable-highlighting () "Disable custom highlighting for `hole-mode'." (font-lock-remove-keywords nil `((,hole-pattern (0 'widget-single-line-field prepend))))) (define-minor-mode hole-mode "Minor mode for filling holes with AI" nil " :<>" nil (if hole-mode (progn (hole-mode-enable-highlighting) (font-lock-flush) (font-lock-ensure)) (hole-mode-disable-highlighting) (font-lock-flush) (font-lock-ensure))) (defun hole-replacement-function (data count) "Replace holes in the buffer with values from a JSON object." (let* ((string (match-string 1)) (matched-key (intern string)) (replacement (cdr (assoc matched-key data)))) (replace-quote (or replacement string)))) (defun hole-do-query-replace (start end replacements) "Execute a query-replace operation on code holes in a region." (let ((query-flag t) (regexp-flag t)) (save-excursion (let ((start-marker (copy-marker start)) (end-marker (copy-marker end))) (perform-replace hole-pattern `(hole-replacement-function . ,replacements) query-flag regexp-flag nil nil nil start-marker end-marker))))) (defun hole-docstring-in-defun () "Insert a placeholder for a docstring in the current defun." (interactive) (save-excursion (paredit-focus-on-defun) (paredit-forward-down 1) (paredit-forward 1) (let ((name (save-excursion (let ((start (point))) (paredit-forward 1) (buffer-substring-no-properties start (point)))))) (paredit-forward 2) (insert "\n\":<docstring for" name ">\"") (paredit-focus-on-defun) (paredit-indent-sexps)))) (defun hole-check-presence-of-llm-command () ;; We could easily do without the llm command by using the API directly... "Check if the `llm' command is available." (interactive) (if (executable-find "llmx") t (error "You need the `llm' command. See https://llm.datasette.io/ for installation instructions. Using `pipx' is recommended to avoid dependency conflicts."))) (defun hole-query-replace (start end) "Query the user to fill in the holes in the selected region." (interactive "r") (hole-check-presence-of-llm-command) (let ((code (buffer-substring start end)) (json-buffer (get-buffer-create "*Hole LLM Output*"))) (shell-command-on-region start end (concat "llm -m 4t -o json_object true -s " (shell-quote-argument hole-system-prompt)) json-buffer nil shell-command-default-error-buffer t) (save-excursion (let ((replacements (with-current-buffer json-buffer (goto-char (point-min)) (json-read)))) (hole-do-query-replace start end replacements))))) (provide 'hole-mode)