Skip to content

Commit ecf9d22

Browse files
authored
Merge pull request #225 from agzam/add-workspace-remove-command
Support removing workspace folders from a running session
2 parents 7b8085c + 2786900 commit ecf9d22

3 files changed

Lines changed: 68 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
- Add `eca-chat-remove-workspace-root` command and `[-]` mode-line button to remove a workspace folder from a running session. Both 'add' and 'remove' is in the transient menu (`W a` / `W r`).
56
- Add `eca-chat-mode-line-format` for customizable chat mode line layout. #184
67
- Fix top-level `(require 'tab-line)` causing side effects when `eca-chat-tab-line` is nil. #195
78
- Add support for `chat/opened` server notification, enabling the `/fork` command to open forked chats as new tabs.

eca-chat.el

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ Must be a valid model supported by server, check `eca-chat-select-model`."
167167
:group 'eca)
168168

169169
(defcustom eca-chat-mode-line-format
170-
'(:workspace-folders :add-workspace-button :spacer :init-progress " " :bg-jobs " " :elapsed-time " " :usage " " :trust)
170+
'(:workspace-folders :add-workspace-button :remove-workspace-button :spacer :init-progress " " :bg-jobs " " :elapsed-time " " :usage " " :trust)
171171
"Format for the ECA chat mode line.
172172
173173
When set to a list, each element is a module keyword or a
@@ -177,6 +177,7 @@ to separate left-aligned and right-aligned content.
177177
Available modules:
178178
`:workspace-folders' - project root paths
179179
`:add-workspace-button' - clickable [+] button
180+
`:remove-workspace-button' - clickable [-] button
180181
`:title' - chat title
181182
`:elapsed-time' - turn duration timer
182183
`:usage' - token/cost info (see `eca-chat-usage-string-format')
@@ -196,6 +197,7 @@ This gives full control for powerline or doom-modeline users."
196197
(string :tag "Literal string")
197198
(const :tag "Workspace folders" :workspace-folders)
198199
(const :tag "Add workspace button" :add-workspace-button)
200+
(const :tag "Remove workspace button" :remove-workspace-button)
199201
(const :tag "Background jobs" :bg-jobs)
200202
(const :tag "Chat title" :title)
201203
(const :tag "Elapsed time" :elapsed-time)
@@ -1762,13 +1764,38 @@ E is the mouse event."
17621764
(eca--session-add-workspace-folder session folder)
17631765
(force-mode-line-update))))
17641766

1767+
(defun eca-chat-remove-workspace-root ()
1768+
"Prompt for a workspace folder to remove from the current session.
1769+
Refuses when only one folder remains. In `merged' worktree mode, a
1770+
removed folder sharing its git-common-dir with another session folder
1771+
may be auto-re-added on the next buffer visit."
1772+
(interactive)
1773+
(when-let ((session (eca-session)))
1774+
(let ((folders (eca--session-workspace-folders session)))
1775+
(cond
1776+
((null folders)
1777+
(user-error "No workspace folders to remove"))
1778+
((<= (length folders) 1)
1779+
(user-error "Cannot remove the last workspace folder"))
1780+
(t
1781+
(let ((folder (completing-read "Remove workspace: " folders nil t)))
1782+
(eca--session-remove-workspace-folder session folder)
1783+
(force-mode-line-update)))))))
1784+
17651785
(defvar eca-chat--add-workspace-map
17661786
(let ((map (make-sparse-keymap)))
17671787
(define-key map [mode-line mouse-1]
17681788
#'eca-chat-add-workspace-root)
17691789
map)
17701790
"Keymap for the modeline [+] workspace button.")
17711791

1792+
(defvar eca-chat--remove-workspace-map
1793+
(let ((map (make-sparse-keymap)))
1794+
(define-key map [mode-line mouse-1]
1795+
#'eca-chat-remove-workspace-root)
1796+
map)
1797+
"Keymap for the modeline [-] workspace button.")
1798+
17721799
(defvar eca-chat--trust-toggle-map
17731800
(let ((map (make-sparse-keymap)))
17741801
(define-key map [mode-line mouse-1]
@@ -1813,6 +1840,12 @@ are in progress."
18131840
'mouse-face 'highlight
18141841
'help-echo "Add workspace folder"
18151842
'local-map eca-chat--add-workspace-map))
1843+
(:remove-workspace-button
1844+
(propertize " [-]"
1845+
'face 'shadow
1846+
'mouse-face 'highlight
1847+
'help-echo "Remove workspace folder"
1848+
'local-map eca-chat--remove-workspace-map))
18161849
(:bg-jobs
18171850
(when-let* ((jobs (eca--session-jobs session))
18181851
(running (seq-count (lambda (j) (string= "running" (plist-get j :status))) jobs)))

eca-util.el

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,34 @@ workspace folders. Returns nil otherwise."
192192
:removed [])))
193193
(eca-info "Added workspace folder: %s" folder))))
194194

195+
(defun eca--session-remove-workspace-folder (session folder)
196+
"Remove FOLDER from SESSION's workspace-folders and notify the server.
197+
Refuses to remove the last remaining folder, since the Emacs client
198+
resolves buffers to sessions by matching against workspace-folders and
199+
an empty list would make the session unreachable. In `merged' worktree
200+
mode, a removed folder whose git-common-dir still matches another
201+
folder in the session can be auto-re-added by `eca-session' the next
202+
time a buffer under it is visited."
203+
(let* ((folder (expand-file-name folder))
204+
(folders (eca--session-workspace-folders session)))
205+
(cond
206+
((not (--first (string= it folder) folders))
207+
(eca-warn "Workspace folder not found: %s" folder))
208+
((<= (length folders) 1)
209+
(user-error "Cannot remove the last workspace folder"))
210+
(t
211+
(setf (eca--session-workspace-folders session)
212+
(cl-remove-if (lambda (it) (string= it folder)) folders))
213+
(eca-api-notify
214+
session
215+
:method "workspace/didChangeWorkspaceFolders"
216+
:params (list :event
217+
(list :added []
218+
:removed (vector
219+
(list :uri (eca--path-to-uri folder)
220+
:name (file-name-nondirectory (directory-file-name folder)))))))
221+
(eca-info "Removed workspace folder: %s" folder)))))
222+
195223
(defun eca-session ()
196224
"Return the session related to root of current buffer otherwise nil."
197225
(or (eca-get eca--sessions eca--session-id-cache)
@@ -327,7 +355,11 @@ Inheirits BASE-MAP."
327355

328356
["Server"
329357
("S r" "Restart" eca-restart)
330-
("S s" "Stop" eca-stop)]]))
358+
("S s" "Stop" eca-stop)]
359+
360+
["Workspace"
361+
("W a" "Add folder" eca-chat-add-workspace-root)
362+
("W r" "Remove folder" eca-chat-remove-workspace-root)]]))
331363

332364
(defun eca-transient-menu ()
333365
"Open the ECA transient menu.

0 commit comments

Comments
 (0)