branch: externals/ellama
commit 1c52902d4de4933b61cd3a3bcdd3f74cadd31f9f
Merge: 1b71217434 22dcffff59
Author: Sergey Kostyaev <[email protected]>
Commit: GitHub <[email protected]>
Merge pull request #235 from s-kostyaev/add-context-header-line
Add ellama context header and mode line modes
---
NEWS.org | 8 ++
README.org | 215 ++++++++++++++++++++++++++++----------------
docs/changelog.org | 3 +
ellama.el | 245 +++++++++++++++++++++++++++++++++------------------
tests/test-ellama.el | 61 +++++--------
5 files changed, 334 insertions(+), 198 deletions(-)
diff --git a/NEWS.org b/NEWS.org
index e7b76e2678..9ec0c38ba8 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -1,3 +1,11 @@
+* Version 1.3.0
+- Implemented ellama context header line and mode line features.
+- Added ~ellama-context-header-line-mode~, ~ellama-context-mode-line-mode~ and
+ its global versions.
+- Session renaming functionality improvements.
+- Improved session deletion.
+- Renamed ~ellama-session-remove~ to ~ellama-session-delete~.
+- Removed ~ellama-long-lines-length~ customization and related usage
* Version 1.2.5
- Fix scroll function.
* Version 1.2.4
diff --git a/README.org b/README.org
index aa2f5a1580..1bda4fb572 100644
--- a/README.org
+++ b/README.org
@@ -32,72 +32,74 @@ Without any configuration, the first available ollama model
will be used.
You can customize ellama configuration like this:
#+BEGIN_SRC emacs-lisp
-(use-package ellama
- :ensure t
- :bind ("C-c e" . ellama-transient-main-menu)
- :init
- ;; setup key bindings
- ;; (setopt ellama-keymap-prefix "C-c e")
- ;; language you want ellama to translate to
- (setopt ellama-language "German")
- ;; could be llm-openai for example
- (require 'llm-ollama)
- (setopt ellama-provider
- (make-llm-ollama
- ;; this model should be pulled to use it
- ;; value should be the same as you print in terminal during pull
- :chat-model "llama3:8b-instruct-q8_0"
- :embedding-model "nomic-embed-text"
- :default-chat-non-standard-params '(("num_ctx" . 8192))))
- (setopt ellama-summarization-provider
- (make-llm-ollama
- :chat-model "qwen2.5:3b"
- :embedding-model "nomic-embed-text"
- :default-chat-non-standard-params '(("num_ctx" . 32768))))
- (setopt ellama-coding-provider
- (make-llm-ollama
- :chat-model "qwen2.5-coder:3b"
- :embedding-model "nomic-embed-text"
- :default-chat-non-standard-params '(("num_ctx" . 32768))))
- ;; Predefined llm providers for interactive switching.
- ;; You shouldn't add ollama providers here - it can be selected interactively
- ;; without it. It is just example.
- (setopt ellama-providers
- '(("zephyr" . (make-llm-ollama
- :chat-model "zephyr:7b-beta-q6_K"
- :embedding-model "zephyr:7b-beta-q6_K"))
- ("mistral" . (make-llm-ollama
- :chat-model "mistral:7b-instruct-v0.2-q6_K"
- :embedding-model "mistral:7b-instruct-v0.2-q6_K"))
- ("mixtral" . (make-llm-ollama
- :chat-model "mixtral:8x7b-instruct-v0.1-q3_K_M-4k"
- :embedding-model
"mixtral:8x7b-instruct-v0.1-q3_K_M-4k"))))
- ;; Naming new sessions with llm
- (setopt ellama-naming-provider
- (make-llm-ollama
- :chat-model "llama3:8b-instruct-q8_0"
- :embedding-model "nomic-embed-text"
- :default-chat-non-standard-params '(("stop" . ("\n")))))
- (setopt ellama-naming-scheme 'ellama-generate-name-by-llm)
- ;; Translation llm provider
- (setopt ellama-translation-provider
- (make-llm-ollama
- :chat-model "qwen2.5:3b"
- :embedding-model "nomic-embed-text"
- :default-chat-non-standard-params
- '(("num_ctx" . 32768))))
- (setopt ellama-extraction-provider (make-llm-ollama
- :chat-model
"qwen2.5-coder:7b-instruct-q8_0"
- :embedding-model "nomic-embed-text"
- :default-chat-non-standard-params
- '(("num_ctx" . 32768))))
- ;; customize display buffer behaviour
- ;; see ~(info "(elisp) Buffer Display Action Functions")~
- (setopt ellama-chat-display-action-function #'display-buffer-full-frame)
- (setopt ellama-instant-display-action-function #'display-buffer-at-bottom)
- :config
- ;; send last message in chat buffer with C-c C-c
- (add-hook 'org-ctrl-c-ctrl-c-hook #'ellama-chat-send-last-message))
+ (use-package ellama
+ :ensure t
+ :bind ("C-c e" . ellama-transient-main-menu)
+ :init
+ ;; setup key bindings
+ ;; (setopt ellama-keymap-prefix "C-c e")
+ ;; language you want ellama to translate to
+ (setopt ellama-language "German")
+ ;; could be llm-openai for example
+ (require 'llm-ollama)
+ (setopt ellama-provider
+ (make-llm-ollama
+ ;; this model should be pulled to use it
+ ;; value should be the same as you print in terminal during pull
+ :chat-model "llama3:8b-instruct-q8_0"
+ :embedding-model "nomic-embed-text"
+ :default-chat-non-standard-params '(("num_ctx" . 8192))))
+ (setopt ellama-summarization-provider
+ (make-llm-ollama
+ :chat-model "qwen2.5:3b"
+ :embedding-model "nomic-embed-text"
+ :default-chat-non-standard-params '(("num_ctx" . 32768))))
+ (setopt ellama-coding-provider
+ (make-llm-ollama
+ :chat-model "qwen2.5-coder:3b"
+ :embedding-model "nomic-embed-text"
+ :default-chat-non-standard-params '(("num_ctx" . 32768))))
+ ;; Predefined llm providers for interactive switching.
+ ;; You shouldn't add ollama providers here - it can be selected
interactively
+ ;; without it. It is just example.
+ (setopt ellama-providers
+ '(("zephyr" . (make-llm-ollama
+ :chat-model "zephyr:7b-beta-q6_K"
+ :embedding-model "zephyr:7b-beta-q6_K"))
+ ("mistral" . (make-llm-ollama
+ :chat-model "mistral:7b-instruct-v0.2-q6_K"
+ :embedding-model "mistral:7b-instruct-v0.2-q6_K"))
+ ("mixtral" . (make-llm-ollama
+ :chat-model "mixtral:8x7b-instruct-v0.1-q3_K_M-4k"
+ :embedding-model
"mixtral:8x7b-instruct-v0.1-q3_K_M-4k"))))
+ ;; Naming new sessions with llm
+ (setopt ellama-naming-provider
+ (make-llm-ollama
+ :chat-model "llama3:8b-instruct-q8_0"
+ :embedding-model "nomic-embed-text"
+ :default-chat-non-standard-params '(("stop" . ("\n")))))
+ (setopt ellama-naming-scheme 'ellama-generate-name-by-llm)
+ ;; Translation llm provider
+ (setopt ellama-translation-provider
+ (make-llm-ollama
+ :chat-model "qwen2.5:3b"
+ :embedding-model "nomic-embed-text"
+ :default-chat-non-standard-params
+ '(("num_ctx" . 32768))))
+ (setopt ellama-extraction-provider (make-llm-ollama
+ :chat-model
"qwen2.5-coder:7b-instruct-q8_0"
+ :embedding-model "nomic-embed-text"
+ :default-chat-non-standard-params
+ '(("num_ctx" . 32768))))
+ ;; customize display buffer behaviour
+ ;; see ~(info "(elisp) Buffer Display Action Functions")~
+ (setopt ellama-chat-display-action-function #'display-buffer-full-frame)
+ (setopt ellama-instant-display-action-function #'display-buffer-at-bottom)
+ :config
+ ;; show ellama context in header line in all buffers
+ (ellama-context-header-line-global-mode +1)
+ ;; send last message in chat buffer with C-c C-c
+ (add-hook 'org-ctrl-c-ctrl-c-hook #'ellama-chat-send-last-message))
#+END_SRC
** Commands
@@ -240,9 +242,9 @@ as a specified format using Ellama.
Load ellama session from file.
-*** ellama-session-remove
+*** ellama-session-delete
-Remove ellama session.
+Delete ellama session.
*** ellama-session-switch
@@ -340,7 +342,7 @@ Ellama, using the ~ellama-keymap-prefix~ prefix (not set by
default):
| "s c" | ellama-summarize-killring | Summarize killring |
| "s l" | ellama-load-session | Session Load |
| "s r" | ellama-session-rename | Session rename |
-| "s d" | ellama-session-remove | Session delete |
+| "s d" | ellama-session-delete | Delete delete |
| "s a" | ellama-session-switch | Session activate |
| "P" | ellama-proofread | Proofread |
| "i w" | ellama-improve-wording | Improve wording |
@@ -383,6 +385,7 @@ There are many supported providers: ~ollama~, ~open ai~,
~vertex~,
~GPT4All~. For more information see
[[https://elpa.gnu.org/packages/llm.html][llm documentation]].
- ~ellama-providers~: association list of model llm providers with
name as key.
+- ~ellama-spinner-enabled~: Enable spinner during text generation.
- ~ellama-spinner-type~: Spinner type for ellama. Default type is
~progress-bar~.
- ~ellama-ollama-binary~: Path to ollama binary.
@@ -401,9 +404,6 @@ argument generated text string.
- ~ellama-sessions-directory~: Directory for saved ellama sessions.
- ~ellama-major-mode~: Major mode for ellama commands. Org mode by
default.
-- ~ellama-long-lines-length~: Long lines length for fill paragraph
- call. Too low value can break generated code by splitting long
- comment lines. Default value 100.
- ~ellama-session-auto-save~: Automatically save ellama sessions if
set. Enabled by default.
- ~ellama-naming-scheme~: How to name new sessions.
@@ -427,7 +427,6 @@ argument generated text string.
- ~ellama-context-poshandler~: Position handler for displaying context buffer.
~posframe-poshandler-frame-top-center~ will be used if not set.
- ~ellama-context-border-width~: Border width for the context buffer.
-- ~ellama-context-element-padding-size~: Padding size for context elements.
- ~ellama-session-remove-reasoning~: Remove internal reasoning from
the session after ellama provide an answer. This can improve
long-term communication with reasoning models. Enabled by default.
@@ -439,13 +438,81 @@ argument generated text string.
ellama output to enhance the versatility of reasoning models across
diverse applications.
- ~ellama-context-posframe-enabled~: Enable showing posframe with
- ellama context. Enabled by default.
+ ellama context.
- ~ellama-manage-context-display-action-function~: Display action
function for ~ellama-render-context~. Default value
~display-buffer-same-window~.
- ~ellama-preview-context-element-display-action-function~: Display
action function for ~ellama-preview-context-element~.
+** Minor modes
+
+*** ellama-context-header-line-mode
+
+*Description:*
+Toggle the Ellama Context header line mode. This minor mode updates the header
line to display
+context-specific information.
+
+*Usage:*
+To enable or disable ~ellama-context-header-line-mode~, use the command:
+
+ M-x ellama-context-header-line-mode
+
+When enabled, this mode adds a hook to ~window-state-change-hook~ to update
the header line whenever
+the window state changes. It also calls ~ellama-context-update-header-line~ to
initialize the header
+line with context-specific information.
+
+When disabled, it removes the evaluation of ~(:eval (ellama-context-line))~
from
+~header-line-format~.
+
+*** ellama-context-header-line-global-mode
+
+*Description:*
+Globalized version of ~ellama-context-header-line-mode~. This mode ensures that
+~ellama-context-header-line-mode~ is enabled in all buffers.
+
+*Usage:*
+To enable or disable ~ellama-context-header-line-global-mode~, use the command:
+
+ M-x ellama-context-header-line-global-mode
+
+This globalized minor mode provides a convenient way to ensure that
context-specific header line
+information is always available, regardless of the buffer being edited.
+
+*** ellama-context-mode-line-mode
+
+*Description:*
+Toggle the Ellama Context mode line mode. This minor mode updates the mode line
+to display context-specific information.
+
+*Usage:*
+To enable or disable ~ellama-context-mode-line-mode~, use the command:
+
+ M-x ellama-context-mode-line-mode
+
+When enabled, this mode adds a hook to ~window-state-change-hook~ to update the
+mode line whenever the window state changes. It also calls
+~ellama-context-update-mode-line~ to initialize the mode line with
+context-specific information.
+
+When disabled, it removes the evaluation of ~(:eval (ellama-context-line))~
from
+~mode-line-format~.
+
+*** ellama-context-mode-line-global-mode
+
+*Description:*
+Globalized version of ~ellama-context-mode-line-mode~. This mode ensures that
+~ellama-context-mode-line-mode~ is enabled in all buffers.
+
+*Usage:*
+To enable or disable ~ellama-context-mode-line-global-mode~, use the command:
+
+ M-x ellama-context-mode-line-global-mode
+
+This globalized minor mode provides a convenient way to ensure that
+context-specific mode line information is always available, regardless of the
+buffer being edited.
+
** Acknowledgments
Thanks [[https://github.com/jmorganca][Jeffrey Morgan]] for excellent project
[[https://github.com/jmorganca/ollama][ollama]]. This project
diff --git a/docs/changelog.org b/docs/changelog.org
new file mode 100644
index 0000000000..a713a2d381
--- /dev/null
+++ b/docs/changelog.org
@@ -0,0 +1,3 @@
+Based on this git log write short changelog in markdown list format. Do not add
+any headings or anknowledgements. Every changelog element should be ended with
+full stop.
diff --git a/ellama.el b/ellama.el
index 20c92023ed..e6171a1922 100644
--- a/ellama.el
+++ b/ellama.el
@@ -5,8 +5,8 @@
;; Author: Sergey Kostyaev <[email protected]>
;; URL: http://github.com/s-kostyaev/ellama
;; Keywords: help local tools
-;; Package-Requires: ((emacs "28.1") (llm "0.22.0") (spinner "1.7.4")
(transient "0.7") (compat "29.1") (posframe "1.4.0"))
-;; Version: 1.2.5
+;; Package-Requires: ((emacs "28.1") (llm "0.22.0") (transient "0.7") (compat
"29.1"))
+;; Version: 1.3.0
;; SPDX-License-Identifier: GPL-3.0-or-later
;; Created: 8th Oct 2023
@@ -38,10 +38,8 @@
(require 'eieio)
(require 'llm)
(require 'llm-provider-utils)
-(require 'spinner)
(require 'transient)
(require 'compat)
-(require 'posframe)
(eval-when-compile (require 'rx))
(defgroup ellama nil
@@ -116,13 +114,22 @@ Make reasoning models more useful for many cases."
:type '(alist :key-type string
:value-type (sexp :validate llm-standard-provider-p)))
+(defvar spinner-types)
+
(defcustom ellama-spinner-type 'progress-bar
"Spinner type for ellama."
:group 'ellama
- :type `(choice ,@(mapcar
- (lambda (type)
- `(const ,(car type)))
- spinner-types)))
+ :type `(choice ,@(if (boundp 'spinner-types)
+ (mapcar
+ (lambda (type)
+ `(const ,(car type)))
+ spinner-types)
+ '(const progress-bar))))
+
+(defcustom ellama-spinner-enabled nil
+ "Enable spinner during text generation."
+ :group 'ellama
+ :type 'boolean)
(defcustom ellama-command-map
(let ((map (make-sparse-keymap)))
@@ -140,7 +147,7 @@ Make reasoning models more useful for many cases."
;; session
(define-key map (kbd "s l") 'ellama-load-session)
(define-key map (kbd "s r") 'ellama-session-rename)
- (define-key map (kbd "s d") 'ellama-session-remove)
+ (define-key map (kbd "s d") 'ellama-session-delete)
(define-key map (kbd "s a") 'ellama-session-switch)
;; improve
(define-key map (kbd "i w") 'ellama-improve-wording)
@@ -449,12 +456,6 @@ It should be a function with single argument generated
text string."
:group 'ellama
:type 'symbol)
-(defcustom ellama-long-lines-length 100
- "Long lines length for fill paragraph call.
-Too low value can break generated code by splitting long comment lines."
- :group 'ellama
- :type 'integer)
-
(defcustom ellama-translate-italic t
"Translate italic during markdown to org transformations."
:group 'ellama
@@ -494,6 +495,7 @@ Too low value can break generated code by splitting long
comment lines."
(define-minor-mode ellama-request-mode
"Minor mode for ellama buffers with active request to llm."
:interactive nil
+ :lighter " ellama:generating"
:keymap '(([remap keyboard-quit] . ellama--cancel-current-request-and-quit))
(if ellama-request-mode
(add-hook 'kill-buffer-hook 'ellama--cancel-current-request nil t)
@@ -522,8 +524,7 @@ Too low value can break generated code by splitting long
comment lines."
(if ellama-fill-paragraphs
(with-temp-buffer
(insert (propertize text 'hard t))
- (let ((fill-column ellama-long-lines-length)
- (use-hard-newlines t))
+ (let ((use-hard-newlines t))
(fill-region (point-min) (point-max) nil t t))
(buffer-substring-no-properties (point-min) (point-max)))
text))
@@ -587,8 +588,7 @@ Too low value can break generated code by splitting long
comment lines."
;; filling long lines
(goto-char beg)
(when ellama-fill-paragraphs
- (let ((fill-column ellama-long-lines-length)
- (use-hard-newlines t))
+ (let ((use-hard-newlines t))
(fill-region beg end nil t t))))
(defun ellama--replace-outside-of-code-blocks (text)
@@ -823,9 +823,12 @@ If EPHEMERAL non nil new session will not be associated
with any file."
(defun ellama--cancel-current-request ()
"Cancel current running request."
+ (declare-function spinner-stop "ext:spinner")
(when ellama--current-request
(llm-cancel-request ellama--current-request)
- (spinner-stop)
+ (when ellama-spinner-enabled
+ (require 'spinner)
+ (spinner-stop))
(setq ellama--current-request nil)))
(defun ellama--cancel-current-request-and-quit ()
@@ -953,27 +956,29 @@ If EPHEMERAL non nil new session will not be associated
with any file."
`((ignore .
(,ellama-chat-display-action-function)))))))
;;;###autoload
-(defun ellama-session-remove ()
- "Remove ellama session."
+(defun ellama-session-delete ()
+ "Delete ellama session."
(interactive)
(let* ((id (completing-read
"Select session to remove: "
(hash-table-keys ellama--active-sessions)))
(buffer (ellama-get-session-buffer id))
(file (buffer-file-name buffer))
- (session-file (ellama--get-session-file-name file))
- (translation-file (ellama--get-translation-file-name file)))
+ (session-file (when file (ellama--get-session-file-name file)))
+ (translation-file (when file (ellama--get-translation-file-name
file))))
(kill-buffer buffer)
- (delete-file file t)
- (delete-file session-file t)
+ (when file (delete-file file t))
+ (when session-file (delete-file session-file t))
(mapc
(lambda (buf)
- (when (and (buffer-file-name buf)
- (file-equal-p (buffer-file-name buf)
- translation-file))
+ (when (and
+ translation-file
+ (buffer-file-name buf)
+ (file-equal-p (buffer-file-name buf)
+ translation-file))
(kill-buffer buf)))
(buffer-list))
- (when (file-exists-p translation-file)
+ (when (and translation-file (file-exists-p translation-file))
(delete-file translation-file t))))
(defun ellama-activate-session (id)
@@ -996,39 +1001,44 @@ If EPHEMERAL non nil new session will not be associated
with any file."
(defun ellama-session-rename ()
"Rename current ellama session."
(interactive)
- (when-let* ((id (if ellama--current-session
- (ellama-session-id ellama--current-session)
- ellama--current-session-id))
- (buffer (ellama-get-session-buffer id))
- (session (with-current-buffer buffer
- ellama--current-session))
- (file-name (buffer-file-name buffer))
- (file-ext (file-name-extension file-name))
- (dir (file-name-directory file-name))
- (session-file-name (ellama--get-session-file-name file-name))
- (new-id (read-string
- "New session name: "
- id))
- (new-file-name (file-name-concat
- dir
- (concat new-id "." file-ext)))
- (new-session-file-name
- (ellama--get-session-file-name new-file-name)))
- (with-current-buffer buffer
- (set-visited-file-name new-file-name))
- (when (file-exists-p file-name)
+ (let* ((id (if ellama--current-session
+ (ellama-session-id ellama--current-session)
+ ellama--current-session-id))
+ (buffer (when id (ellama-get-session-buffer id)))
+ (session (when buffer (with-current-buffer buffer
+ ellama--current-session)))
+ (file-name (when buffer (buffer-file-name buffer)))
+ (file-ext (when file-name (file-name-extension file-name)))
+ (dir (when file-name (file-name-directory file-name)))
+ (session-file-name (when file-name (ellama--get-session-file-name
file-name)))
+ (new-id (read-string
+ "New session name: "
+ id))
+ (new-file-name (when dir (file-name-concat
+ dir
+ (concat new-id "." file-ext))))
+ (new-session-file-name
+ (when new-file-name (ellama--get-session-file-name new-file-name))))
+ (when new-file-name (with-current-buffer buffer
+ (set-visited-file-name new-file-name)))
+ (when buffer (with-current-buffer buffer
+ (rename-buffer (or new-file-name new-id))))
+ (when (and file-name (file-exists-p file-name))
(rename-file file-name new-file-name))
- (when (file-exists-p session-file-name)
+ (when (and session-file-name (file-exists-p session-file-name))
(rename-file session-file-name new-session-file-name))
- (setf (ellama-session-id session) new-id)
+ (when session (setf (ellama-session-id session) new-id))
(when (equal ellama--current-session-id id)
(setq ellama--current-session-id new-id))
(remhash id ellama--active-sessions)
- (puthash new-id buffer ellama--active-sessions)))
+ (puthash new-id buffer ellama--active-sessions)
+ (when (and buffer ellama-session-auto-save)
+ (with-current-buffer buffer
+ (save-buffer)))))
(defvar ellama--context-buffer " *ellama-context*")
-(defcustom ellama-context-posframe-enabled t
+(defcustom ellama-context-posframe-enabled nil
"Enable showing posframe with ellama context."
:group 'ellama
:type 'boolean)
@@ -1040,8 +1050,7 @@ If EPHEMERAL non nil new session will not be associated
with any file."
(setq ellama--global-context nil)
(with-current-buffer ellama--context-buffer
(erase-buffer))
- (when ellama-context-posframe-enabled
- (posframe-hide ellama--context-buffer)))
+ (ellama-update-context-show))
;; Context elements
@@ -1070,32 +1079,95 @@ If EPHEMERAL non nil new session will not be associated
with any file."
:group 'ellama
:type 'integer)
-(defcustom ellama-context-element-padding-size 20
- "Padding size for context elements."
- :group 'ellama
- :type 'integer)
-
-(defun ellama-update-context-posframe-show ()
- "Update and show context posframe."
+(defun ellama-update-context-show ()
+ "Update and show context in posframe of header line."
+ (declare-function posframe-show "ext:posframe")
+ (declare-function posframe-hide "ext:posframe")
+ (with-current-buffer ellama--context-buffer
+ (erase-buffer)
+ (when ellama--global-context
+ (insert (format
+ " ellama ctx: %s"
+ (string-join
+ (mapcar
+ (lambda (el)
+ (ellama-context-element-display el))
+ ellama--global-context)
+ " ")))))
(when ellama-context-posframe-enabled
- (with-current-buffer ellama--context-buffer
- (erase-buffer)
- (when ellama--global-context
- (insert (format
- "context: %s"
- (string-join
- (mapcar
- (lambda (el)
- (string-pad
- (ellama-context-element-display el)
ellama-context-element-padding-size))
- ellama--global-context)
- " ")))))
+ (require 'posframe)
(if ellama--global-context
(posframe-show
ellama--context-buffer
:poshandler ellama-context-poshandler
:internal-border-width ellama-context-border-width)
- (posframe-hide ellama--context-buffer))))
+ (posframe-hide ellama--context-buffer)))
+ (ellama-context-update-header-line))
+
+(defface ellama-face '((t (:inherit shadow)))
+ "Base face for all ellama things.")
+
+(defface ellama-context-line-face '((t (:inherit (mode-line-buffer-id
ellama-face))))
+ "Face for ellama context line.")
+
+(defun ellama-context-line ()
+ "Return current global context line."
+ (propertize (with-current-buffer ellama--context-buffer
+ (buffer-substring-no-properties
+ (point-min) (point-max)))
+ 'help-echo "mouse-1: manage ellama context"
+ 'mouse-face 'header-line-format
+ 'face 'ellama-context-line-face
+ 'keymap (let ((m (make-sparse-keymap)))
+ (define-key m [header-line mouse-1]
#'ellama-transient-context-menu)
+ (define-key m [mode-line mouse-1]
#'ellama-transient-context-menu)
+ m)))
+
+;;;###autoload
+(define-minor-mode ellama-context-header-line-mode
+ "Toggle Ellama Context header line mode."
+ :group 'ellama
+ (add-hook 'window-state-change-hook #'ellama-context-update-header-line)
+ (if ellama-context-header-line-mode
+ (ellama-context-update-header-line)
+ (setq header-line-format (delete '(:eval (ellama-context-line))
header-line-format))))
+
+;;;###autoload
+(define-globalized-minor-mode ellama-context-header-line-global-mode
+ ellama-context-header-line-mode
+ ellama-context-header-line-mode)
+
+(defun ellama-context-update-header-line ()
+ "Update and display context information in the header line."
+ (if (and ellama-context-header-line-mode ellama--global-context)
+ (add-to-list 'header-line-format '(:eval (ellama-context-line)) t)
+ (setq header-line-format (delete '(:eval (ellama-context-line))
header-line-format))))
+
+;;;###autoload
+(define-minor-mode ellama-context-mode-line-mode
+ "Toggle Ellama Context mode line mode."
+ :group 'ellama
+ (add-hook 'window-state-change-hook #'ellama-context-update-mode-line)
+ (if ellama-context-mode-line-mode
+ (ellama-context-update-mode-line)
+ (setq mode-line-format (delete '(:eval (ellama-context-line))
mode-line-format))))
+
+;;;###autoload
+(define-globalized-minor-mode ellama-context-mode-line-global-mode
+ ellama-context-mode-line-mode
+ ellama-context-mode-line-mode)
+
+(defun ellama-context-turn-on-mode-line-mode ()
+ "Turn on `ellama-context-mode-line-mode' if appropriate."
+ (when (or (eq major-mode 'text-mode)
+ (derived-mode-p 'text-mode))
+ (ellama-context-mode-line-mode 1)))
+
+(defun ellama-context-update-mode-line ()
+ "Update and display context information in the mode line."
+ (if (and ellama-context-mode-line-mode ellama--global-context)
+ (add-to-list 'mode-line-format '(:eval (ellama-context-line)) t)
+ (setq mode-line-format (delete '(:eval (ellama-context-line))
mode-line-format))))
(cl-defmethod ellama-context-element-add ((element ellama-context-element))
"Add the ELEMENT to the Ellama context."
@@ -1104,7 +1176,7 @@ If EPHEMERAL non nil new session will not be associated
with any file."
:test #'equal-including-properties)
(setf ellama--global-context (nreverse ellama--global-context))
(get-buffer-create ellama--context-buffer t)
- (ellama-update-context-posframe-show))
+ (ellama-update-context-show))
(defcustom ellama-manage-context-display-action-function
#'display-buffer-same-window
"Display action function for `ellama-render-context'."
@@ -1203,7 +1275,7 @@ If EPHEMERAL non nil new session will not be associated
with any file."
(when-let ((elt (get-text-property (point) 'context-element)))
(ellama-remove-context-element elt)
(ellama-manage-context)
- (ellama-update-context-posframe-show)))
+ (ellama-update-context-show)))
;; Buffer context element
@@ -1450,7 +1522,6 @@ If EPHEMERAL non nil new session will not be associated
with any file."
(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))
@@ -1803,6 +1874,8 @@ failure (with BUFFER current).
:on-done ON-DONE -- ON-DONE a function or list of functions that's called with
the full response text when the request completes (with BUFFER current)."
+ (declare-function spinner-start "ext:spinner")
+ (declare-function spinner-stop "ext:spinner")
(let* ((session-id (plist-get args :session-id))
(session (or (plist-get args :session)
(when session-id
@@ -1869,7 +1942,9 @@ failure (with BUFFER current).
(setq ellama--change-group (prepare-change-group))
(activate-change-group ellama--change-group)
(ellama-set-markers start end point)
- (spinner-start ellama-spinner-type)
+ (when ellama-spinner-enabled
+ (require 'spinner)
+ (spinner-start ellama-spinner-type))
(let ((request (llm-chat-streaming
provider
llm-prompt
@@ -1883,7 +1958,8 @@ failure (with BUFFER current).
text)))
(with-current-buffer buffer
(accept-change-group ellama--change-group)
- (spinner-stop)
+ (when ellama-spinner-enabled
+ (spinner-stop))
(if (and (listp donecb)
(functionp (car donecb)))
(mapc (lambda (fn) (funcall fn text))
@@ -1907,7 +1983,8 @@ failure (with BUFFER current).
(lambda (_ msg)
(with-current-buffer buffer
(cancel-change-group ellama--change-group)
- (spinner-stop)
+ (when ellama-spinner-enabled
+ (spinner-stop))
(funcall errcb msg)
(setq ellama--current-request nil)
(ellama-request-mode -1))))))
@@ -2944,7 +3021,7 @@ Call CALLBACK on result list of strings. ARGS contains
keys for fine control.
[["Session Commands"
("l" "Load Session" ellama-load-session)
("r" "Rename Session" ellama-session-rename)
- ("d" "Remove Session" ellama-session-remove)
+ ("d" "Delete Session" ellama-session-delete)
("a" "Activate Session" ellama-session-switch)]
["Quit" ("q" "Quit" transient-quit-one)]])
diff --git a/tests/test-ellama.el b/tests/test-ellama.el
index b88e2226ce..6b47022191 100644
--- a/tests/test-ellama.el
+++ b/tests/test-ellama.el
@@ -251,70 +251,70 @@
```tex
\\documentclass{article}
\\usepackage{tikz} \\begin{document}
-\\begin{tikzpicture} \\node[rectangle, draw=blue, fill=blue!20] (mynode)
{Text};
+\\begin{tikzpicture} \\node[rectangle, draw=blue] (mynode) {Text};
\\end{tikzpicture}
\\end{document}
```
This code will create a rectangle with a blue border and light
-blue filling. You can replace \'Text\' with your desired text or other TikZ
-elements.")))
+blue filling. You can replace \'Text\' with your desired text
+or other TikZ elements.")))
(should (string-equal result "Here is your TikZ code for a blue rectangle:
#+BEGIN_SRC tex
\\documentclass{article}
\\usepackage{tikz} \\begin{document}
-\\begin{tikzpicture} \\node[rectangle, draw=blue, fill=blue!20] (mynode)
{Text};
+\\begin{tikzpicture} \\node[rectangle, draw=blue] (mynode) {Text};
\\end{tikzpicture}
\\end{document}
#+END_SRC
This code will create a rectangle with a blue border and light
-blue filling. You can replace \'Text\' with your desired text or other TikZ
-elements."))))
+blue filling. You can replace \'Text\' with your desired text
+or other TikZ elements."))))
(ert-deftest test-ellama-md-to-org-code-hard ()
(let ((result (ellama--translate-markdown-to-org-filter "Here is your TikZ
code for a blue rectangle:
```
\\documentclass{article}
\\usepackage{tikz} \\begin{document}
-\\begin{tikzpicture} \\node[rectangle, draw=blue, fill=blue!20] (mynode)
{Text};
+\\begin{tikzpicture} \\node[rectangle, draw=blue] (mynode) {Text};
\\end{tikzpicture}
\\end{document}
```
This code will create a rectangle with a blue border and light
-blue filling. You can replace \'Text\' with your desired text or other TikZ
-elements.")))
+blue filling. You can replace \'Text\' with your desired text or other
+TikZ elements.")))
(should (string-equal result "Here is your TikZ code for a blue rectangle:
#+BEGIN_SRC
\\documentclass{article}
\\usepackage{tikz} \\begin{document}
-\\begin{tikzpicture} \\node[rectangle, draw=blue, fill=blue!20] (mynode)
{Text};
+\\begin{tikzpicture} \\node[rectangle, draw=blue] (mynode) {Text};
\\end{tikzpicture}
\\end{document}
#+END_SRC
This code will create a rectangle with a blue border and light
-blue filling. You can replace \'Text\' with your desired text or other TikZ
-elements."))))
+blue filling. You can replace \'Text\' with your desired text or other
+TikZ elements."))))
(ert-deftest test-ellama-md-to-org-code-nightmare ()
(let ((result (ellama--translate-markdown-to-org-filter "Here is your TikZ
code for a blue rectangle:
```
\\documentclass{article}
\\usepackage{tikz} \\begin{document}
-\\begin{tikzpicture} \\node[rectangle, draw=blue, fill=blue!20] (mynode)
{Text};
+\\begin{tikzpicture} \\node[rectangle, draw=blue] (mynode) {Text};
\\end{tikzpicture}
\\end{document}```This code will create a rectangle with a blue border and
light
-blue filling. You can replace \'Text\' with your desired text or other TikZ
-elements.")))
+blue filling. You can replace \'Text\' with your desired text
+or other TikZ elements.")))
(should (string-equal result "Here is your TikZ code for a blue rectangle:
#+BEGIN_SRC
\\documentclass{article}
\\usepackage{tikz} \\begin{document}
-\\begin{tikzpicture} \\node[rectangle, draw=blue, fill=blue!20] (mynode)
{Text};
+\\begin{tikzpicture} \\node[rectangle, draw=blue] (mynode) {Text};
\\end{tikzpicture}
\\end{document}
#+END_SRC
This code will create a rectangle with a blue border and light
-blue filling. You can replace \'Text\' with your desired text or other TikZ
-elements."))))
+blue filling. You can replace \'Text\' with your desired text
+or other TikZ elements."))))
(ert-deftest test-ellama-md-to-org-code-multiple-bad-blocks ()
(let ((result (ellama--translate-markdown-to-org-filter "Some text:
@@ -380,7 +380,8 @@ $P_\\theta$
(should (string-equal result "This"))))
(ert-deftest test-ellama-md-to-org-code-snake-case ()
- (let ((result (ellama--translate-markdown-to-org-filter "```python
+ (let* ((fill-column 70)
+ (result (ellama--translate-markdown-to-org-filter "```python
# Example of snake case variables and functions
# Variable names using snake_case
@@ -407,27 +408,7 @@ In this example:
- The function name `calculate_average_score` also follows the snake_case
convention.
Snake case helps improve readability, especially in languages that are
sensitive to capitalization like Python.")))
- (should (string-equal result "#+BEGIN_SRC python
-# Example of snake case variables and functions
-
-# Variable names using snake_case
-student_name = \"Alice Johnson\"
-class_name = \"Mathematics\"
-grade_level = 10
-
-# Function name using snake_case
-def calculate_average_score(math_score, science_score, english_score):
- average_score = (math_score + science_score + english_score) / 3
- return average_score
-
-# Using the function
-student_math_score = 85
-student_science_score = 90
-student_english_score = 78
-
-average_score = calculate_average_score(student_math_score,
student_science_score, student_english_score)
-print(f\"The average score of {student_name} in {class_name} is:
{average_score:.2f}\")
-#+END_SRC\n\nIn this example:\n- Variable names like ~student/name~,
~class/name~, and ~grade/level~ use snake/case.\n- The function name
~calculate/average/score~ also follows the snake_case convention.\n\nSnake case
helps improve readability, especially in languages that are sensitive to
capitalization\nlike Python."))))
+ (should (string-equal result "#+BEGIN_SRC python\n# Example of snake case
variables and functions\n\n# Variable names using snake_case\nstudent_name =
\"Alice Johnson\"\nclass_name = \"Mathematics\"\ngrade_level = 10\n\n# Function
name using snake_case\ndef calculate_average_score(math_score, science_score,
english_score):\n average_score = (math_score + science_score +
english_score) / 3\n return average_score\n\n# Using the
function\nstudent_math_score = 85\nstudent_science_s [...]
(ert-deftest test-ellama--fix-file-name ()
(should (string=