-
Notifications
You must be signed in to change notification settings - Fork 0
/
tag-eshell.html
318 lines (298 loc) · 14.1 KB
/
tag-eshell.html
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="alternate"
type="application/rss+xml"
href="https://www.birkey.co/rss.xml"
title="RSS feed for https://www.birkey.co/">
<title>BirkeyCo</title>
<link href="static/style.css" rel="stylesheet" type="text/css" />
<link rel="apple-touch-icon" sizes="180x180" href="static/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="static/safari-pinned-tab.svg" color="#5bbad5">
<link rel="alternate" type="application/rss+xml" title="RSS Feed for birkey.co" href="/rss.xml">
<meta name="author" content="Kasim Tuman">
<meta name="referrer" content="no-referrer">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8">
<meta name="viewport" content="initial-scale=1,width=device-width,minimum-scale=1">
</head>
<body>
<div id="preamble" class="status"><br><center>
<div style="display: inline-block; vertical-align:middle;">
<a href="https://www.birkey.co/index.html" style="text-decoration: none;"><b>BIRKEY CONSULTING</b><br>
</a><hr/><div style="text-align: justify;display: inline-block; width: 100%;">
<a class="title" href="https://github.com/oneness">ABOUT</a> <a class="title" href="https://www.birkey.co/rss.xml">RSS</a> <a class="title" href="https://www.birkey.co/archive.html">ARCHIVE</a></div></div>
</center><br><br>
<div style="margin-bottom: 3ch;text-transform: none;"></div></div>
<div id="content">
<h1 class="title">Posts tagged "eshell":</h1>
<div class="post-date">01 Aug 2021</div><h1 class="post-title"><a href="https://www.birkey.co/2021-08-01-why-eshell-part-5.html">Why Eshell? - Part 5</a></h1>
<p>
One of the feature of Eshell that took me sometime to really
appreciate is its built-in ability to emulate Plan9 smart Shell. It
allows you to run a script or a command, run it again by just hitting
enter key after you modify it, say you made a mistake or want to
change part of it using Emacs editing power. You might say that you
can do same thing in any terminal using your up arrow key and command
line editing. But I challenge you to try it until you fully realize
the advantage you have vs regular terminal. Below is a simple screen
recording to show you what I mean:
</p>
<figure id="orgf663aab">
<img src="https://www.birkey.co/images/eshell-plan9-smart-shell.gif" alt="eshell-plan9-smart-shell.gif">
</figure>
<p>
I recommend you read following post to learn more about smart shell
and more about eshell including aliases:
<a href="https://masteringemacs.org/article/complete-guide-mastering-eshell">https://masteringemacs.org/article/complete-guide-mastering-eshell</a>.
</p>
<p>
This concludes my `Why Eshell` series. Hope you find it useful and
happy Eshelling!
</p>
<div class="taglist"><a href="https://www.birkey.co/tags.html">Tags</a>: <a href="https://www.birkey.co/tag-eshell.html">eshell</a> <a href="https://www.birkey.co/tag-emacs.html">emacs</a> </div>
<div class="post-date">17 Jul 2021</div><h1 class="post-title"><a href="https://www.birkey.co/2021-07-17-why-eshell-part-4.html">Why Eshell? - part 4</a></h1>
<p>
Since eshell buffer is just a regular emacs buffer, we have all of the
emacs power at our disposal. In part 3 of my post, I briefly alluded
to multiple terminal management by just using few lines of elisp and
all without using any third party packages. I am posting the main elisp
function for posterity here:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(defun krun (cmd)
(interactive
(list
(ido-completing-read
"Enter cmd to run (append ##name for buffer name): "
(let ((history nil))
;; We have to build up a list ourselves from the ring vector.
(dotimes (index (ring-length keshell-history-global-ring))
(push (ring-ref keshell-history-global-ring index) history))
;; Show them most-recent-first.
(setq history (nreverse history))))))
(let* ((cmds (split-string cmd "##"))
(tag (or (-> cmds second)
"kshell"))
(buff-name (-> tag s-chomp s-trim)))
(kshell cmd buff-name)))
</pre>
</div>
<p>
The above function (along with those from the previous post) will
allow you to do following:
</p>
<ul class="org-ul">
<li>Start a new shell with a specific name by just appending
##buffer-name after the command</li>
<li>Run a command from history or new command in a dedicated eshell
buffer, which defaults to <b>kshell</b>. You can override as any name you
want.</li>
<li>Use all hotkeys, interactive lisp functions as you would for regular
emacs buffer. For example, you can do buffer switching, ibuffer
management, isearch, protect a buffer from being killed, etc.</li>
</ul>
<p>
Following demonstrates above cases I am talking about:
</p>
<figure id="org7fae62d">
<img src="https://www.birkey.co/images/eshell-buffer-management.gif" alt="eshell-buffer-management.gif">
</figure>
<div class="taglist"><a href="https://www.birkey.co/tags.html">Tags</a>: <a href="https://www.birkey.co/tag-eshell.html">eshell</a> <a href="https://www.birkey.co/tag-emacs.html">emacs</a> </div>
<div class="post-date">10 Jul 2021</div><h1 class="post-title"><a href="https://www.birkey.co/2021-07-10-why-eshell-part-3.html">Why Eshell? - Part 3</a></h1>
<p>
If you have been following my `Why Eshell` series, you might be
wondering about interactive ido completion for eshell. Since Eshell
buffer is just a regular emacs buffer, we can compose few emacs
builtin functionalities to bend it to our command line work flow.
Following is all the code you need. Note that it is heavily commented
so you can understand what is happening.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(defun kshell-with-name (&optional name)
;; creates an eshell buffer with `kshell' as the default name. Take
;; optional name to override
(let ((m (->> (or name "kshell")
(format "*%s*"))))
(if (get-buffer m)
(pop-to-buffer m)
(progn
(eshell)
(rename-buffer m)))))
(defun kshell (&optional cmd buff-name send-input)
;; interactive fn that you can call via M-x or hotkey. It detects
;; current project root to start eshell buffer if no `buff-name' is
;; given. You can control how the `cmd` gets insert only or insert
;; and executed using `send-input` flag. Ex. Useful for further
;; editing.
(interactive)
(let ((dir (projectile-project-root))) ;; you need projectile
(if buff-name
(kshell-with-name buff-name)
(kshell-with-name))
(eshell/clear-scrollback)
(insert (format "cd %s" (or dir "~/")))
(eshell-send-input)
(insert (format "%s" cmd))
(when send-input (eshell-send-input))))
(defun krun (cmd)
;; eshell command history with ido completion. Assign it to a hot
;; key say, F12 and you will get a search-able command history that
;; you can execute just by doing ido interactive search.
(interactive
(list
(ido-completing-read
"Enter cmd to run (append ##name for buffer name): "
(let ((history nil))
;; We have to build up a list ourselves from the ring vector.
(dotimes (index (ring-length keshell-history-global-ring))
(push (ring-ref keshell-history-global-ring index) history))
;; Show them most-recent-first.
(setq history (nreverse history))))))
(let* ((cmds (split-string cmd "##")) ;; you need s.el lib
(tag (or (-> cmds second)
"kshell"))
(buff-name (-> tag s-chomp s-trim)))
(kshell cmd buff-name)))
</pre>
</div>
<p>
Here is the screen recording in action:
</p>
<figure id="org5159e5f">
<img src="https://www.birkey.co/images/eshell-ido-interactive.gif" alt="eshell-ido-interactive.gif">
</figure>
<p>
I am using F12 to invoke `krun` and my cross session eshell history
shows up in the minibuffer where I can use ido completion to select a
command that I can run. As an added benefit, above code allows one to
bring a eshell buffer with specific name by adding ##name at the end
of the command if one wants to have the command run in a dedicated
buffer.
</p>
<div class="taglist"><a href="https://www.birkey.co/tags.html">Tags</a>: <a href="https://www.birkey.co/tag-eshell.html">eshell</a> <a href="https://www.birkey.co/tag-emacs.html">emacs</a> </div>
<div class="post-date">27 Jun 2021</div><h1 class="post-title"><a href="https://www.birkey.co/2021-06-27-why-eshell-part-2.html">Why Eshell? - Part 2</a></h1>
<p>
Among many reasons of why I use eshell as my main terminal, I listed
following in part 1 of my `Why Eshell?` series blog post. I am listing
it here for posterity:
</p>
<ol class="org-ol">
<li><b>Long running command notification and time</b></li>
<li><b>Cross session history</b></li>
<li><b>Interactive ido completion</b></li>
<li><b>Unified interface (shell prompt buffer as regular emacs buffer)</b></li>
<li><b>Plan9 Style Shell prompt (Think of it as bash REPL)</b></li>
<li><b>Multiple terminal management</b></li>
<li><b>Super charge bash with elisp</b></li>
<li><b>Eshell aliases that puts bash aliases to shame :)</b></li>
</ol>
<p>
I addressed first point here: <a href="https://www.birkey.co/2021-06-20-why-eshell-part-1.html">notification and time</a>. Let me address
second point, which is sharing eshell history across many terminal
sessions.
</p>
<div class="org-src-container">
<pre class="src src-elisp">(defvar keshell-history-global-ring nil
"The history ring shared across Eshell sessions.")
(defun keshell-hist-use-global-history ()
"Make Eshell history shared across different sessions."
(unless keshell-history-global-ring
(when eshell-history-file-name
(eshell-read-history nil t))
(setq keshell-history-global-ring
(or eshell-history-ring (make-ring eshell-history-size))))
(setq eshell-history-ring keshell-history-global-ring))
;; Following hook enables it
(add-hook 'eshell-mode-hook 'keshell-hist-use-global-history)
;; Following removes the hook
(remove-hook 'eshell-mode-hook 'keshell-hist-use-global-history)
</pre>
</div>
<p>
After evaluating above 12 lines of elisp, you will have a list that
holds all the eshell entries across sessions, which you can persist
into a history file (just uses bash history file) and can even share
it across machines over network. This opens up a whole new
possibilities of completions, deduplication and multiple eshell
buffer management goodness, which I will cover in the next few parts
of `Why Eshell?` posts. So stay tuned and happy eshelling!
</p>
<div class="taglist"><a href="https://www.birkey.co/tags.html">Tags</a>: <a href="https://www.birkey.co/tag-eshell.html">eshell</a> <a href="https://www.birkey.co/tag-emacs.html">emacs</a> </div>
<div class="post-date">20 Jun 2021</div><h1 class="post-title"><a href="https://www.birkey.co/2021-06-20-why-eshell-part-1.html">Why Eshell? - Part 1</a></h1>
<p>
From time to time, I got asked why I use eshell as my main terminal.
There are multiple reasons I do so and covering all of them in one
post would be too long. Instead, I would like to start with a high
level bullet points and address each one in a separate blog post with
working code examples where I can point my coworkers and friends to
them so they can pick and choose as they wish.
</p>
<ol class="org-ol">
<li><b>Long running command notification and time</b></li>
<li><b>Cross session history</b></li>
<li><b>Interactive ido completion</b></li>
<li><b>Unified interface (shell prompt buffer as regular emacs buffer)</b></li>
<li><b>Plan9 Style Shell prompt (Think of it as bash REPL)</b></li>
<li><b>Multiple terminal management</b></li>
<li><b>Super charge bash with elisp</b></li>
<li><b>Eshell aliases that puts bash aliases to shame :)</b></li>
</ol>
<p>
Let us start with how you can accomplish the first item from the list
above. Following 18 lines of elisp will give you the super power of:
</p>
<ul class="org-ul">
<li>How long a command took to run as if you typed in <b>time <command></b></li>
<li>Notify you that the long running command finished in x second even
if you switch away from Emacs saving you the trouble of constantly
checking back. As a bonus, you can set the notification threshold
for long running commands that you want to run async.</li>
</ul>
<div class="org-src-container">
<pre class="src src-elisp">;; eshell time and notification
(defvar-local eshell-current-command-start-time nil)
(defun eshell-current-command-start ()
(setq eshell-current-command-start-time (current-time)))
(defun eshell-current-command-stop ()
(when eshell-current-command-start-time
(let ((elapsed-time (float-time
(time-subtract (current-time)
eshell-current-command-start-time))))
(if (> elapsed-time 30)
(tooltip-show (format "Finished in: %.0fs" elapsed-time))
(eshell-interactive-print
(format "Time: %.0fs\n" elapsed-time))))
(setq eshell-current-command-start-time nil)))
(defun eshell-current-command-time-track ()
(add-hook 'eshell-pre-command-hook #'eshell-current-command-start nil t)
(add-hook 'eshell-post-command-hook #'eshell-current-command-stop nil t))
;; This line below installs time tracking and notification
(add-hook 'eshell-mode-hook #'eshell-current-command-time-track)
;; Once you eval above snippet in emacs, fire up M-x eshell, and type:
sleep 40
;; You can switch away from emacs and will be notified that above
;; command took 40s to run
;; To uninstall
;; (remove-hook 'eshell-mode-hook #'eshell-current-command-time-track)
</pre>
</div>
<p>
Try doing above with some bashrc voodoo or plug-in that you have no
control over. I have been there and done that and it is one of many
reasons why I use eshell now. I hope someone finds it useful to his or
her command line work flow. Happy eshelling!
</p>
<div class="taglist"><a href="https://www.birkey.co/tags.html">Tags</a>: <a href="https://www.birkey.co/tag-emacs.html">emacs</a> <a href="https://www.birkey.co/tag-eshell.html">eshell</a> </div><div id="archive">
<a href="https://www.birkey.co/archive.html">Other posts</a>
</div>
</div>
<div id="postamble" class="status"><br><center>
<div style="display: inline-block; vertical-align:middle;"></div></div>
</body>
</html>