branch: elpa/gptel commit 31c9ee3ae0ad390863d3c5bdb855e12de286e349 Author: Karthik Chikmagalur <karthikchikmaga...@gmail.com> Commit: Karthik Chikmagalur <karthikchikmaga...@gmail.com>
gptel: Match presets anywhere in the user prompt Catch strings of the form `@preset-name` anywhere in the user prompt and apply the preset in the transform/augment step. This change is experimental, and will be reverted if there are unexpected consequences or performance problems. This change is to make it easy to specify an on-the-fly preset when the user prompt structure is slightly off. Two examples: 1. When the user prompt is structured as ** Some heading *Prompt*: @preset-name ... where the heading is used for structural purposes. Technically the user prompt begins at the heading, but it's clear from context that the user intends to apply preset-name to the message. 2. When the preset specification naturally comes at the end. <long chunk of text> What do you make of the above, @explainer? This also promotes a more conversational preset usage style. * gptel.el (gptel--transform-apply-preset): Scan the entire user prompt for `@preset-name` mentions and apply presets as they are found. (gptel--fontify-preset-keyword): Fontify all `@preset-name` mentions in the user prompt. (gptel--prettify-preset): Adjust for new fontification keyword. --- gptel.el | 60 ++++++++++++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/gptel.el b/gptel.el index 54a9f32a19..49be6c519b 100644 --- a/gptel.el +++ b/gptel.el @@ -3665,41 +3665,35 @@ symbol." "Apply a gptel preset to the buffer depending on the prompt. If the user prompt begins with @foo, the preset foo is applied." - (text-property-search-backward 'gptel nil t) - (when (looking-at - (concat "[\n[:blank:]]*" - (and-let* ((prefix (gptel-prompt-prefix-string)) - ((not (string-empty-p prefix)))) - (concat "\\(?:" (regexp-quote prefix) "\\)?")))) - (goto-char (match-end 0))) - (while-let (((looking-at "[[:blank:]\n]*@\\([^[:blank:]]+\\)\\s-+")) - (name (match-string 1)) - (preset (or (gptel-get-preset (intern-soft name)) - (gptel-get-preset name)))) - (delete-region (match-beginning 0) (match-end 0)) - (gptel--apply-preset (cons name preset) - (lambda (sym val) - (set (make-local-variable sym) val))) - (message "Sending request with preset %s applied!" - (propertize name 'face 'mode-line-emphasis)))) + (when gptel--known-presets + (text-property-search-backward 'gptel nil t) + (while (re-search-forward "@\\([^[:blank:]]+\\)\\_>" nil t) + ;; The following convoluted check is because re-search is much faster if + ;; the search pattern begins with a non-whitespace char. + (when (or (= (match-beginning 0) (point-min)) + (memq (char-syntax (char-before (match-beginning 0))) '(32 62))) + (when-let* ((name (match-string 1)) + (preset (or (gptel-get-preset (intern-soft name)) + (gptel-get-preset name)))) + (delete-region (match-beginning 0) (match-end 0)) + (gptel--apply-preset (cons name preset) + (lambda (sym val) + (set (make-local-variable sym) val)))))))) + +;; ;; Alternative approach with string search +;; (search-forward "@" nil t) +;; (if (and (memq (char-syntax (char-before (1- (point)))) '(32 62)) +;; (looking-at "\\([^[:blank:]]+?\\)[[:punct:]]?\\s-+")) +;; do-stuff) (defun gptel--fontify-preset-keyword (end) "Font-lock function for preset indicators in chat buffers. Return preset fontification info for text up to END." - (when (re-search-forward "\\(?:^\\|[[:blank:]]+\\)\\(@\\([^[:blank:]\n]+\\)\\)" - end t) - (= (match-beginning 1) - (save-excursion - (text-property-search-backward 'gptel nil t) - (save-match-data - (if (looking-at - (concat "[\n[:blank:]]*" - (and-let* ((prefix (gptel-prompt-prefix-string)) - ((not (string-empty-p prefix)))) - (concat "\\(?:" (regexp-quote prefix) "\\)?" - "[\n[:blank:]]*")))) - (match-end 0) (point))))))) + (and (re-search-forward "@\\([^[:blank:]]+\\)\\_>" end t) + (or (= (match-beginning 0) (point-min)) + (memq (char-syntax (char-before (match-beginning 0))) '(32 62))) + (not (plist-get (text-properties-at (match-beginning 1)) 'gptel)))) (defun gptel-preset-capf () "Completion at point for gptel presets in `gptel-mode'. @@ -3723,9 +3717,11 @@ Add this to `completion-at-point-functions'." Intended to be added to `gptel-mode-hook'." (let ((keyword '((gptel--fontify-preset-keyword - 1 (when-let* ((comps (all-completions (match-string 2) + ;; subexp 0 here is not required, we retain it to make it + ;; easy to swtich to more complex patterns in the future + 0 (when-let* ((comps (all-completions (match-string 1) gptel--known-presets)) - ((member (match-string 2) comps))) + ((member (match-string 1) comps))) '(:box -1 :inherit secondary-selection)) prepend)))) (cond