Skip to content

Commit d7632c8

Browse files
committed
Open the global config file the server reads (#321)
On Windows without HOME, Emacs expands ~ to %APPDATA% while the server resolves user.home to the user profile dir, so eca-open-global-config edited a file the server never read. Use the globalConfigPath now sent in the initialize response, mapping it through TRAMP for remote sessions, and make the fallback for older servers resolve the home dir like the server does.
1 parent 0dc74a8 commit d7632c8

5 files changed

Lines changed: 116 additions & 5 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+
- Bugfix: `eca-open-global-config` edited a file the server never reads on Windows when `HOME` is unset (#321), since Emacs defaults `HOME` to `%APPDATA%` while the server uses the user profile directory. The path now comes from the server's `initialize` response (`globalConfigPath`), translated through TRAMP for remote sessions; with older servers the local fallback resolves the home directory like the server does.
56
- Bugfix: new chat buffers now get the session's first workspace folder as `default-directory` (#323). It was inherited from whichever buffer was current when the buffer got created, which for a new session is the async `initialize` response, so `(let ((default-directory dir)) (eca))` wrappers ended up with the chat rooted in the previous buffer's directory.
67
- User messages in the chat now stand out as a turn marker (#265): `eca-chat-user-messages-face` is bold on the theme-derived block background instead of `font-lock-doc-face`, painted over the whole message so markdown spans in it keep the background, and an empty line separates the message from the previous answer.
78
- `eca-workspaces-new-chat` (`+`) now always asks which workspace to start the chat in, defaulting to the one at point, and no longer requires a match: any other existing directory starts a session there. Typing a path inside a running workspace reuses its session instead of starting a second server.

‎eca-config.el‎

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
;;
1313
;;; Code:
1414

15+
(require 'dash)
1516
(require 'f)
1617

1718
(require 'eca-util)
@@ -21,11 +22,42 @@
2122

2223
;; Paths
2324

24-
(defun eca-config--global-path ()
25-
"Return the path to the global ECA config file."
26-
(if-let (xdg (getenv "XDG_CONFIG_HOME"))
25+
(defun eca-config--home-directory ()
26+
"Return the home directory the ECA server resolves.
27+
The server uses the JVM `user.home', which on Windows is the user
28+
profile directory even when HOME is unset, while Emacs defaults
29+
HOME to %APPDATA% in that case."
30+
(or (and (eq system-type 'windows-nt)
31+
(getenv "USERPROFILE"))
32+
(f-expand "~")))
33+
34+
(defun eca-config--local-global-path ()
35+
"Resolve the global ECA config path the same way the server does."
36+
(if-let* ((xdg (getenv "XDG_CONFIG_HOME")))
2737
(f-join xdg "eca" "config.json")
28-
(f-join (f-expand "~") ".config" "eca" "config.json")))
38+
(f-join (eca-config--home-directory) ".config" "eca" "config.json")))
39+
40+
(defun eca-config--server-path-to-local (path session)
41+
"Translate PATH reported by the server of SESSION to a local path.
42+
Applies the session path mappings; when the workspace folders are
43+
remote and no mapping applied, reuse their TRAMP prefix so the file
44+
is opened on the host running the server."
45+
(let* ((eca--path-session session)
46+
(local (eca--path-remote-to-local path)))
47+
(if-let* ((remote (and (string= local path)
48+
(-some #'file-remote-p
49+
(eca--session-workspace-folders session)))))
50+
(concat remote path)
51+
local)))
52+
53+
(defun eca-config--global-path (&optional session)
54+
"Return the path to the global ECA config file.
55+
Prefer the path the server of SESSION reported in the `initialize'
56+
response, so the buffer edits the file the server actually reads.
57+
Fall back to resolving it locally for servers without support."
58+
(if-let* ((path (and session (eca--session-global-config-path session))))
59+
(eca-config--server-path-to-local path session)
60+
(eca-config--local-global-path)))
2961

3062
;; Helpers
3163

@@ -81,7 +113,7 @@ SESSION is the current ECA session. PATH is the config file."
81113
(defun eca-config--create-global-buffer (session)
82114
"Create the Global Config settings tab buffer for SESSION."
83115
(eca-config--create-buffer "global-config" session
84-
(eca-config--global-path)))
116+
(eca-config--global-path session)))
85117

86118
;; Refresh
87119

‎eca-util.el‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ Each function receives the session being deleted.")
146146
;; The welcome message for new chats.
147147
(chat-welcome-message "")
148148

149+
;; The global config file path the server reads, from `initialize'.
150+
(global-config-path nil)
151+
149152
;; Init progress tasks alist: (taskId . plist) where plist has :title :type
150153
(init-tasks nil)
151154

‎eca.el‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ is only usable asynchronously."
333333
:success-callback (-lambda (res)
334334
(setf (eca--session-status session) 'started)
335335
(setf (eca--session-chat-welcome-message session) (plist-get res :chatWelcomeMessage))
336+
(setf (eca--session-global-config-path session) (plist-get res :globalConfigPath))
336337
(eca-api-notify session :method "initialized")
337338
(eca-info "Started with workspaces: %s" (string-join (eca--session-workspace-folders session) ","))
338339
(eca-chat-open session)

‎test/eca-config-test.el‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
;;; eca-config-test.el --- Tests for eca-config -*- lexical-binding: t; -*-
2+
;;; Commentary:
3+
;;; Code:
4+
5+
(require 'buttercup)
6+
(require 'f)
7+
(require 'eca-util)
8+
(require 'eca-config)
9+
10+
(defvar eca-local-to-remote-prefix-map)
11+
12+
(defun eca-config-test--env (&rest vars)
13+
"Return `process-environment' with VARS prepended.
14+
A VAR of the form \"NAME=VALUE\" sets NAME, a bare \"NAME\" unsets it."
15+
(append vars process-environment))
16+
17+
(describe "eca-config--global-path"
18+
(describe "with the path reported by the server"
19+
(it "uses it over the local resolution"
20+
(let ((session (make-eca--session
21+
:global-config-path "/srv/home/.config/eca/config.json"
22+
:workspace-folders '("/srv/project")))
23+
(eca-local-to-remote-prefix-map nil)
24+
(process-environment (eca-config-test--env "XDG_CONFIG_HOME=/tmp/xdg")))
25+
(expect (eca-config--global-path session)
26+
:to-equal "/srv/home/.config/eca/config.json")))
27+
28+
(it "applies the explicit prefix map"
29+
(let ((session (make-eca--session
30+
:global-config-path "/root/.config/eca/config.json"
31+
:workspace-folders '("/Users/me/dev/project")))
32+
(eca-local-to-remote-prefix-map
33+
'(("/Users/me/eca-home" . "/root/.config/eca"))))
34+
(expect (eca-config--global-path session)
35+
:to-equal (expand-file-name "/Users/me/eca-home/config.json"))))
36+
37+
(it "reuses the TRAMP prefix of remote workspace folders"
38+
(let ((session (make-eca--session
39+
:global-config-path "/home/me/.config/eca/config.json"
40+
:workspace-folders '("/docker:container:/workspace/project")))
41+
(eca-local-to-remote-prefix-map nil))
42+
(expect (eca-config--global-path session)
43+
:to-equal "/docker:container:/home/me/.config/eca/config.json")))
44+
45+
(it "does not prefix a path already translated from a TRAMP folder"
46+
(let ((session (make-eca--session
47+
:global-config-path "/workspace/project/eca/config.json"
48+
:workspace-folders '("/docker:container:/workspace/project")))
49+
(eca-local-to-remote-prefix-map nil))
50+
(expect (eca-config--global-path session)
51+
:to-equal "/docker:container:/workspace/project/eca/config.json"))))
52+
53+
(describe "without a path from the server"
54+
(it "falls back to XDG_CONFIG_HOME when set"
55+
(let ((process-environment (eca-config-test--env "XDG_CONFIG_HOME=/tmp/xdg")))
56+
(expect (eca-config--global-path (make-eca--session))
57+
:to-equal (f-join "/tmp/xdg" "eca" "config.json"))))
58+
59+
(it "falls back to ~/.config/eca/config.json"
60+
(let ((system-type 'gnu/linux)
61+
(process-environment (eca-config-test--env "XDG_CONFIG_HOME"
62+
"USERPROFILE=/Users/other")))
63+
(expect (eca-config--global-path)
64+
:to-equal (f-join (f-expand "~") ".config" "eca" "config.json"))))
65+
66+
(it "uses USERPROFILE on Windows like the server's user.home"
67+
(let ((system-type 'windows-nt)
68+
(process-environment (eca-config-test--env "XDG_CONFIG_HOME"
69+
"USERPROFILE=/Users/me")))
70+
(expect (eca-config--global-path)
71+
:to-equal (f-join "/Users/me" ".config" "eca" "config.json"))))))
72+
73+
(provide 'eca-config-test)
74+
;;; eca-config-test.el ends here

0 commit comments

Comments
 (0)