Skip to content

Commit 8059e5b

Browse files
authored
Merge pull request #2 from a13/master
2 parents 0714564 + d42953d commit 8059e5b

File tree

2 files changed

+87
-37
lines changed

2 files changed

+87
-37
lines changed

README.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,25 +45,36 @@ project's root, add `babashka-project-tasks` to your
4545

4646
![](./videos/4-project.gif)
4747

48+
## Customization
49+
`babashka-command` - The command used to execute Babashka, if [CIDER](https://cider.mx/) is loaded, gets its default value from `cider-babashka-command`, so you don't need to customize both.
50+
51+
`babashka-async-shell-command` - a single-arity Emacs lisp function to call `babashka-command`. The default value is `async-shell-command`, another possible option is `detached-shell-command` from [detached.el](https://sr.ht/~niklaseklund/detached.el/) package.
52+
53+
`babashka-annotation-function` - a function to convert `tasks` hashtable to (task . documentation) alist. The only available option now is `babashka--annotation-function`.
54+
4855
## Installation
4956
Babashka.el is available on [MELPA](https://melpa.org/#/babashka) and [MELPA Stable](https://stable.melpa.org/#/babashka) and can be installed with:
5057

5158
```
5259
M-x package-install RET babashka RET
5360
```
5461

55-
or using `use-package`:
62+
or using `use-package` [ensure feature](https://github.com/jwiegley/use-package#package-installation):
5663

5764
```elisp
5865
(use-package babashka)
5966
```
6067

68+
Don't forget to explicitly ensure the installation:
69+
70+
```elisp
71+
(use-package babashka
72+
:ensure t)
73+
```
74+
if `use-package-always-ensure` is not set.
75+
6176
## Versioning
6277
The project uses [break versioning](https://github.com/ptaoussanis/encore/blob/master/BREAK-VERSIONING.md), meaning that upgrading from 1.0.x to 1.0.y will always be safe, upgrade to 1.y.0 might break something small, and upgrade to y.0.0. will break almost everything. That was a versioning spec in one sentence, by the way.
6378

6479
## Contributing
6580
If you have more ideas about using babashka from Emacs — please submit a PR or a feature request.
66-
67-
68-
69-

babashka.el

Lines changed: 71 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
;;
55
;; Author: Mykhaylo Bilyanskyy <mb@m1k.pw>
66
;; Maintainer: Mykhaylo Bilyanskyy <mb@m1k.pw>
7-
;; Version: 1.0.4
7+
;; Version: 1.0.5
88
;; Package-Requires: ((emacs "27.1") (parseedn "1.1.0"))
99
;;
1010
;; Created: 11 Jun 2023
@@ -37,8 +37,34 @@
3737
;;
3838
;;; Code:
3939
(require 'parseedn)
40+
(require 'seq)
4041
(require 'project)
4142

43+
(defgroup babashka nil
44+
"Babashka Tasks Interface"
45+
:group 'external)
46+
47+
(defcustom babashka-async-shell-command #'async-shell-command
48+
"Emacs function to run shell commands."
49+
:group 'babashka
50+
:type 'function
51+
:safe #'functionp)
52+
53+
(defcustom babashka-command
54+
(or (when (featurep 'cider)
55+
cider-babashka-command)
56+
"bb")
57+
"The command used to execute Babashka."
58+
:group 'babashka
59+
:type 'string
60+
:safe #'stringp)
61+
62+
(defcustom babashka-annotation-function nil
63+
"Function to annotate completions, can be `babashka--annotation-function' or a similar one."
64+
:group 'babashka
65+
:type '(choice (const :tag "Don't annotate." nil)
66+
function))
67+
4268
(defmacro babashka--comment (&rest _)
4369
"Ignore body eval to nil."
4470
nil)
@@ -50,51 +76,66 @@
5076
(insert-file-contents file-path)
5177
(buffer-string))))
5278

53-
(defun babashka--run-shell-command-in-directory (directory command &optional output-buffer)
79+
(defun babashka--run-shell-command-in-directory (directory command)
5480
"Run a shell COMMAND in a DIRECTORY and display output in OUTPUT-BUFFER."
5581
(let ((default-directory directory))
56-
(async-shell-command command output-buffer)))
82+
(funcall babashka-async-shell-command command)))
5783

5884
(defun babashka--locate-bb-edn (&optional dir)
5985
"Recursively search upwards from DIR for bb.edn file."
60-
(if-let ((found (locate-dominating-file (or dir default-directory) "bb.edn")))
61-
(concat found "bb.edn")))
86+
(when-let ((found (locate-dominating-file (or dir default-directory) "bb.edn")))
87+
(concat found "bb.edn")))
6288

6389
(defun babashka--get-tasks-hash-table (file-path)
6490
"List babashka tasks as hash table from edn file unde FILE-PATH."
65-
(thread-last
66-
file-path
91+
(thread-last file-path
6792
babashka--read-edn-file
6893
(gethash :tasks)))
6994

95+
7096
(defun babashka--escape-args (s)
7197
"Shell quote parts of the string S that require it."
7298
(mapconcat #'shell-quote-argument (split-string s) " "))
7399

100+
(defun babashka--annotation-function (s)
101+
"Annotate S using current completiong table."
102+
(when-let ((item (assoc s minibuffer-completion-table)))
103+
(concat " " (cdr item))))
104+
105+
(defun babashka--tasks-to-annotated-names (tasks)
106+
"Convert TASKS to annotated alist."
107+
(let (results)
108+
(maphash (lambda (key value)
109+
(let ((task-name (symbol-name key)))
110+
(unless (string-prefix-p ":" task-name)
111+
(push (cons task-name (gethash :doc value))
112+
results))))
113+
tasks)
114+
results))
115+
74116
(defun babashka--run-task (dir &optional do-not-recurse)
75117
"Select a task to run from bb.edn in DIR or its parents.
76118
77119
If DO-NOT-RECURSE is passed and is not nil, don't search for bb.edn in
78120
DIR's parents."
79-
(if-let*
80-
((bb-edn (if do-not-recurse
81-
(let ((f (concat dir "/bb.edn"))) (and (file-exists-p f) f))
82-
(babashka--locate-bb-edn dir))))
83-
(let* ((bb-edn-dir (file-name-directory bb-edn))
84-
(tasks (babashka--get-tasks-hash-table bb-edn))
85-
(task-names (thread-last tasks hash-table-keys (mapcar #'symbol-name)))
86-
(sorted-task-names (sort task-names #'string<)))
87-
(if tasks
88-
(thread-last
89-
sorted-task-names
121+
(if-let* ((bb-edn (if do-not-recurse
122+
(let ((f (concat dir "/bb.edn")))
123+
(and (file-exists-p f) f))
124+
(babashka--locate-bb-edn dir))))
125+
(if-let* ((bb-edn-dir (file-name-directory bb-edn))
126+
(tasks (babashka--get-tasks-hash-table bb-edn)))
127+
(let ((completion-extra-properties (when babashka-annotation-function
128+
`(:annotation-function ,babashka-annotation-function))))
129+
(thread-last tasks
130+
babashka--tasks-to-annotated-names
90131
(completing-read "Run tasks: ")
91132
babashka--escape-args
92-
(format "bb %s")
93-
(babashka--run-shell-command-in-directory bb-edn-dir))
94-
(message "No tasks found in %s" bb-edn)))
95-
(message (if do-not-recurse
96-
"No bb.edn found in directory."
97-
"No bb.edn found in directory or any of the parents."))))
133+
(format "%s %s" babashka-command)
134+
(babashka--run-shell-command-in-directory bb-edn-dir)))
135+
(message "No tasks found in %s" bb-edn))
136+
(let ((msg-suffix (if do-not-recurse "" " or any of the parents")))
137+
(message (format "No bb.edn found in directory %s%s." dir msg-suffix)))))
138+
98139

99140
;;;###autoload
100141
(defun babashka-tasks (arg)
@@ -106,12 +147,11 @@ a task.
106147
107148
When called with interactive ARG prompts for directory."
108149
(interactive "P")
109-
(let* ((dir (if arg
110-
(read-file-name "Enter a path to bb.edn: ")
111-
default-directory)))
112-
(if dir
113-
(babashka--run-task dir)
114-
(message "Not in a file buffer. Run babashka-tasks when visiting one of your project's files."))))
150+
(if-let* ((dir (if arg
151+
(read-file-name "Enter a path to bb.edn: ")
152+
default-directory)))
153+
(babashka--run-task dir)
154+
(message "Not in a file buffer. Run babashka-tasks when visiting one of your project's files.")))
115155

116156
;;;###autoload
117157
(defun babashka-project-tasks ()
@@ -125,8 +165,7 @@ For example by evaling:
125165
\(add-to-list \\='project-switch-commands
126166
\\='(babashka-project-tasks \"Babashka task\" \"t\"))"
127167
(interactive)
128-
(thread-first
129-
(project-current t)
168+
(thread-first (project-current t)
130169
project-root
131170
(babashka--run-task t)))
132171

0 commit comments

Comments
 (0)