bb-tasks-and-more
Table of Contents
Design is about pulling things apart.
Rich Hickey
With bash-completion
we get a really nice boost for making shell commands from Emacs.
Babashka tasks
completions are for free, together with make
, same as dynamic git
, ssh
and whatever.
Here is the screencast on youtube.
Below are sort of show notes.
1. Make sure you have completions in your shell (bash for me)
shell-file-name ; (setf shell-file-name "/bin/bash")
1.a for bb:
https://book.babashka.org/#_terminal_tab_completion
.bashrc
_bb_complete() { BB_TASKS=$(bb tasks|bb -io '(->> *input* (drop 2) (map #(-> % (str/split #" ") first)))') BB_HELP=$(bb help|bb -io '(->> *input* (map #(->> % (re-find #"^ ([-a-z]+)") second)) (filter some?))') COMPREPLY=($(compgen -W "$BB_TASKS $BB_HELP" -- "${COMP_WORDS[$COMP_CWORD]}")) } complete -f -F _bb_complete bb
2. Setup bash-completion
https://github.com/szermatt/emacs-bash-completion
(use-package bash-completion :config (bash-completion-setup) (setf bash-completion-use-separate-processes t) (defun bash-completion-capf-1 (bol) (bash-completion-dynamic-complete-nocomint (funcall bol) (point) t)) (defun bash-completion-capf () (bash-completion-capf-1 #'point-at-bol)) (add-hook 'sh-mode-hook (defun mm/add-bash-completion () (add-hook 'completion-at-point-functions #'bash-completion-capf nil t))))
read-shell-command
Afterwards, this should work for you:
(I always try with git check...
).
(read-shell-command "your command: ")
read-shell-command
sets up a special keymap where tab
now means completion-at-point
.
read-from-minibuffer, 3thr arg
(read-from-minibuffer "foo: " nil (let ((m (make-sparse-keymap))) (define-key m "f" (defun my-hi () (interactive) (insert "lol"))) m))
Commands that use read-shell-command
- async-shell-command, shell-command
- dired-do-async-shell-command, dired-do-shell-command
- compile
I use project.el
to run async shell commands and compile
in the project root.
Run in any dir?
Design is about splitting things apart.
- Select a current dir, up to you. My main paths would be
consult-dir
,project-switch-project
,- consult-buffer + bookmarks
- Run
async-shell-command
or a friend of it.
More config
(setq async-shell-command-buffer 'new-buffer) (defun path-slug (dir) "Returns the initials of `dir`s path, with the last part appended fully Example: (path-slug \"/foo/bar/hello\") => \"f/b/hello\" " (let* ((path (replace-regexp-in-string "\\." "" dir)) (path (split-string path "/" t)) (path-s (mapconcat (lambda (it) (cl-subseq it 0 1)) (nbutlast (copy-sequence path) 1) "/")) (path-s (concat path-s "/" (car (last path))))) path-s)) (defun mm/put-command-in-async-buff-name (f &rest args) (let* ((path-s (if default-directory (path-slug default-directory) "")) (command (car args)) (buffname (concat path-s " " command)) (shell-command-buffer-name-async (format "*async-shell-command %s*" (string-trim (substring buffname 0 (min (length buffname) 50)))))) (apply f args))) (advice-add 'shell-command :around #'mm/put-command-in-async-buff-name) (add-hook 'comint-mode-hook (defun mm/do-hack-dir-locals (&rest _) (hack-dir-local-variables-non-file-buffer))) ;; it logs a warning when you hack a local ;; Making process-environment buffer-local while locally let-bound! ;; It is sort of want I want though (advice-add #'start-process-shell-command :before #'mm/do-hack-dir-locals) (advice-add 'compile :filter-args (defun mm/always-use-comint-for-compile (args) `(,(car args) t)))
shell
(defun mm/with-current-window-buffer (f &rest args) (with-current-buffer (window-buffer (car (window-list))) (apply f args))) (defun mm/shell-via-async-shell-command () (let ((display-buffer-alist '((".*" display-buffer-same-window)))) (async-shell-command shell-file-name))) (advice-add #'mm/shell-via-async-shell-command :around #'mm/with-current-window-buffer) (setf shell-kill-buffer-on-exit t) (add-hook 'shell-mode-hook (defun mm/shell-dont-mess-with-scroll-conservatively () (setq-local scroll-conservatively 0)))
I invoke mm/shell-via-async-shell-command
with a stumpwm keybinding. This is the only reason I need mm/with-current-window-buffer
irrc.
See also
- Bashing Is Better Than Extending, more in-depth on the same topic. But one of my earlier blog posts and too long.