I’ve been spending some of my time off customizing my Emacs config. I’ve used Emacs a long time but I’ve never dipped into writing Emacs Lisp to customize it. Now is the time.
I started trying to use the Emacs shell for various things (previous
blog post), but one of the things I didn’t
like was the history completion. I wanted my
Ctrl-r to act like
fzf rather than built-in commands
that just pull the first thing that prefix-matches. It’s nice to see a
list of what else is in the history and to have some sort of fuzzy
It took about 10 minutes to patch together something searching the
M-x describe-function to find other relevant code
inside Emacs itself. Here is what I came up with:
(defun timmy/counsel-eshell-history-action (cmd) "Insert cmd into the buffer" (interactive) (insert cmd)) (defun timmy/counsel-eshell-history (&optional initial-input) "Find command from eshell history. INITIAL-INPUT can be given as the initial minibuffer input." (interactive) (ivy-read "Find cmd: " (timmy/eshell-history-list) :initial-input initial-input :action #'timmy/counsel-eshell-history-action :caller 'timmy/counsel-eshell-history)) (defun timmy/eshell-history-list () "return the eshell history as a list" (and (or (not (ring-p eshell-history-ring)) (ring-empty-p eshell-history-ring)) (error "No history")) (let* ((index (1- (ring-length eshell-history-ring))) (ref (- (ring-length eshell-history-ring) index)) (items (list))) (while (>= index 0) (setq items (cons (format "%s" (eshell-get-history index)) items) index (1- index) ref (1+ ref))) items)) (use-package esh-mode :ensure nil :bind (:map eshell-mode-map ("C-r" . timmy/counsel-eshell-history)))
I use counsel/ivy already, so I basically just wrote a function to gather the eshell history and pass it to counsel. Selecting the command is pretty straightforward–it just inserts the text into the buffer. There are probably a lot of better ways to write this code, but that’s not the point.
On a somewhat related note, I’m also enjoying setting up global bindings for my function keys. Here is what I have as of right now, but this will probably change a lot as I get a feel for what I like:
(global-set-key (kbd "<f1>") 'eshell) (global-set-key (kbd "<f2>") 'recompile) (global-set-key (kbd "<f5>") 'deadgrep) (global-set-key (kbd "<f6>") 'counsel-git) (global-set-key (kbd "<f9>") 'dired) (global-set-key (kbd "<f10>") 'magit-status) (global-set-key (kbd "<f11>") 'bury-buffer) (global-set-key (kbd "<f12>") 'delete-other-windows)