-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from a13/master
- Loading branch information
Showing
2 changed files
with
87 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
;; | ||
;; Author: Mykhaylo Bilyanskyy <[email protected]> | ||
;; Maintainer: Mykhaylo Bilyanskyy <[email protected]> | ||
;; Version: 1.0.4 | ||
;; Version: 1.0.5 | ||
;; Package-Requires: ((emacs "27.1") (parseedn "1.1.0")) | ||
;; | ||
;; Created: 11 Jun 2023 | ||
|
@@ -37,8 +37,34 @@ | |
;; | ||
;;; Code: | ||
(require 'parseedn) | ||
(require 'seq) | ||
(require 'project) | ||
|
||
(defgroup babashka nil | ||
"Babashka Tasks Interface" | ||
:group 'external) | ||
|
||
(defcustom babashka-async-shell-command #'async-shell-command | ||
"Emacs function to run shell commands." | ||
:group 'babashka | ||
:type 'function | ||
:safe #'functionp) | ||
|
||
(defcustom babashka-command | ||
(or (when (featurep 'cider) | ||
cider-babashka-command) | ||
"bb") | ||
"The command used to execute Babashka." | ||
:group 'babashka | ||
:type 'string | ||
:safe #'stringp) | ||
|
||
(defcustom babashka-annotation-function nil | ||
"Function to annotate completions, can be `babashka--annotation-function' or a similar one." | ||
:group 'babashka | ||
:type '(choice (const :tag "Don't annotate." nil) | ||
function)) | ||
|
||
(defmacro babashka--comment (&rest _) | ||
"Ignore body eval to nil." | ||
nil) | ||
|
@@ -50,51 +76,66 @@ | |
(insert-file-contents file-path) | ||
(buffer-string)))) | ||
|
||
(defun babashka--run-shell-command-in-directory (directory command &optional output-buffer) | ||
(defun babashka--run-shell-command-in-directory (directory command) | ||
"Run a shell COMMAND in a DIRECTORY and display output in OUTPUT-BUFFER." | ||
(let ((default-directory directory)) | ||
(async-shell-command command output-buffer))) | ||
(funcall babashka-async-shell-command command))) | ||
|
||
(defun babashka--locate-bb-edn (&optional dir) | ||
"Recursively search upwards from DIR for bb.edn file." | ||
(if-let ((found (locate-dominating-file (or dir default-directory) "bb.edn"))) | ||
(concat found "bb.edn"))) | ||
(when-let ((found (locate-dominating-file (or dir default-directory) "bb.edn"))) | ||
(concat found "bb.edn"))) | ||
|
||
(defun babashka--get-tasks-hash-table (file-path) | ||
"List babashka tasks as hash table from edn file unde FILE-PATH." | ||
(thread-last | ||
file-path | ||
(thread-last file-path | ||
babashka--read-edn-file | ||
(gethash :tasks))) | ||
|
||
|
||
(defun babashka--escape-args (s) | ||
"Shell quote parts of the string S that require it." | ||
(mapconcat #'shell-quote-argument (split-string s) " ")) | ||
|
||
(defun babashka--annotation-function (s) | ||
"Annotate S using current completiong table." | ||
(when-let ((item (assoc s minibuffer-completion-table))) | ||
(concat " " (cdr item)))) | ||
|
||
(defun babashka--tasks-to-annotated-names (tasks) | ||
"Convert TASKS to annotated alist." | ||
(let (results) | ||
(maphash (lambda (key value) | ||
(let ((task-name (symbol-name key))) | ||
(unless (string-prefix-p ":" task-name) | ||
(push (cons task-name (gethash :doc value)) | ||
results)))) | ||
tasks) | ||
results)) | ||
|
||
(defun babashka--run-task (dir &optional do-not-recurse) | ||
"Select a task to run from bb.edn in DIR or its parents. | ||
If DO-NOT-RECURSE is passed and is not nil, don't search for bb.edn in | ||
DIR's parents." | ||
(if-let* | ||
((bb-edn (if do-not-recurse | ||
(let ((f (concat dir "/bb.edn"))) (and (file-exists-p f) f)) | ||
(babashka--locate-bb-edn dir)))) | ||
(let* ((bb-edn-dir (file-name-directory bb-edn)) | ||
(tasks (babashka--get-tasks-hash-table bb-edn)) | ||
(task-names (thread-last tasks hash-table-keys (mapcar #'symbol-name))) | ||
(sorted-task-names (sort task-names #'string<))) | ||
(if tasks | ||
(thread-last | ||
sorted-task-names | ||
(if-let* ((bb-edn (if do-not-recurse | ||
(let ((f (concat dir "/bb.edn"))) | ||
(and (file-exists-p f) f)) | ||
(babashka--locate-bb-edn dir)))) | ||
(if-let* ((bb-edn-dir (file-name-directory bb-edn)) | ||
(tasks (babashka--get-tasks-hash-table bb-edn))) | ||
(let ((completion-extra-properties (when babashka-annotation-function | ||
`(:annotation-function ,babashka-annotation-function)))) | ||
(thread-last tasks | ||
babashka--tasks-to-annotated-names | ||
(completing-read "Run tasks: ") | ||
babashka--escape-args | ||
(format "bb %s") | ||
(babashka--run-shell-command-in-directory bb-edn-dir)) | ||
(message "No tasks found in %s" bb-edn))) | ||
(message (if do-not-recurse | ||
"No bb.edn found in directory." | ||
"No bb.edn found in directory or any of the parents.")))) | ||
(format "%s %s" babashka-command) | ||
(babashka--run-shell-command-in-directory bb-edn-dir))) | ||
(message "No tasks found in %s" bb-edn)) | ||
(let ((msg-suffix (if do-not-recurse "" " or any of the parents"))) | ||
(message (format "No bb.edn found in directory %s%s." dir msg-suffix))))) | ||
|
||
|
||
;;;###autoload | ||
(defun babashka-tasks (arg) | ||
|
@@ -106,12 +147,11 @@ a task. | |
When called with interactive ARG prompts for directory." | ||
(interactive "P") | ||
(let* ((dir (if arg | ||
(read-file-name "Enter a path to bb.edn: ") | ||
default-directory))) | ||
(if dir | ||
(babashka--run-task dir) | ||
(message "Not in a file buffer. Run babashka-tasks when visiting one of your project's files.")))) | ||
(if-let* ((dir (if arg | ||
(read-file-name "Enter a path to bb.edn: ") | ||
default-directory))) | ||
(babashka--run-task dir) | ||
(message "Not in a file buffer. Run babashka-tasks when visiting one of your project's files."))) | ||
|
||
;;;###autoload | ||
(defun babashka-project-tasks () | ||
|
@@ -125,8 +165,7 @@ For example by evaling: | |
\(add-to-list \\='project-switch-commands | ||
\\='(babashka-project-tasks \"Babashka task\" \"t\"))" | ||
(interactive) | ||
(thread-first | ||
(project-current t) | ||
(thread-first (project-current t) | ||
project-root | ||
(babashka--run-task t))) | ||
|
||
|