branch: externals/ellama commit 3af214afb770ee01a06336c291e07dedc9cd6129 Author: Sergey Kostyaev <sskosty...@gmail.com> Commit: Sergey Kostyaev <sskosty...@gmail.com>
Add webpage quote context elements --- ellama.el | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/test-ellama.el | 37 ++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/ellama.el b/ellama.el index e28ed3e060..ae00b48610 100644 --- a/ellama.el +++ b/ellama.el @@ -41,6 +41,7 @@ (require 'spinner) (require 'info) (require 'shr) +(require 'eww) (eval-when-compile (require 'rx)) (defgroup ellama nil @@ -322,6 +323,11 @@ Too low value can break generated code by splitting long comment lines." :group 'ellama :type 'boolean) +(defcustom ellama-show-quotes nil + "Show quotes in chat context." + :group 'ellama + :type 'boolean) + (define-minor-mode ellama-session-mode "Minor mode for ellama session buffers." :interactive nil @@ -893,6 +899,52 @@ If EPHEMERAL non nil new session will not be associated with any file." (ignore mode) (oref element content)) +;; Webpage quote context elements + +(defclass ellama-context-element-webpage-quote (ellama-context-element) + ((name :initarg :name :type string) + (url :initarg :url :type string) + (content :initarg :content :type string)) + "A structure for holding information about a context element.") + +(cl-defmethod ellama-context-element-extract + ((element ellama-context-element-webpage-quote)) + "Extract the content of the context ELEMENT." + (oref element content)) + +(cl-defmethod ellama-context-element-format + ((element ellama-context-element-webpage-quote) (mode (eql 'markdown-mode))) + "Format the context ELEMENT for the major MODE." + (ignore mode) + (with-slots (name url content) element + (if ellama-show-quotes + (format "[%s](%s):\n%s\n\n" + name url + (ellama--md-quote content)) + (format "[%s](%s)" name url)))) + +(defun ellama--md-quote (content) + "Return quoted CONTENT for markdown." + (with-temp-buffer + (insert (propertize content 'hard t)) + (let ((fill-prefix "> ") + (fill-column ellama-long-lines-length) + (use-hard-newlines t) + (comment-start ">") + (comment-empty-lines t)) + (comment-region (point-min) (point-max) ">") + (fill-region (point-min) (point-max) nil t t)) + (buffer-substring-no-properties (point-min) (point-max)))) + +(cl-defmethod ellama-context-element-format + ((element ellama-context-element-webpage-quote) (mode (eql 'org-mode))) + "Format the context ELEMENT for the major MODE." + (ignore mode) + (with-slots (name url content) element + (if ellama-show-quotes + (format "[[%s][%s]]:\n#+BEGIN_QUOTE\n%s\n#+END_QUOTE\n" url name content) + (format "[[%s][%s]]" url name)))) + ;;;###autoload (defun ellama-context-add-file () "Add file to context." @@ -925,6 +977,29 @@ If EPHEMERAL non nil new session will not be associated with any file." (let ((element (ellama-context-element-info-node :name node))) (ellama-context-element-add element))) +(defun ellama-context-add-webpage-quote (name url content) + "Add webpage with NAME and URL quote CONTENT to context." + (let ((element (ellama-context-element-webpage-quote + :name name :url url :content content))) + (ellama-context-element-add element))) + +;;;###autoload +(defun ellama-context-add-webpage-quote-eww () + "Add webpage quote to context interactively from `eww'." + (interactive) + (if (eq major-mode 'eww-mode) + (let* ((name (plist-get eww-data :title)) + (url (eww-current-url)) + (content (if (region-active-p) + (buffer-substring-no-properties + (region-beginning) + (region-end)) + (buffer-substring-no-properties + (point-min) + (point-max))))) + (ellama-context-add-webpage-quote name url content)) + (warn "Should be called from `eww'."))) + (defun ellama--translate-string (s) "Translate string S to `ellama-language' syncronously." (llm-chat diff --git a/tests/test-ellama.el b/tests/test-ellama.el index 384d8a418f..dfb0683aba 100644 --- a/tests/test-ellama.el +++ b/tests/test-ellama.el @@ -86,6 +86,39 @@ (let ((element (ellama-context-element-text :content "123"))) (should (equal "123" (ellama-context-element-format element 'org-mode))))) +(ert-deftest test-ellama-context-element-format-webpage-quote-disabled-markdown () + (let ((element (ellama-context-element-webpage-quote :name "test name" :url "https://example.com/" :content "1\n\n2")) + (ellama-show-quotes nil)) + (should (equal "[test name](https://example.com/)" (ellama-context-element-format element 'markdown-mode))))) + +(ert-deftest test-ellama-context-element-format-webpage-quote-enabled-markdown () + (let ((element (ellama-context-element-webpage-quote :name "test name" :url "https://example.com/" :content "1\n\n2")) + (ellama-show-quotes t)) + (should (equal "[test name](https://example.com/): +> 1 +> +> 2 + +" + (ellama-context-element-format element 'markdown-mode))))) + +(ert-deftest test-ellama-context-element-format-webpage-quote-disabled-org-mode () + (let ((element (ellama-context-element-webpage-quote :name "test name" :url "https://example.com/" :content "1\n\n2")) + (ellama-show-quotes nil)) + (should (equal "[[https://example.com/][test name]]" (ellama-context-element-format element 'org-mode))))) + +(ert-deftest test-ellama-context-element-format-webpage-quote-enabled-org-mode () + (let ((element (ellama-context-element-webpage-quote :name "test name" :url "https://example.com/" :content "1\n\n2")) + (ellama-show-quotes t)) + (should (equal "[[https://example.com/][test name]]: +#+BEGIN_QUOTE +1 + +2 +#+END_QUOTE +" + (ellama-context-element-format element 'org-mode))))) + (ert-deftest test-ellama-context-element-extract-buffer () (with-temp-buffer (insert "123") @@ -106,6 +139,10 @@ (let ((element (ellama-context-element-text :content "123"))) (should (string-match "123" (ellama-context-element-extract element))))) +(ert-deftest test-ellama-context-element-extract-webpage-quote () + (let ((element (ellama-context-element-webpage-quote :content "123"))) + (should (equal "123" (ellama-context-element-extract element))))) + (ert-deftest test-ellama-md-to-org-code-simple () (let ((result (ellama--translate-markdown-to-org-filter "Here is your TikZ code for a blue rectangle: ```tex