semext-rename-current-file
Hi, thanks for an interesting package!
I don't know to what extent you're open to suggestions or informal contributions, but if so, here's a light modification of a command that's survived a few rounds of culling in my init file and feels aligned with the aims of semext:
(defun semext-rename-current-file ()
"Interactively rename current file following LLM suggestion."
(interactive)
(unless (buffer-file-name)
(user-error "Current buffer is not visiting a file"))
(let* ((current-name (file-name-nondirectory (buffer-file-name)))
(file-content (buffer-substring-no-properties (point-min) (point-max)))
(buffer (current-buffer))
(prompt (format "\
Given the following file content and current filename '%s', suggest a better, \
more descriptive filename. \Make sure to keep the file extension the same. \
Also, if the filename contains a timestamp at or near the beginning, then \
preserve that -- follow that timestamp with double dashes followed by a name \
separated by single dashes. Use the suggest_filename function to provide your \
suggestion.\n\nFile content:\n%s"
current-name
(if (> (length file-content) 1000)
(concat (substring file-content 0 1000) "...")
file-content)))
(filename-tool
(llm-make-tool
:function (lambda (callback suggested-name)
(funcall callback suggested-name))
:name "suggest_filename"
:description "Suggest a better filename for the current file."
:args '((:name "suggested_name"
:description "The suggested new filename."
:type string
:required t))
:async t))
(final-cb
(lambda (response)
(with-current-buffer buffer
(if-let* ((suggestion-pair (and (listp response)
(car response)))
(suggested-name (and (equal (car suggestion-pair)
"suggest_filename")
(cdr suggestion-pair))))
(let* ((current-dir (file-name-directory (buffer-file-name)))
(new-path (read-file-name "Rename file to: "
current-dir
nil
nil
suggested-name)))
(when (y-or-n-p (format "Rename '%s' to '%s'? "
(buffer-file-name)
new-path))
(require 'dired-aux)
(dired-rename-file (buffer-file-name) new-path 1)
(message "File renamed to '%s'"
(file-name-nondirectory new-path))))
(user-error
"Failed to get a valid filename suggestion from LLM")))))
(error-cb
(lambda (err msg)
(message "Error: %s - %s" err msg))))
(llm-chat-async semext-provider
(llm-make-chat-prompt
prompt
:tools (list filename-tool))
final-cb
error-cb)))
Typical use is to rename a scratch file to something descriptive based on its actual content.
If this aligns with your package's aims, then please feel to make use of it, modify it, incorporate it, etc. I'd also be happy to open a PR if that'd be helpful, but figured it might be easier just to share the idea informally, since you might have other design considerations or implementation details in mind.
Thanks for the suggestion! Right now semext is providing alternatives to commands that are powered semantically. This is slighty different, it's an alternative to a command that used to take an argument but no longer does, since we can figure out a reasonable value. But I think it's a fairly small step from what semext is doing now, to this.
One other interesting change is that the prompt here seems useful to have a customizable variable, unlike the prompts already in semext.
it's an alternative to a command that used to take an argument but no longer does, since we can figure out a reasonable value
To elaborate a bit, I still think of the suggested command as taking an argument, since the user can revise the LLM's suggestion. The argument isn't eliminated, but now comes with a "semantically aware" default value. This is similar to Emacs commands that provide sensible defaults via M-n, and suggests an extrapolation: add a minibuffer bind (perhaps M-N) that provides an LLM-powered default when relevant. For instance, the suggested command could be absorbed as the M-N feature in the input reading parts of commands like dired-do-rename and vc-rename-file.
One other interesting change is that the prompt here seems useful to have a customizable variable, unlike the prompts already in semext.
I assume you have in mind the lengthy prompt, which is not user agnostic, and indeed adds some complexity.