2017-06-12 22:26:50 +02:00
|
|
|
|
;;; Eshell
|
2016-10-14 14:03:30 +02:00
|
|
|
|
|
2017-06-16 20:53:25 +02:00
|
|
|
|
;;; Eshell gets initialized differently. When eshell.el first gets loaded, only
|
|
|
|
|
;;; the core is defined and `eshell-load-hook' is called. For every Eshell
|
|
|
|
|
;;; session, `eshell-mode' is run: it resets `eshell-mode-map', it loads
|
|
|
|
|
;;; modules, runs their hooks and concludes with `eshell-first-time-mode-hook'
|
|
|
|
|
;;; (for the first session only) and `eshell-mode-hook'.
|
|
|
|
|
|
2017-10-25 20:12:52 +02:00
|
|
|
|
;; Emacs pinentry for GPG.
|
|
|
|
|
(require 'main)
|
|
|
|
|
|
2017-11-05 12:39:37 +01:00
|
|
|
|
;;; REVIEW: If history contains read-only text (e.g. accidental insertion of the prompt),
|
|
|
|
|
;;; `eshell-write-history' won't work.
|
|
|
|
|
;;; See #29153.
|
2017-11-03 14:55:57 +01:00
|
|
|
|
|
2018-02-15 15:55:30 +01:00
|
|
|
|
;;; REVIEW: Sometimes transmission-daemon does not start from Eshell.
|
|
|
|
|
;;; See #30465.
|
2017-10-23 21:06:08 +02:00
|
|
|
|
|
2017-11-05 12:39:37 +01:00
|
|
|
|
;;; REVIEW: Redirecting big output to file (e.g. /dev/null) is extremely slow.
|
2017-10-10 16:19:22 +02:00
|
|
|
|
;; > cat /usr/share/dict/british-english | wc -l
|
|
|
|
|
;;; The above line yields rancom results. Plus it's much slower than
|
|
|
|
|
;; > wc -l /usr/share/dict/british-english
|
|
|
|
|
;;; while it should only cost an additional process to launch.
|
2017-11-05 12:39:37 +01:00
|
|
|
|
;;; See #29154.
|
2017-08-01 20:55:50 +02:00
|
|
|
|
|
2017-09-02 12:14:09 +02:00
|
|
|
|
;;; REVIEW: Cannot "C-c C-c" during a `sudo pacman -Syu`. A bug was filed about that already.
|
2017-07-29 11:14:18 +02:00
|
|
|
|
|
2017-08-01 20:55:50 +02:00
|
|
|
|
;;; TODO: The buffer stutters when writing "in-place", e.g. pacman, git.
|
|
|
|
|
;;; It seems that it does not do it as much in `emacs -Q`.
|
|
|
|
|
|
|
|
|
|
;;; REVIEW: `eshell/sudo' should not read -u in command arguments.
|
|
|
|
|
;;; This fails: sudo pacman -Syu --noconfirm.
|
|
|
|
|
;;; http://www.gnu.org/software/emacs/manual/html_node/eshell/Built_002dins.html
|
|
|
|
|
;;; https://emacs.stackexchange.com/questions/5608/how-to-let-eshell-remember-sudo-password-for-two-minutes
|
|
|
|
|
;;; See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=27411
|
2017-09-02 12:14:09 +02:00
|
|
|
|
;;; and #28323.
|
|
|
|
|
|
2017-07-28 09:12:25 +02:00
|
|
|
|
;;; REVIEW: Eshell/Shell completion fails when PATH has a non-readable element.
|
2017-09-02 12:14:09 +02:00
|
|
|
|
;;; See https://github.com/emacs-helm/helm/issues/1785
|
|
|
|
|
;;; and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27300.
|
|
|
|
|
|
|
|
|
|
;;; REVIEW: 40M+ output: Stack overflow in regexp matcher
|
|
|
|
|
;;; See bug#28329.
|
2017-11-06 22:07:48 +01:00
|
|
|
|
;;; I guess the chunking is significant too. Could you try saving
|
|
|
|
|
;;; the output chunks, with this:
|
|
|
|
|
;;
|
|
|
|
|
;; (defvar eshell-chunk-number 0)
|
|
|
|
|
;; (defconst eshell-output-chunk-dir "eshell-output")
|
|
|
|
|
;; (make-directory eshell-output-chunk-dir t)
|
|
|
|
|
;;
|
|
|
|
|
;; (defun catch-eshell-output-chunk ()
|
|
|
|
|
;; (write-region eshell-last-output-block-begin
|
|
|
|
|
;; eshell-last-output-end
|
|
|
|
|
;; (format "%s/chunk.%d"
|
|
|
|
|
;; eshell-output-chunk-dir
|
|
|
|
|
;; eshell-chunk-number)
|
|
|
|
|
;; nil :quiet)
|
|
|
|
|
;; (setq eshell-chunk-number (1+ eshell-chunk-number)))
|
|
|
|
|
;;
|
|
|
|
|
;; (add-hook 'eshell-output-filter-functions
|
|
|
|
|
;; 'catch-eshell-output-chunk)
|
|
|
|
|
;;;
|
|
|
|
|
;;; And then afterwards 'cat eshell-output/chunk.*' should hopefully
|
|
|
|
|
;;; reproduce it?
|
|
|
|
|
|
2017-09-02 12:14:09 +02:00
|
|
|
|
|
|
|
|
|
;;; REVIEW: Eshell mixes stderr and stdout it seems.
|
|
|
|
|
;;; Example:
|
|
|
|
|
;;; $ mu find --nocolor --sortfield=d --maxnum=500 flag:unread AND NOT flag:trashed >/dev/null
|
|
|
|
|
;;; mu: no matches for search expression (4)
|
|
|
|
|
;;; See #21605 "24.3; Eshell not using stderr".
|
2017-07-28 09:12:25 +02:00
|
|
|
|
|
2017-11-05 12:39:37 +01:00
|
|
|
|
;;; REVIEW: Some parsing fails
|
2017-10-15 14:55:49 +02:00
|
|
|
|
;;; > echo -n $PATH | sed 's/:[^:]*sophos[^:]*/:/g'
|
|
|
|
|
;;; :s/:]*sophos[/:]*/:/"/
|
|
|
|
|
;;; Unknown modifier character ‘/’
|
|
|
|
|
;;;
|
|
|
|
|
;;; > date +%Z
|
2017-11-05 12:39:37 +01:00
|
|
|
|
;;; See #29157.
|
2018-03-09 12:07:58 +01:00
|
|
|
|
(when (< emacs-major-version 27)
|
|
|
|
|
(require 'patch-eshell-26))
|
2017-10-15 14:55:49 +02:00
|
|
|
|
|
2017-11-26 22:37:24 +01:00
|
|
|
|
;;; TODO: Change face of eshell/* commands in commandline to avoid confusion
|
|
|
|
|
;;; with system programs.
|
|
|
|
|
|
|
|
|
|
;;; TODO: Merge/re-use documentation of eshell/* commands with their docstring.
|
|
|
|
|
|
2017-10-24 18:30:34 +02:00
|
|
|
|
;;; TODO: Hour is printed twice. We don't need to set this?
|
|
|
|
|
;; (setq eshell-ls-date-format (replace-regexp-in-string "^\\+*" "" (getenv "TIME_STYLE")))
|
|
|
|
|
|
|
|
|
|
;;; TODO: ls: Sort using locale.
|
|
|
|
|
|
2017-11-05 12:39:37 +01:00
|
|
|
|
;;; REVIEW: `kill -#' does not work.
|
|
|
|
|
;;; See #29156.
|
2017-10-24 18:30:34 +02:00
|
|
|
|
|
2018-01-17 10:10:26 +01:00
|
|
|
|
;;; Use TRAMP to use Eshell as root.
|
2017-06-17 18:37:04 +02:00
|
|
|
|
(require 'em-tramp)
|
2018-01-15 12:17:36 +01:00
|
|
|
|
(setq password-cache t)
|
2018-01-17 10:10:26 +01:00
|
|
|
|
(setq password-cache-expiry 3600)
|
2017-06-17 18:37:04 +02:00
|
|
|
|
|
2017-11-05 12:39:37 +01:00
|
|
|
|
(with-eval-after-load 'esh-module
|
2018-07-03 18:03:50 +02:00
|
|
|
|
;; REVIEW: It used to work, but now the early `provide' seems to backfire.
|
|
|
|
|
(unless (boundp 'eshell-modules-list)
|
|
|
|
|
(load "esh-module"))
|
2017-06-17 18:37:04 +02:00
|
|
|
|
;; Don't print the banner.
|
|
|
|
|
(delq 'eshell-banner eshell-modules-list)
|
2017-06-17 19:01:32 +02:00
|
|
|
|
(push 'eshell-tramp eshell-modules-list))
|
2017-06-16 20:53:25 +02:00
|
|
|
|
|
2017-06-12 22:26:50 +02:00
|
|
|
|
(setq
|
|
|
|
|
eshell-ls-use-colors t
|
2017-06-18 22:25:17 +02:00
|
|
|
|
;; ffap-shell-prompt-regexp changes the behaviour of `helm-find-files' when
|
|
|
|
|
;; point is on prompt. I find this disturbing.
|
|
|
|
|
ffap-shell-prompt-regexp nil
|
2017-06-27 22:13:51 +02:00
|
|
|
|
eshell-history-size 1024
|
|
|
|
|
eshell-hist-ignoredups t
|
2017-06-15 18:56:22 +02:00
|
|
|
|
eshell-destroy-buffer-when-process-dies t)
|
|
|
|
|
|
2018-10-17 14:36:13 +02:00
|
|
|
|
(defun ambrevar/eshell-prompt ()
|
|
|
|
|
(let ((path (abbreviate-file-name (eshell/pwd))))
|
|
|
|
|
(concat
|
|
|
|
|
(when ambrevar/eshell-status-p
|
|
|
|
|
(propertize (or (ambrevar/eshell-status-display) "") 'face font-lock-comment-face))
|
|
|
|
|
(format
|
|
|
|
|
(propertize "(%s@%s)" 'face '(:weight bold))
|
|
|
|
|
(propertize (user-login-name) 'face '(:foreground "cyan"))
|
|
|
|
|
(propertize (system-name) 'face '(:foreground "cyan")))
|
|
|
|
|
(if (and (require 'magit nil t) (or (magit-get-current-branch) (magit-get-current-tag)))
|
2018-12-09 16:31:57 +01:00
|
|
|
|
;; We need "--show-prefix and not "--top-level" when we don't follow symlinks.
|
|
|
|
|
(let* ((git-file-path (abbreviate-file-name (magit-rev-parse "--show-prefix")))
|
|
|
|
|
prefix)
|
|
|
|
|
(let ((common-folder (car (split-string git-file-path "/"))))
|
|
|
|
|
(setq prefix (mapconcat 'identity (seq-take-while
|
|
|
|
|
(lambda (s) (not (string= s common-folder)))
|
|
|
|
|
(split-string path "/"))
|
|
|
|
|
"/")))
|
2017-06-12 22:26:50 +02:00
|
|
|
|
(format
|
2018-10-17 14:36:13 +02:00
|
|
|
|
(propertize "[%s/%s@%s]" 'face '(:weight bold))
|
2018-12-09 16:31:57 +01:00
|
|
|
|
(propertize prefix 'face `(:foreground ,(if (= (user-uid) 0) "red" "green") :weight bold))
|
|
|
|
|
(propertize (substring-no-properties path (min (length path) (1+ (length prefix))))
|
|
|
|
|
'face `(:foreground ,(if (= (user-uid) 0) "orange" "gold")))
|
2018-10-17 14:36:13 +02:00
|
|
|
|
(or (magit-get-current-branch) (magit-get-current-tag))))
|
|
|
|
|
(format
|
|
|
|
|
(propertize "[%s]" 'face '(:weight bold))
|
|
|
|
|
(propertize path 'face `(:foreground ,(if (= (user-uid) 0) "red" "green") :weight bold))))
|
|
|
|
|
(propertize "\n>" 'face '(:weight bold))
|
|
|
|
|
" ")))
|
|
|
|
|
|
|
|
|
|
;;; Leave `eshell-highlight-prompt' to t as it sets the read-only property.
|
|
|
|
|
(setq eshell-prompt-function #'ambrevar/eshell-prompt)
|
2017-06-12 22:26:50 +02:00
|
|
|
|
;;; If the prompt spans over multiple lines, the regexp should match
|
|
|
|
|
;;; last line only.
|
2017-06-18 20:52:16 +02:00
|
|
|
|
(setq-default eshell-prompt-regexp "^> ")
|
2014-02-12 18:31:00 +01:00
|
|
|
|
|
2017-06-16 20:53:25 +02:00
|
|
|
|
(with-eval-after-load 'em-term
|
2018-01-19 09:12:13 +01:00
|
|
|
|
(dolist (p '("abook" "alsamixer" "cmus" "fzf" "gtypist" "htop" "mpsyt" "mpv" "mutt" "ncdu" "newsbeuter" "pinentry-curses" "ranger" "watch" "wifi-menu"))
|
2017-10-24 18:30:34 +02:00
|
|
|
|
(add-to-list 'eshell-visual-commands p))
|
2017-06-16 20:53:25 +02:00
|
|
|
|
(setq eshell-visual-subcommands
|
2017-12-12 22:49:18 +01:00
|
|
|
|
;; Some Git commands use a pager by default.
|
|
|
|
|
;; Either invoke the subcommands in a term ("visual") or configure Git
|
|
|
|
|
;; to disable the pager globally.
|
|
|
|
|
;; '(("git" "log" "diff" "show")
|
|
|
|
|
'(("sudo" "wifi-menu") ; Arch Linux
|
2017-10-24 18:30:34 +02:00
|
|
|
|
("sudo" "vi" "visudo"))))
|
2016-06-09 18:23:04 +02:00
|
|
|
|
|
2017-06-12 22:26:50 +02:00
|
|
|
|
;;; Alias management possibilities:
|
|
|
|
|
;;; - Version eshell-alias and store it in user-emacs-directory. Simplest and
|
|
|
|
|
;;; fastest, but aliases cannot be included conditionnaly, e.g. depending on the
|
|
|
|
|
;;; existence of a program.
|
|
|
|
|
;;; - Store eshell-alias in cache and populate it dynamically on startup.
|
|
|
|
|
;; (setq eshell-aliases-file (concat user-emacs-directory "eshell-alias"))
|
|
|
|
|
;;;
|
|
|
|
|
;;; `eshell/alias' is too slow as it reads and write the file on each definition.
|
|
|
|
|
;;; Let's write manually instead.
|
2017-06-16 20:53:25 +02:00
|
|
|
|
(with-eval-after-load 'em-alias
|
2017-10-21 11:35:03 +02:00
|
|
|
|
;;; If we read the alias list here, it means we make commandline-defined aliases persistent.
|
2017-10-24 18:30:34 +02:00
|
|
|
|
;; (eshell-read-aliases-list)
|
2017-06-16 20:53:25 +02:00
|
|
|
|
(dolist
|
|
|
|
|
(alias
|
|
|
|
|
'(("l" "ls -1 $*")
|
|
|
|
|
("la" "ls -lAh $*")
|
|
|
|
|
("ll" "ls -lh $*")
|
2017-10-23 21:06:08 +02:00
|
|
|
|
;; TODO: Aliasing eshell/{cp,mv,ln} does not work.
|
|
|
|
|
;; REVIEW: Eshell/TRAMP's sudo does not work with aliases.
|
2018-02-15 15:55:30 +01:00
|
|
|
|
;; See #28320, #27168.
|
2017-10-21 11:35:03 +02:00
|
|
|
|
;; ("ls" "ls -F $*") ; not supported
|
2017-06-16 20:53:25 +02:00
|
|
|
|
;; ("emacs" "find-file $1")
|
2017-10-23 21:06:08 +02:00
|
|
|
|
;; ("cp" "eshell/cp -iv $*")
|
2017-10-21 11:35:03 +02:00
|
|
|
|
;; ("mv" "eshell/mv -iv $*")
|
2017-10-23 21:06:08 +02:00
|
|
|
|
("cpv" "cp -iv $*")
|
2017-10-22 11:37:51 +02:00
|
|
|
|
("mvv" "mv -iv $*")
|
|
|
|
|
("rmv" "rm -v $*")
|
|
|
|
|
("md" "eshell/mkdir -p $*")
|
2018-02-15 15:55:30 +01:00
|
|
|
|
("mkcd" "eshell/mkdir -p $* ; cd $1"))) ; TODO: '&&' does not work because mkdir exits with nil?
|
2017-06-16 20:53:25 +02:00
|
|
|
|
(add-to-list 'eshell-command-aliases-list alias))
|
|
|
|
|
(eshell-write-aliases-list))
|
2014-02-12 18:31:00 +01:00
|
|
|
|
|
2017-06-17 13:14:45 +02:00
|
|
|
|
;;; Hooks
|
|
|
|
|
;;; `nobreak-char-display' makes some output look weird, e.g. with 'tree'.
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(add-hook 'eshell-mode-hook 'ambrevar/turn-off-nobreak-char-display)
|
2017-06-17 13:14:45 +02:00
|
|
|
|
|
2017-10-22 21:19:12 +02:00
|
|
|
|
;;; History
|
2017-06-27 22:13:51 +02:00
|
|
|
|
;;; Filter out space-beginning commands from history.
|
2018-02-15 15:56:55 +01:00
|
|
|
|
;;; TODO: history/command hook: trim spaces. Check `eshell-rewrite-command-hook'.
|
2019-02-05 22:45:17 +01:00
|
|
|
|
;;; REVIEW: history: do not save failed Eshell commands (See `eshell-last-command-status')
|
2018-02-15 15:56:55 +01:00
|
|
|
|
;;; Eshell commands always return 0.
|
2017-06-27 22:13:51 +02:00
|
|
|
|
(setq eshell-input-filter
|
|
|
|
|
(lambda (str)
|
2018-03-19 11:33:19 +01:00
|
|
|
|
(not (or
|
|
|
|
|
;; Here we can filter out failing commands. This is usually a bad
|
|
|
|
|
;; idea since a lot of useful commands have non-zero exit codes
|
|
|
|
|
;; (including Emacs/Eshell functions).
|
|
|
|
|
;; (/= eshell-last-command-status 0)
|
|
|
|
|
(string= "" str)
|
2019-02-04 19:13:17 +01:00
|
|
|
|
(string= "cd" str)
|
|
|
|
|
(string-prefix-p "cd " str)
|
2018-03-19 11:33:19 +01:00
|
|
|
|
(string-prefix-p " " str)))))
|
2017-06-27 22:13:51 +02:00
|
|
|
|
|
2017-10-22 21:19:12 +02:00
|
|
|
|
;;; Shared history.
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(defvar ambrevar/eshell-history-global-ring nil
|
2017-10-22 21:19:12 +02:00
|
|
|
|
"The history ring shared across Eshell sessions.")
|
|
|
|
|
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(defun ambrevar/eshell-hist-use-global-history ()
|
2017-10-22 21:19:12 +02:00
|
|
|
|
"Make Eshell history shared across different sessions."
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(unless ambrevar/eshell-history-global-ring
|
2018-01-12 11:27:11 +01:00
|
|
|
|
(when eshell-history-file-name
|
|
|
|
|
(eshell-read-history nil t))
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(setq ambrevar/eshell-history-global-ring (or eshell-history-ring (make-ring eshell-history-size))))
|
|
|
|
|
(setq eshell-history-ring ambrevar/eshell-history-global-ring))
|
|
|
|
|
(add-hook 'eshell-mode-hook 'ambrevar/eshell-hist-use-global-history)
|
2017-10-22 21:19:12 +02:00
|
|
|
|
|
2019-02-05 22:45:17 +01:00
|
|
|
|
(defun ambrevar/eshell-history-remove-duplicates ()
|
|
|
|
|
"Remove duplicates of last command in history.
|
|
|
|
|
This should be faster then `seq-uniq'."
|
|
|
|
|
(let ((first (ring-ref eshell-history-ring 0))
|
|
|
|
|
(index 1))
|
|
|
|
|
(while (<= index (1- (ring-length eshell-history-ring)))
|
|
|
|
|
(if (string= first (ring-ref eshell-history-ring index))
|
2019-02-11 19:40:23 +01:00
|
|
|
|
;; REVIEW: We could stop at the first match, it would be faster and it
|
|
|
|
|
;; would eliminate duplicates if we started from a fresh history.
|
|
|
|
|
;; From an existing history that would not clean up existing
|
|
|
|
|
;; duplicates beyond the first one.
|
2019-02-05 22:45:17 +01:00
|
|
|
|
(ring-remove eshell-history-ring index)
|
|
|
|
|
(setq index (1+ index))))))
|
|
|
|
|
(add-hook 'eshell-pre-command-hook 'ambrevar/eshell-history-remove-duplicates)
|
|
|
|
|
|
2019-02-05 22:47:37 +01:00
|
|
|
|
;; Always save history
|
|
|
|
|
(add-hook 'eshell-pre-command-hook 'eshell-save-some-history)
|
|
|
|
|
|
|
|
|
|
;;; Version and encrypt history.
|
|
|
|
|
;; TODO: The following makes EPA always prompt for recipients for some reason. Bug?
|
|
|
|
|
;; (make-directory "~/personal/history/" :parents)
|
|
|
|
|
;; (setq eshell-history-file-name (expand-file-name "eshell.gpg" "~/personal/history"))
|
|
|
|
|
;; (defun ambrevar/fix-local-epa-file-encrypt-to ()
|
|
|
|
|
;; (unless (local-variable-p 'epa-file-encrypt-to (current-buffer))
|
|
|
|
|
;; (make-local-variable 'epa-file-encrypt-to))
|
|
|
|
|
;; (setq epa-file-encrypt-to "mail@ambrevar.xyz"))
|
|
|
|
|
;; (add-hook 'eshell-mode-hook 'ambrevar/fix-local-epa-file-encrypt-to)
|
|
|
|
|
|
2017-10-22 21:19:12 +02:00
|
|
|
|
;;; Spawning
|
2019-02-22 17:26:25 +01:00
|
|
|
|
(defvar helm-eshell-buffers-map
|
|
|
|
|
(let ((map (make-sparse-keymap)))
|
|
|
|
|
(set-keymap-parent map helm-map)
|
|
|
|
|
(define-key map (kbd "C-c o") 'helm-buffer-switch-other-window)
|
|
|
|
|
(define-key map (kbd "C-c C-o") 'helm-buffer-switch-other-frame)
|
|
|
|
|
(define-key map (kbd "M-D") 'helm-buffer-run-kill-buffers)
|
|
|
|
|
map)
|
|
|
|
|
"Keymap for browser source in Helm.")
|
|
|
|
|
|
|
|
|
|
(defun ambrevar/helm-buffer-transformer (buffers)
|
|
|
|
|
(mapcar #'buffer-name buffers))
|
|
|
|
|
|
|
|
|
|
(defun ambrevar/helm-eshell-buffers ()
|
|
|
|
|
"Yet another smart buffer switcher with `helm'."
|
|
|
|
|
(interactive)
|
|
|
|
|
(helm-build-sync-source "Eshell buffers"
|
|
|
|
|
:candidates (seq-filter (lambda (b) (with-current-buffer b
|
|
|
|
|
(derived-mode-p 'eshell-mode)))
|
|
|
|
|
(buffer-list))
|
|
|
|
|
:candidate-transformer #'ambrevar/helm-buffer-transformer
|
|
|
|
|
;; :filtered-candidate-transformer #'helm-highlight-buffers
|
|
|
|
|
:action `(("Switch to buffer(s)" . helm-buffer-switch-buffers)
|
|
|
|
|
(,(substitute-command-keys "Switch to buffer(s) in other window \\<helm-eshell-buffers-map>`\\[helm-buffer-switch-other-window]'")
|
|
|
|
|
. helm-buffer-switch-buffers-other-window)
|
|
|
|
|
(,(substitute-command-keys "Switch to buffer in other frame \\<helm-eshell-buffers-map>`\\[helm-buffer-switch-other-frame]'")
|
|
|
|
|
. switch-to-buffer-other-frame)
|
|
|
|
|
(,(substitute-command-keys "Kill buffer(s) \\<helm-eshell-buffers-map>`\\[helm-buffer-run-kill-buffers]'")
|
|
|
|
|
. helm-kill-marked-buffers))
|
|
|
|
|
:keymap helm-eshell-buffers-map
|
|
|
|
|
:persistent-action 'helm-buffers-list-persistent-action))
|
|
|
|
|
(add-to-list 'helm-source-names-using-follow "Eshell buffers")
|
|
|
|
|
|
|
|
|
|
(defun ambrevar/helm-eshell-new (name)
|
|
|
|
|
"Fetch URL and render the page in a new buffer.
|
|
|
|
|
If the input doesn't look like an URL or a domain name, the
|
|
|
|
|
word(s) will be searched for via `eww-search-prefix'."
|
|
|
|
|
(eshell 'new)
|
|
|
|
|
(rename-buffer (format "*eshell<%s>*" name) 'unique))
|
|
|
|
|
|
|
|
|
|
(defvar ambrevar/helm-eshell-new
|
|
|
|
|
(helm-build-dummy-source "Open new Eshell"
|
|
|
|
|
:action (helm-make-actions "Open new Eshell" 'ambrevar/helm-eshell-new-buffer)))
|
|
|
|
|
|
|
|
|
|
(defun ambrevar/helm-eshell-mini ()
|
|
|
|
|
"Helm for Eshell buffers."
|
|
|
|
|
(interactive)
|
|
|
|
|
(helm :sources (list (ambrevar/helm-eshell-buffers)
|
|
|
|
|
'ambrevar/helm-eshell-new)
|
|
|
|
|
:buffer "*helm-eshell-mini*"))
|
|
|
|
|
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(defun ambrevar/eshell-or-new-session (&optional arg)
|
2017-07-27 00:08:58 +02:00
|
|
|
|
"Create an interactive Eshell buffer.
|
2017-10-20 16:13:57 +02:00
|
|
|
|
Switch to last Eshell session if any.
|
|
|
|
|
Otherwise create a new one and switch to it.
|
2017-07-27 00:08:58 +02:00
|
|
|
|
See `eshell' for the numeric prefix ARG."
|
|
|
|
|
(interactive "P")
|
2017-10-20 16:13:57 +02:00
|
|
|
|
(if (or arg (eq major-mode 'eshell-mode))
|
2019-02-22 17:26:25 +01:00
|
|
|
|
(ambrevar/helm-eshell-mini)
|
|
|
|
|
;; (eshell (or arg t))
|
2017-10-20 16:13:57 +02:00
|
|
|
|
(let ((last (buffer-list)))
|
|
|
|
|
(while (and last
|
|
|
|
|
(not (with-current-buffer (car last)
|
|
|
|
|
(eq major-mode 'eshell-mode))))
|
|
|
|
|
(setq last (cdr last)))
|
|
|
|
|
(if last
|
|
|
|
|
(switch-to-buffer (car last))
|
|
|
|
|
(eshell (or arg t))))))
|
2017-07-27 00:08:58 +02:00
|
|
|
|
|
2017-11-01 16:06:15 +01:00
|
|
|
|
;;; Auto-suggestion
|
2017-12-27 11:35:49 +01:00
|
|
|
|
(when (require 'esh-autosuggest nil t)
|
2018-05-14 20:08:05 +02:00
|
|
|
|
(setq esh-autosuggest-delay 0.75)
|
2017-12-27 11:35:49 +01:00
|
|
|
|
(add-hook 'eshell-mode-hook 'esh-autosuggest-mode)
|
|
|
|
|
(define-key esh-autosuggest-active-map (kbd "<tab>") 'company-complete-selection)
|
2017-11-01 16:06:15 +01:00
|
|
|
|
(when (require 'helm-config nil t)
|
2017-12-09 19:20:24 +01:00
|
|
|
|
(define-key company-active-map (kbd "M-p") 'helm-eshell-history)))
|
2017-07-07 18:38:00 +02:00
|
|
|
|
|
2017-11-01 17:59:53 +01:00
|
|
|
|
;;; Extra execution information
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(defvar ambrevar/eshell-status-p t
|
2017-11-01 17:59:53 +01:00
|
|
|
|
"If non-nil, display status before prompt.")
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(defvar ambrevar/eshell-status--last-command-time nil)
|
|
|
|
|
(make-variable-buffer-local 'ambrevar/eshell-status--last-command-time)
|
|
|
|
|
(defvar ambrevar/eshell-status-min-duration-before-display 1
|
2017-11-01 17:59:53 +01:00
|
|
|
|
"If a command takes more time than this, display its duration.")
|
|
|
|
|
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(defun ambrevar/eshell-status-display ()
|
|
|
|
|
(when ambrevar/eshell-status--last-command-time
|
|
|
|
|
(let ((duration (time-subtract (current-time) ambrevar/eshell-status--last-command-time)))
|
|
|
|
|
(setq ambrevar/eshell-status--last-command-time nil)
|
|
|
|
|
(when (> (time-to-seconds duration) ambrevar/eshell-status-min-duration-before-display)
|
2017-11-02 23:35:14 +01:00
|
|
|
|
(format "#[STATUS] End time %s, duration %.3fs\n"
|
|
|
|
|
(format-time-string "%F %T" (current-time))
|
|
|
|
|
(time-to-seconds duration))))))
|
2017-11-01 17:59:53 +01:00
|
|
|
|
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(defun ambrevar/eshell-status-record ()
|
|
|
|
|
(setq ambrevar/eshell-status--last-command-time (current-time)))
|
2017-11-01 17:59:53 +01:00
|
|
|
|
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(add-hook 'eshell-pre-command-hook 'ambrevar/eshell-status-record)
|
2017-11-01 17:59:53 +01:00
|
|
|
|
|
2017-11-08 17:39:44 +01:00
|
|
|
|
;;; Detach
|
|
|
|
|
(when (require 'package-eshell-detach nil t)
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(defun ambrevar/eshell-detach-set-keys ()
|
2017-11-09 17:34:05 +01:00
|
|
|
|
(define-key eshell-mode-map (kbd "C-c C-z") 'eshell-detach-stop)
|
|
|
|
|
(define-key eshell-mode-map (kbd "S-<return>") 'eshell-detach-send-input)
|
|
|
|
|
(define-key eshell-mode-map (kbd "C-<return>") 'eshell-detach-attach))
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(add-hook 'eshell-mode-hook 'ambrevar/eshell-detach-set-keys))
|
2017-11-08 17:39:44 +01:00
|
|
|
|
|
2018-07-24 09:45:01 +02:00
|
|
|
|
;; Man
|
2018-02-08 12:58:06 +01:00
|
|
|
|
(when (string= (file-symlink-p (executable-find "man")) "mandoc")
|
|
|
|
|
;; Some systems like Void Linux use mandoc instead of man and do not know the
|
|
|
|
|
;; --nj, --nh flags.
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(defun ambrevar/pcmpl-args-mandoc-man-function (name)
|
2018-02-08 12:58:06 +01:00
|
|
|
|
(let ((process-environment process-environment))
|
|
|
|
|
;; Setting MANWIDTH to a high number makes most paragraphs fit on a single
|
|
|
|
|
;; line, reducing the number of false positives that result from lines
|
|
|
|
|
;; starting with `-' that aren't really options.
|
|
|
|
|
(push "MANWIDTH=10000" process-environment)
|
|
|
|
|
(pcmpl-args-process-file "man" "--" name)))
|
2018-02-13 13:42:11 +01:00
|
|
|
|
(setq pcmpl-args-man-function 'ambrevar/pcmpl-args-mandoc-man-function))
|
2018-02-08 12:58:06 +01:00
|
|
|
|
|
2018-07-24 09:45:01 +02:00
|
|
|
|
;; Completion
|
|
|
|
|
(when (require 'bash-completion nil t)
|
|
|
|
|
(when (and (or (executable-find "fish")
|
|
|
|
|
;; "fish" needs not be in PATH with guix.
|
|
|
|
|
(executable-find "guix"))
|
|
|
|
|
(require 'fish-completion nil t))
|
|
|
|
|
(setq fish-completion-fallback-on-bash-p t)
|
|
|
|
|
(global-fish-completion-mode)))
|
|
|
|
|
|
2019-02-04 19:12:48 +01:00
|
|
|
|
;; Misc.
|
|
|
|
|
(defun ambrevar/eshell-append-region-to-command-line (begin end)
|
|
|
|
|
(interactive "r")
|
2019-02-05 22:44:45 +01:00
|
|
|
|
(require 'subr-x) ; For `string-trim'.
|
2019-02-04 19:12:48 +01:00
|
|
|
|
(save-mark-and-excursion
|
|
|
|
|
(let ((string (buffer-substring-no-properties begin end)))
|
|
|
|
|
(setq string (string-trim string))
|
|
|
|
|
(setq string (concat string " "))
|
|
|
|
|
(goto-char (point-max))
|
|
|
|
|
(ignore-errors (cycle-spacing 0))
|
|
|
|
|
(insert string))))
|
|
|
|
|
|
2017-07-07 18:38:00 +02:00
|
|
|
|
(provide 'init-eshell)
|