Emacs: Tweak Eshell (prompt, aliases, evil bindings, next-prompt defun, helm)
parent
e44a13c3e5
commit
c37af9b279
|
@ -236,6 +236,7 @@ e-mail."
|
|||
(add-hook 'dired-mode-hook (lambda () (require 'mode-dired)))
|
||||
|
||||
;;; Eshell
|
||||
(add-to-list 'package-selected-packages 'pcomplete-extension)
|
||||
(add-hook 'eshell-load-hook (lambda () (require 'mode-eshell)))
|
||||
|
||||
;;; Evil
|
||||
|
|
|
@ -1,47 +1,87 @@
|
|||
;; Eshell
|
||||
;;; Eshell
|
||||
|
||||
;; This mode has a lot of hooks.
|
||||
;; `emacs-load-hook' is run at the very beginning; not all variables/functions will be set.
|
||||
;; `emacs-mode-hook' is run once everything is loaded.
|
||||
;;; This mode has a lot of hooks.
|
||||
;;; `emacs-load-hook' is run at the very beginning; not all variables/functions will be set.
|
||||
;;; `emacs-mode-hook' is run once everything is loaded.
|
||||
|
||||
(setq eshell-directory-name (concat emacs-cache-folder "eshell"))
|
||||
;;; TODO: Bind "ls"? No need if we have Ctrl-e?
|
||||
;; (local-set-key "\C-l" 'eshell/ls)
|
||||
|
||||
;; 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"))
|
||||
(setq
|
||||
eshell-directory-name (concat emacs-cache-folder "eshell")
|
||||
eshell-banner-message ""
|
||||
eshell-ls-use-colors t
|
||||
eshell-destroy-buffer-when-process-dies t
|
||||
;; TODO: Hour is printed twice. We don't need to set this?
|
||||
;; eshell-ls-date-format (replace-regexp-in-string "^\\+*" "" (getenv "TIME_STYLE"))
|
||||
)
|
||||
|
||||
;;; Leave `eshell-highlight-prompt' to t as it sets the read-only property.
|
||||
(setq eshell-prompt-function
|
||||
(lambda nil
|
||||
(let ((path (abbreviate-file-name (eshell/pwd))))
|
||||
(format "(%s@%s)[%s]\n%s "
|
||||
(user-login-name)
|
||||
(system-name)
|
||||
path
|
||||
(if (= (user-uid) 0) "#" ">")))))
|
||||
;; If the prompt spans over multiple lines, the regexp should match last line only.
|
||||
(setq eshell-prompt-regexp "^[#>] ")
|
||||
(concat
|
||||
(format
|
||||
(propertize "(%s@%s)[%s]\n>" 'face '(:weight bold))
|
||||
(propertize (user-login-name) 'face '(:foreground "cyan"))
|
||||
(propertize (system-name) 'face '(:foreground "cyan"))
|
||||
(propertize path 'face `(:foreground ,(if (= (user-uid) 0) "red" "green") :weight bold)))
|
||||
" "))))
|
||||
;;; If the prompt spans over multiple lines, the regexp should match
|
||||
;;; last line only.
|
||||
(setq eshell-prompt-regexp "^> ")
|
||||
|
||||
(with-eval-after-load 'em-term
|
||||
(nconc eshell-visual-commands
|
||||
'("abook" "cmus" "fzf" "htop" "mpv" "mutt" "ncdu" "newsbeuter" "ranger")))
|
||||
;; (with-eval-after-load 'em-term
|
||||
;; (add-to-list 'eshell-visual-subcommands '("git" "log" "diff" "show")))
|
||||
'("abook" "cmus" "fzf" "htop" "mpv" "mutt" "ncdu" "newsbeuter" "ranger"))
|
||||
(add-to-list 'eshell-visual-subcommands '("git" "log" "diff" "show")))
|
||||
|
||||
;; eshell/alias is too slow as it reads and write the file on each definition.
|
||||
;;; 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.
|
||||
;;; TODO: Add pacman functions from fish config.
|
||||
;;; TODO: Compare system tools and lisp equivalents of ls and grep.
|
||||
(with-eval-after-load 'em-alias
|
||||
(eshell-read-aliases-list)
|
||||
(dolist (alias '(("ls" "ls -F $*")
|
||||
(dolist (alias '(
|
||||
;; ("ls" "ls -F $*")
|
||||
("l" "ls -1 $*")
|
||||
("la" "ls -lAh $*")
|
||||
("ll" "ls -lh $*")
|
||||
("grep" "grep --color=auto")
|
||||
;; ("grep" "grep --color=auto")
|
||||
("cal" "cal -m $*")
|
||||
("cp" "cp -i $*")
|
||||
("mv" "mv -i $*")
|
||||
("mkdir" "mkdir -p $*")
|
||||
("mkcd" "mkdir -p $* && cd $1")
|
||||
("emacs" "find-file $1")
|
||||
;; ("emacs" "find-file $1")
|
||||
("em" "find-file $1")))
|
||||
(add-to-list 'eshell-command-aliases-list alias))
|
||||
(eshell-write-aliases-list))
|
||||
|
||||
;;; Emacs' standard function fail when output has empty lines.
|
||||
;;; This implementation is more reliable.
|
||||
;;; TODO: Report upstream
|
||||
(defun eshell-next-prompt (n)
|
||||
"Move to end of Nth next prompt in the buffer.
|
||||
See `eshell-prompt-regexp'."
|
||||
(interactive "p")
|
||||
(re-search-forward eshell-prompt-regexp nil t n)
|
||||
(while (not (get-text-property (line-beginning-position) 'read-only) )
|
||||
(re-search-forward eshell-prompt-regexp nil t n))
|
||||
(eshell-skip-prompt))
|
||||
|
||||
(defun eshell-previous-prompt (n)
|
||||
"Move to end of Nth previous prompt in the buffer.
|
||||
See `eshell-prompt-regexp'."
|
||||
(interactive "p")
|
||||
(backward-char)
|
||||
(eshell-next-prompt (- n)))
|
||||
|
||||
(provide 'mode-eshell)
|
||||
|
|
|
@ -31,15 +31,14 @@
|
|||
(evil-mode 1)
|
||||
|
||||
(evil-leader/set-key
|
||||
"RET" 'spawn-terminal
|
||||
"RET" 'eshell
|
||||
"\\" 'toggle-window-split
|
||||
"b" 'buffer-menu
|
||||
"e" 'find-file
|
||||
"k" 'kill-this-buffer
|
||||
"o" 'delete-other-windows
|
||||
"w" 'evil-window-next
|
||||
"|" 'swap-windows
|
||||
)
|
||||
"|" 'swap-windows)
|
||||
(when (require 'magit nil t)
|
||||
;; Use S-SPC instead of SPC to browse commit details.
|
||||
(evil-leader/set-key "v" 'magit-status))
|
||||
|
@ -159,6 +158,54 @@
|
|||
(evil-define-key 'normal package-menu-mode-map "d" 'package-menu-mark-delete)
|
||||
(evil-define-key 'normal package-menu-mode-map "x" 'package-menu-execute)
|
||||
|
||||
;; Eshell
|
||||
(defun evil/eshell-insert ()
|
||||
(interactive)
|
||||
(when (get-text-property (point) 'read-only)
|
||||
(eshell-next-prompt 1))
|
||||
(evil-insert 1))
|
||||
(defun evil/eshell-interrupt-process ()
|
||||
(interactive)
|
||||
(eshell-interrupt-process)
|
||||
(evil-insert 1))
|
||||
(defun evil/eshell-define-keys ()
|
||||
(with-eval-after-load 'tool-helm
|
||||
(evil-define-key '(normal insert) eshell-mode-map "\C-r" 'helm-eshell-history)
|
||||
(evil-define-key 'insert eshell-mode-map "\C-e" 'helm-find-files))
|
||||
(evil-define-key 'normal eshell-mode-map "i" 'evil/eshell-insert)
|
||||
(evil-define-key 'normal eshell-mode-map "\M-k" 'eshell-previous-prompt)
|
||||
(evil-define-key 'normal eshell-mode-map "\M-j" 'eshell-next-prompt)
|
||||
(evil-define-key 'normal eshell-mode-map "0" 'eshell-bol)
|
||||
(evil-define-key 'normal eshell-mode-map (kbd "RET") 'eshell-send-input)
|
||||
(evil-define-key 'normal eshell-mode-map (kbd "C-c C-c") 'evil/eshell-interrupt-process)
|
||||
(evil-define-key '(normal insert) eshell-mode-map "\M-h" 'eshell-backward-argument)
|
||||
(evil-define-key '(normal insert) eshell-mode-map "\M-l" 'eshell-forward-argument))
|
||||
(add-hook 'eshell-mode-hook 'evil/eshell-define-keys)
|
||||
|
||||
;; TODO: When point is on "> ", helm-find-files looks up parent folder. Prevent that.
|
||||
|
||||
;; DONE: eshell-mode-map gets reset on new shells. Make it permanent. Hook? Hook looks good:
|
||||
;; https://stackoverflow.com/questions/11946113/emacs-eshell-how-to-read-content-of-command-line-on-pressing-ret
|
||||
|
||||
;; TODO: Cannot kill emacs when eshell has started: "text is read only"
|
||||
|
||||
;; TODO: Make Evil commands react more dynamically with read-only text.
|
||||
;; Add support for I, C, D, S, s, c*, d*, R, r.
|
||||
(defun evil/eshell-delete-whole-line ()
|
||||
(interactive)
|
||||
(if (not (get-text-property (line-beginning-position) 'read-only))
|
||||
(evil-delete-whole-line (line-beginning-position) (line-end-position))
|
||||
(eshell-return-to-prompt) ; Difference with eshell-bol?
|
||||
(evil-delete-line (point) (line-end-position))))
|
||||
;; (evil-define-key 'normal eshell-mode-map "dd" 'evil/eshell-delete-whole-line)
|
||||
(defun evil/eshell-change-whole-line ()
|
||||
(interactive)
|
||||
(if (not (get-text-property (line-beginning-position) 'read-only))
|
||||
(evil-change-whole-line (line-beginning-position) (line-end-position))
|
||||
(eshell-return-to-prompt) ; Difference with eshell-bol?
|
||||
(evil-change-line (point) (line-end-position))))
|
||||
;; (evil-define-key 'normal eshell-mode-map "cc" 'evil/eshell-change-whole-line)
|
||||
|
||||
;; Go-to-definition.
|
||||
;; From https://emacs.stackexchange.com/questions/608/evil-map-keybindings-the-vim-way
|
||||
(evil-global-set-key
|
||||
|
|
|
@ -54,6 +54,14 @@
|
|||
(helm-make-source "Git files" 'helm-ls-git-source
|
||||
:fuzzy-match helm-ls-git-fuzzy-match)))
|
||||
|
||||
;;; Eshell
|
||||
(add-hook
|
||||
'eshell-mode-hook
|
||||
(lambda ()
|
||||
(eshell-cmpl-initialize)
|
||||
(define-key eshell-mode-map [remap eshell-pcomplete] 'helm-esh-pcomplete)
|
||||
(define-key eshell-mode-map (kbd "C-r") 'helm-eshell-history)))
|
||||
|
||||
;;; Do not exclude any files from 'git grep'.
|
||||
(setq helm-grep-git-grep-command "git --no-pager grep -n%cH --color=always --full-name -e %p -- %f")
|
||||
|
||||
|
|
Loading…
Reference in New Issue