[emacs] More tools for the bot
Hmm, looking interesting!
This commit is contained in:
parent
9dc63e7548
commit
4a849cf912
1 changed files with 189 additions and 1 deletions
|
|
@ -34,6 +34,8 @@
|
||||||
(require 'gptel)
|
(require 'gptel)
|
||||||
(require 'url)
|
(require 'url)
|
||||||
|
|
||||||
|
;; === Emacs tools
|
||||||
|
|
||||||
(defun doty-tools--describe-function (func-name)
|
(defun doty-tools--describe-function (func-name)
|
||||||
"Return the help text for function FUNC-NAME."
|
"Return the help text for function FUNC-NAME."
|
||||||
(save-window-excursion
|
(save-window-excursion
|
||||||
|
|
@ -89,6 +91,8 @@
|
||||||
:confirm nil
|
:confirm nil
|
||||||
:include t)
|
:include t)
|
||||||
|
|
||||||
|
;; ==== File reading
|
||||||
|
|
||||||
(defun doty-tools--open-file (filename)
|
(defun doty-tools--open-file (filename)
|
||||||
"Visit FILENAME and return its contents as a string."
|
"Visit FILENAME and return its contents as a string."
|
||||||
(with-current-buffer (find-file-noselect filename)
|
(with-current-buffer (find-file-noselect filename)
|
||||||
|
|
@ -109,10 +113,194 @@ drwxr-x--- 2 john.doty ubuntu 4096 May 13 17:08 .
|
||||||
:args '((:name "filename"
|
:args '((:name "filename"
|
||||||
:type string
|
:type string
|
||||||
:description "The path of the file to read."))
|
:description "The path of the file to read."))
|
||||||
:category "devtools"
|
:category "reading"
|
||||||
:confirm nil
|
:confirm nil
|
||||||
:include t)
|
:include t)
|
||||||
|
|
||||||
|
(defun doty-tools--read-lines (buffer-or-file start-line &optional end-line include-line-numbers)
|
||||||
|
"Get content from specified line range in BUFFER-OR-FILE.
|
||||||
|
START-LINE is the beginning line number.
|
||||||
|
Optional END-LINE is the ending line number. If nil, only START-LINE is returned.
|
||||||
|
Optional INCLUDE-LINE-NUMBERS, if non-nil, adds line numbers to the output."
|
||||||
|
(with-current-buffer (if (bufferp buffer-or-file)
|
||||||
|
buffer-or-file
|
||||||
|
(find-file-noselect buffer-or-file))
|
||||||
|
(save-excursion
|
||||||
|
(save-restriction
|
||||||
|
(widen)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(forward-line (1- start-line))
|
||||||
|
(let ((end-line (or end-line start-line))
|
||||||
|
(result ""))
|
||||||
|
(dotimes (i (- end-line start-line -1))
|
||||||
|
(let ((line-num (+ start-line i))
|
||||||
|
(line-content (buffer-substring-no-properties
|
||||||
|
(line-beginning-position)
|
||||||
|
(line-end-position))))
|
||||||
|
(setq result
|
||||||
|
(concat result
|
||||||
|
(if include-line-numbers
|
||||||
|
(format "%d: %s\n" line-num line-content)
|
||||||
|
(format "%s\n" line-content)))))
|
||||||
|
(forward-line 1))
|
||||||
|
result)))))
|
||||||
|
|
||||||
|
(gptel-make-tool
|
||||||
|
:name "emacs_read_lines"
|
||||||
|
:function #'doty-tools--read-lines
|
||||||
|
:description "Get content from specified line range in a file."
|
||||||
|
:args '((:name "buffer_or_file"
|
||||||
|
:type string
|
||||||
|
:description "Buffer name or file path")
|
||||||
|
(:name "start_line"
|
||||||
|
:type integer
|
||||||
|
:description "Starting line number")
|
||||||
|
(:name "end_line"
|
||||||
|
:type integer
|
||||||
|
:optional t
|
||||||
|
:description "Ending line number (optional)")
|
||||||
|
(:name "include_line_numbers"
|
||||||
|
:type boolean
|
||||||
|
:optional t
|
||||||
|
:description "Whether to include line numbers in output (optional)"))
|
||||||
|
:category "reading"
|
||||||
|
:confirm nil
|
||||||
|
:include t)
|
||||||
|
|
||||||
|
(defun doty-tools--convert-regex (regex)
|
||||||
|
"Convert the REGEX in standard syntax to Emacs regex syntax.
|
||||||
|
Handles common differences like | vs \\|, () vs \\(\\), etc.
|
||||||
|
Also converts special character classes like \\d to [[:digit:]]."
|
||||||
|
(let ((case-fold-search nil)
|
||||||
|
(i 0)
|
||||||
|
(result "")
|
||||||
|
(len (length regex))
|
||||||
|
(escaped nil))
|
||||||
|
(while (< i len)
|
||||||
|
(let ((char (aref regex i)))
|
||||||
|
(cond
|
||||||
|
;; Handle escaped characters and special character classes
|
||||||
|
(escaped
|
||||||
|
(setq escaped nil)
|
||||||
|
(cond
|
||||||
|
;; Convert \d (digits) to [[:digit:]]
|
||||||
|
((= char ?d)
|
||||||
|
(setq result (concat result "[[:digit:]]")))
|
||||||
|
|
||||||
|
;; Convert \D (non-digits) to [^[:digit:]]
|
||||||
|
((= char ?D)
|
||||||
|
(setq result (concat result "[^[:digit:]]")))
|
||||||
|
|
||||||
|
;; Convert \w (word chars) to [[:alnum:]_]
|
||||||
|
((= char ?w)
|
||||||
|
(setq result (concat result "[[:alnum:]_]")))
|
||||||
|
|
||||||
|
;; Convert \W (non-word chars) to [^[:alnum:]_]
|
||||||
|
((= char ?W)
|
||||||
|
(setq result (concat result "[^[:alnum:]_]")))
|
||||||
|
|
||||||
|
;; Convert \s (whitespace) to [[:space:]]
|
||||||
|
((= char ?s)
|
||||||
|
(setq result (concat result "[[:space:]]")))
|
||||||
|
|
||||||
|
;; Convert \S (non-whitespace) to [^[:space:]]
|
||||||
|
((= char ?S)
|
||||||
|
(setq result (concat result "[^[:space:]]")))
|
||||||
|
|
||||||
|
;; Pass through other escaped characters
|
||||||
|
(t
|
||||||
|
(setq result (concat result "\\" (string char))))))
|
||||||
|
|
||||||
|
;; Handle escape character
|
||||||
|
((= char ?\\)
|
||||||
|
(setq escaped t))
|
||||||
|
|
||||||
|
;; Convert | to \|
|
||||||
|
((= char ?|)
|
||||||
|
(setq result (concat result "\\|")))
|
||||||
|
|
||||||
|
;; Convert ( to \( and ) to \)
|
||||||
|
((= char ?\()
|
||||||
|
(setq result (concat result "\\(")))
|
||||||
|
((= char ?\))
|
||||||
|
(setq result (concat result "\\)")))
|
||||||
|
|
||||||
|
;; Convert { to \{ and } to \}
|
||||||
|
((= char ?{)
|
||||||
|
(setq result (concat result "\\{")))
|
||||||
|
((= char ?})
|
||||||
|
(setq result (concat result "\\}")))
|
||||||
|
|
||||||
|
;; Pass other characters through
|
||||||
|
(t
|
||||||
|
(setq result (concat result (string char))))))
|
||||||
|
(setq i (1+ i)))
|
||||||
|
result))
|
||||||
|
|
||||||
|
(defun doty-tools--search-text (buffer-or-file pattern context-lines max-matches use-regex)
|
||||||
|
"Search for PATTERN in BUFFER-OR-FILE and return matches with context.
|
||||||
|
|
||||||
|
CONTEXT-LINES is the number of lines before and after each match to
|
||||||
|
include.
|
||||||
|
|
||||||
|
MAX-MATCHES is the maximum number of matches to return.
|
||||||
|
|
||||||
|
If USE-REGEX is non-nil, treat PATTERN as a regular expression, in
|
||||||
|
standard syntax. It will be converted into Emacs syntax before being
|
||||||
|
run."
|
||||||
|
(with-current-buffer (if (bufferp buffer-or-file)
|
||||||
|
buffer-or-file
|
||||||
|
(find-file-noselect buffer-or-file))
|
||||||
|
(save-excursion
|
||||||
|
(save-restriction
|
||||||
|
(widen)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(let ((count 0)
|
||||||
|
(matches "")
|
||||||
|
(search-pattern (if use-regex (doty-tools--convert-regex pattern) pattern))
|
||||||
|
(search-fn (if use-regex 're-search-forward 'search-forward)))
|
||||||
|
(while (and (funcall search-fn search-pattern nil t)
|
||||||
|
(< count max-matches))
|
||||||
|
(setq count (1+ count))
|
||||||
|
(let* ((match-line (line-number-at-pos))
|
||||||
|
(start-line (max 1 (- match-line context-lines)))
|
||||||
|
(end-line (+ match-line context-lines))
|
||||||
|
(context (doty-tools--read-lines (current-buffer)
|
||||||
|
start-line
|
||||||
|
end-line
|
||||||
|
t)))
|
||||||
|
(setq matches (concat matches
|
||||||
|
(format "Match %d (line %d):\n"
|
||||||
|
count match-line)
|
||||||
|
context
|
||||||
|
"\n"))))
|
||||||
|
matches)))))
|
||||||
|
|
||||||
|
(gptel-make-tool
|
||||||
|
:name "emacs_search_text"
|
||||||
|
:function #'doty-tools--search-text
|
||||||
|
:description "Find text matching a pattern and return with context. Returns formatted matches with line numbers and surrounding context."
|
||||||
|
:args '((:name "buffer_or_file"
|
||||||
|
:type string
|
||||||
|
:description "Buffer name or file path")
|
||||||
|
(:name "pattern"
|
||||||
|
:type string
|
||||||
|
:description "Text or regex to search for")
|
||||||
|
(:name "context_lines"
|
||||||
|
:type integer
|
||||||
|
:description "Number of lines before/after to include")
|
||||||
|
(:name "max_matches"
|
||||||
|
:type integer
|
||||||
|
:description "Maximum number of matches to return")
|
||||||
|
(:name "use_regex"
|
||||||
|
:type boolean
|
||||||
|
:description "Whether to use regex matching"))
|
||||||
|
:category "reading"
|
||||||
|
:confirm nil
|
||||||
|
:include t)
|
||||||
|
|
||||||
|
;; === System tools
|
||||||
|
|
||||||
(defun doty-tools--run-async-command (callback command)
|
(defun doty-tools--run-async-command (callback command)
|
||||||
"Run COMMAND asynchronously and call CALLBACK with the results as a string."
|
"Run COMMAND asynchronously and call CALLBACK with the results as a string."
|
||||||
(let ((output-buffer (generate-new-buffer " *async-command-output*")))
|
(let ((output-buffer (generate-new-buffer " *async-command-output*")))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue