-
Notifications
You must be signed in to change notification settings - Fork 8
/
shell-setting.el
323 lines (310 loc) · 13.4 KB
/
shell-setting.el
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
319
320
321
322
323
;; -*- coding: utf-8 -*-
;; File: shell-setting.el
;;
;; Author: Denny Zhang(https://www.dennyzhang.com/contact)
;; Copyright 2020, https://DennyZhang.com
;; Created:2008-10-01
;; Updated: Time-stamp: <2020-02-03 15:37:42>
;;
;; --8<-------------------------- separator ------------------------>8--
;; (setq shell-file-name "/bin/zsh")
(setq shell-file-name "/bin/bash")
;; When killing a file, also kill related shell buffer
;;(add-hook 'kill-buffer-hook 'kill-shell-buffer)
(defun kill-shell-buffer()
"When killing a file, also kill related shell buffer."
(let* ((file-name (buffer-name)) shell-buffer-name prefix current-hostname)
(with-temp-buffer
(shell-command "hostname" (current-buffer))
(setq current-hostname (replace-regexp-in-string "\n" "" (buffer-string))))
(setq prefix (format "*shell*-%s-" current-hostname))
(setq shell-buffer-name (concat prefix file-name))
(if (get-buffer shell-buffer-name)
(kill-buffer shell-buffer-name))
)
)
;; --8<-------------------------- separator ------------------------>8--
(add-hook 'shell-mode-hook
(lambda ()
(local-set-key (kbd "<up>") 'previous-line)
(local-set-key (kbd "<down>") 'next-line)))
(setq eshell-banner-message '(format "Denny: %s\n" (get-motto)))
;; --8<-------------------------- separator ------------------------>8--
(defun open-shell-of-current-file ()
"If current file doesn't open a shell, generate one.
Otherwise, switch to related shell.
"
(interactive)
(let* ((file-name (buffer-name)) shell-buffer-name
current-hostname prefix-regexp prefix)
(with-temp-buffer
(shell-command "hostname" (current-buffer))
(setq current-hostname
(replace-regexp-in-string "\n" "" (buffer-string)))
)
(setq prefix-regexp (format "\\*shell\\*-%s-" current-hostname))
(setq prefix (format "*shell*-%s-" current-hostname))
(if (equal mode-name "Shell")
;; if current buffer is a shell, switch to related file
(pop-to-buffer (replace-regexp-in-string prefix-regexp "" file-name))
;; if current buffer is not a shell, create a related shell buffer
(setq shell-buffer-name (concat prefix file-name))
(shell shell-buffer-name)
)))
(defun open-shell-of-current-directory ()
"If any file of current directory already have a related shell, switch to it
"
(interactive)
(let* ((file-name (buffer-name)) shell-buffer-name
current-hostname prefix-regexp prefix
(directory-name default-directory))
(with-temp-buffer
(shell-command "hostname" (current-buffer))
(setq current-hostname
(replace-regexp-in-string "\n" "" (buffer-string))))
(setq prefix-regexp (format "\\*shell\\*-%s-" current-hostname))
(setq prefix (format "*shell*-%s-" current-hostname))
(setq shell-buffer-name (concat prefix file-name))
(if (equal mode-name "Shell")
;; if current buffer is a shell, switch to related file
(pop-to-buffer (replace-regexp-in-string prefix-regexp "" file-name))
;; if current buffer is not a shell, check
;; whether there is any shell opened by files in the directory
(unless (get-buffer shell-buffer-name)
(dolist (file-var (directory-files default-directory))
(if (get-buffer (concat prefix file-var))
(setq shell-buffer-name (concat prefix file-var))
))
)
(if (get-buffer shell-buffer-name)
(pop-to-buffer shell-buffer-name)
(shell shell-buffer-name)
(insert " ")
;; insert shell history
;; (load-shell-history file-name)
;; send default input
;; (comint-previous-matching-input "." -1)
)))
)
(defvar shell-history-alist
'(;; erlang files
(".*erl" . (("make && ./start.sh")
("erlc ./%f && erl -noshell -s %s start_link")
("sudo rabbitmqctl list_queues")
("mnesia:info().")
("mnesia:start().")
("mnesia:stop().")
("erl -mnesia dir '\"data/mnesia/\"' -name crontab_generator_app@ubuntu")
("erl -noshell -s mnesia start -s tv start")
("sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged")
))
;; ledger files
(".*ledger" . (("bankbal")))
;; default value for any files
(".*" . ())
)
" For the shell of one file, append user defined commands to the shell history
Each element looks like (REGEXP . COMMAND-LIST).
REGEXP is a regexp which filter filename.
COMMAND-LIST is a list of commands, which will be inserted to shell history one by one.
COMMAND is either a plain string or a string of %-constructs.
%f -- print visited file name.
%s -- print short file name, with posfix removed
Sample:
- For any files of *.erl, append two commands to related shell history
(\"*.erl\" . ((\"make && ./start.sh\") (\"erlc ./%f && erl -noshell -s %s start_link\")))
- For any files whose filename match the regexp of bak, append one command to shell history
(\"*.bak.*\" . ((\"rm -rf ./%f\")))
")
(defun load-shell-history(file-name)
(let (shell-command shell-command-list)
;; add command list to shell historyp
(make-local-variable 'comint-input-ring)
(setq shell-command-list (assoc-default file-name shell-history-alist 'string-match))
(if shell-command-list
(progn
;; reverse the list
(setq shell-command-list (nreverse shell-command-list))
(dolist (command shell-command-list)
(setq shell-command (car command))
;; replace the %-construct with the runtime value
(setq shell-command (replace-regexp-in-string "%f" file-name shell-command))
(setq shell-command
(replace-regexp-in-string "%s"
(file-name-sans-extension file-name)
shell-command))
(ring-insert-at-beginning comint-input-ring shell-command))
(move-beginning-of-line nil)
)
))
)
(global-set-key [f9] 'shell-my)
;; f9.: only spawn one shell for files in the same directory
;; C-u f9.: shell is spawn by file, instead of by directory
(defun shell-my(&optional arg)
"By default, if current file doesn't open a shell, generate one.
Otherwise, switch to related shell.
If arg is given, only open a shell for one directory.
"
(interactive "P")
(if (null arg) (open-shell-of-current-directory)
(open-shell-of-current-file)
))
;; --8<-------------------------- separator ------------------------>8--
;;eshell
;; quickly switch to eshell, and do buffer toggle things
(load-file (concat CONF-EMACS-VENDOR "/eshell-toggle/eshell-toggle.el"))
(global-set-key (kbd "<C-f9>") 'eshell-toggle)
(autoload 'eshell-toggle "eshell-toggle"
"Toggles between the *eshell* buffer and whatever buffer you are editing."
t)
(autoload 'eshell-toggle-cd "eshell-toggle"
"Pops up a eshell-buffer and insert a \"cd <file-dir>\" command." t)
;; --8<-------------------------- separator ------------------------>8--
(eval-after-load 'eshell
(setq eshell-cmpl-cycle-completions nil
eshell-save-history-on-exit t
eshell-cmpl-dir-ignore "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\)/\\'"))
;; --8<-------------------------- separator ------------------------>8--
(defun python-shell()
"make a python shell"
(interactive)
(switch-to-buffer (make-comint "python" "python" nil "-i")))
(defun perl-shell()
"make a perl db shell"
(interactive)
(switch-to-buffer (make-comint "perl" "perl" nil "-d -e''")))
;; setup environments
(setenv "PAGER" "cat")
;; --8<-------------------------- separator ------------------------>8--
(require 'shell)
(require 'term)
(define-key term-raw-map (kbd "C-j") 'term-switch-to-shell-mode)
(defun term-switch-to-shell-mode ()
(interactive)
(if (equal major-mode 'term-mode)
(progn
(shell-mode)
(set-process-filter
(get-buffer-process (current-buffer)) 'comint-output-filter )
(local-set-key (kbd "C-j") 'term-switch-to-shell-mode)
(compilation-shell-minor-mode 1)
(comint-send-input)
)
(progn
(compilation-shell-minor-mode -1)
(font-lock-mode -1)
(set-process-filter
(get-buffer-process (current-buffer)) 'term-emulate-terminal)
(term-mode)
(term-char-mode)
(term-send-raw-string (kbd "C-l"))
)))
;; --8<-------------------------- separator ------------------------>8--
(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
;; --8<-------------------------- separator ------------------------>8--
(eval-after-load 'esh-opt
'(progn
(require 'em-prompt)
(require 'em-term)
(require 'em-cmpl)
(set-face-attribute 'eshell-prompt nil :foreground "turquoise1")
(add-hook 'eshell-mode-hook ;; for some reason this needs to be a hook
#'(lambda () (define-key eshell-mode-map "\C-a" 'eshell-bol)))
;;(add-to-list 'eshell-output-filter-functions 'eshell-handle-ansi-color)
(setq eshell-cmpl-cycle-completions nil)
(add-to-list 'eshell-visual-commands "ssh")
(add-to-list 'eshell-visual-commands "tail")
(add-to-list 'eshell-command-completions-alist
'("gunzip" "gz\\'"))
(add-to-list 'eshell-command-completions-alist
'("tar" "\\(\\.tar|\\.tgz\\|\\.tar\\.gz\\)\\'"))))
;; --8<-------------------------- separator ------------------------>8--
(defun clear-shell ()
"Remove content of shell/eshell, with the prompt lines reserved"
(interactive)
(cond
((string-equal mode-name "Shell")
;; In shell buffer, leverage comint
(let ((comint-buffer-maximum-size 0))
(comint-truncate-buffer)))
((string-equal mode-name "EShell")
;; In eshell buffer, simply delete content of region
(let ((inhibit-read-only t))
(goto-char (point-min))
(forward-line 2)
(eval-after-load 'eshell
'(eshell-bol))
(kill-region (point) (point-max))))
))
(dolist (mode-hook-var '(shell-mode-hook eshell-mode-hook))
(add-hook mode-hook-var
#'(lambda () (local-set-key (kbd "C-l") 'clear-shell))))
;; --8<-------------------------- separator ------------------------>8--
;; In the ls output of *eshell* buffer, enable us to open related files/directories
(eval-after-load "em-ls"
'(progn
(defun eshell-ls-find-file-at-point ()
(interactive)
(let ((fname (buffer-substring-no-properties
(previous-single-property-change (point) 'help-echo)
(next-single-property-change (point) 'help-echo))))
;; Remove any leading whitespace, including newline that might
;; be fetched by buffer-substring-no-properties
(setq fname (replace-regexp-in-string "^[ \t\n]*" "" fname))
;; Same for trailing whitespace and newline
(setq fname (replace-regexp-in-string "[ \t\n]*$" "" fname))
(cond
((equal "" fname)
(message "No file name found at point"))
(fname
(find-file fname)))))
(defun pat-eshell-ls-find-file-at-mouse-click (event)
"Middle click on Eshell's `ls' output to open files.
From Patrick Anderson via the wiki."
(interactive "e")
(eshell-ls-find-file-at-point (posn-point (event-end event))))
(let ((map (make-sparse-keymap)))
(define-key map (kbd "RET") 'eshell-ls-find-file-at-point)
(define-key map (kbd "<return>") 'eshell-ls-find-file-at-point)
(define-key map (kbd "<mouse-2>") 'pat-eshell-ls-find-file-at-mouse-click)
(defvar ted-eshell-ls-keymap map))
(defadvice eshell-ls-decorated-name (after ted-electrify-ls activate)
"Eshell's `ls' now lets you click or RET on file names to open them."
(add-text-properties 0 (length ad-return-value)
(list 'help-echo "RET, mouse-2: visit this file"
'mouse-face 'highlight
'keymap ted-eshell-ls-keymap)
ad-return-value)
ad-return-value)))
;; --8<-------------------------- separator ------------------------>8--
(setq eshell-scroll-to-bottom-on-output t
eshell-scroll-show-maximum-output t
comint-buffer-maximum-size 20000)
;; --8<-------------------------- separator ------------------------>8--
(require 'tramp)
(setq tramp-default-method "sshx")
(remove-hook 'find-file-hook 'tramp-set-auto-save) ;; when tramp, don't auto save files
(add-to-list 'tramp-remote-path "/usr/sbin")
(add-to-list 'tramp-remote-path "/usr/local/sbin")
(add-to-list 'tramp-remote-path "/sbin")
(setq tramp-default-method-alist
'(("\\`localhost\\'" "\\`root\\'" "su")
(nil "%" "smb")
("" "\\`\\(anonymous\\|ftp\\)\\'" "ftp")
("\\`ftp\\." "" "ftp")))
(setq tramp-verbose 3)
(setq password-cache-expiry 60)
;; --8<-------------------------- separator ------------------------>8--
;; (load-file (concat CONF-EMACS-VENDOR "/multi-term/multi-term.el")) ;; TODO
(autoload 'multi-term "multi-term" nil t)
(autoload 'multi-term-next "multi-term" nil t)
(setq multi-term-program "/bin/bash") ;; use bash
;;(setq multi-term-program "/bin/zsh") ;; or use zsh...
;; only needed if you use autopair
(add-hook 'term-mode-hook
#'(lambda () (setq autopair-dont-activate t)))
(global-set-key (kbd "C-c t") 'multi-term-next)
(global-set-key (kbd "C-c T") 'multi-term) ;; create a new one
;; --8<-------------------------- separator ------------------------>8--
;; File: shell-setting.el