-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
emacs.clj
163 lines (144 loc) · 5.84 KB
/
emacs.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
(ns ralphie.emacs
(:require
[ralphie.notify :as notify :refer [notify]]
[babashka.process :as process :refer [$ check]]
[clojure.string :as string]
[babashka.fs :as fs]
[ralphie.zsh :as zsh]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; emacs server/client fns
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn emacs-server-running? []
(try
(-> ($ emacsclient -a false -e 't')
check :out slurp string/trim (= "t"))
(catch Exception _e
false)))
(defn initialize-emacs-server []
(->
(process/$ systemctl restart --user emacs)
(process/check))
;; (r.sh/zsh
;; (str "emacsclient --alternate-editor='' --no-wait --create-frame"
;; " -e '(delete-frame)'"))
)
(defn fire
"Expects a string, passes it to emacsclient --eval."
[form]
(-> ($ emacsclient --eval ~form)
check))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Open emacs client for passed workspace
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def fallback-default-files
["readme.md"
"readme.org"
"deps.edn"
"shadow-cljs.edn"
"package.json"
"bb.edn"])
(defn determine-initial-file
"Initial-file should be a file in the workspace repo's root.
If it exists, it is returned.
If it does not exist, sibling `fallback-default-files` are sought out.
The first to exist is used.
"
[initial-file]
(when initial-file
(let [initial-file (if (string/starts-with? initial-file "~")
(zsh/expand initial-file)
initial-file)]
(if (and (fs/exists? initial-file) (not (fs/directory? initial-file)))
initial-file
(if-let [dir (if (fs/directory? initial-file)
initial-file
(fs/parent initial-file))]
(let [lower-case-f->f (->> (fs/list-dir dir)
(map str)
(map (fn [f] [(string/lower-case f) f]))
(into {}))]
;; TODO refactor to partial match on fallbacks, or support a fn/includes for that
(->> fallback-default-files
(map #(str (string/lower-case dir) "/" %))
(filter lower-case-f->f)
first
lower-case-f->f))
(println "deter initial file fail" initial-file))))))
(comment
(determine-initial-file (zsh/expand "~/russmatney/clawe/some.blah"))
(determine-initial-file (zsh/expand "~/russmatney/clawe"))
(fs/directory? (zsh/expand "~/russmatney/clawe"))
(determine-initial-file (zsh/expand "~/borkdude/babashka/readme.org")))
(defn open
"Opens a new emacs client in the passed workspace.
Uses the passed workspace data to direct emacs to the relevant initial file
and named emacs workspace."
{:org.babashka/cli
{:alias {:wsp :workspace/title
:file :emacs.open/file}}}
([] (open nil))
([wsp]
(try
(let [wsp (or wsp {})
wsp-name
(or (some wsp [:emacs.open/workspace
:workspace/title :org/name :clawe.defs/name])
"ralphie-fallback")
initial-file (some wsp [:emacs.open/file :emacs.open/directory])
initial-file (determine-initial-file initial-file)
elisp-hook (:emacs.open/elisp-hook wsp)
eval-str (str
"(progn "
;; TODO refactor russ/open-workspace to support initial-file
;; so that we don't open the readme when the workspace is already open
(when wsp-name
(str " (russ/open-workspace \"" wsp-name "\") "))
(when initial-file
(str " (find-file \"" initial-file "\") " " "))
(when elisp-hook elisp-hook)
" )")]
(when-not (emacs-server-running?)
(notify {:notify/subject "Initializing Emacs Server, initializing."
:notify/replaces-process "init-emacs-server"})
(initialize-emacs-server)
(notify {:notify/subject "Started Emacs Server"
:notify/replaces-process "init-emacs-server"}))
(-> ($ emacsclient --no-wait --create-frame
-F ~(str "((name . \"" wsp-name "\"))")
--display=:0
--eval ~eval-str)
check))
;; TODO proper clawe error log
(catch Exception e
(notify/notify "emacs/open error" (str e))
(println e)))))
(comment
(open {:emacs.open/workspace "clawe"
:emacs.open/file (zsh/expand "~/russmatney/clawe/readme.org")}))
(defn open-in-emacs-str [opts]
(let [file-path (some opts [:emacs/file-path])
frame-name (:emacs/frame-name opts)]
(str
"(progn "
(when frame-name (str
"\n(let ((named-frame (car
(filtered-frame-list (lambda (frame) (equal (frame-parameter frame 'name) \"" frame-name "\"))))))
(if named-frame
(select-frame named-frame)))"))
(when file-path (str "\n(find-file \"" file-path "\") " " ")) " )")))
(comment
(open-in-emacs-str
{:emacs/file-path "some-file-path"
:emacs/frame-name "journal"}))
;; TODO is this redundant with `emacs/open` above? the above creates a new client, maybe this name should change
(defn open-in-emacs
"Opens a file in the last-focused existing emacs client.
Expects an absolute file-path."
[opts]
(let [eval-str (open-in-emacs-str opts)]
(-> ($ emacsclient --no-wait --eval ~eval-str)
check)))
(comment
(def --file "/Users/russ/russmatney/clawe/src/api/emacs.clj")
(open-in-emacs
{:emacs/file-path --file}))