Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial prototype for modules support #70

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 136 additions & 4 deletions justl.el
Original file line number Diff line number Diff line change
Expand Up @@ -537,14 +537,15 @@ They are returned as objects, as per the JSON output of \"just --dump\"."
(define-key map (kbd "h") 'justl-help-popup)
(define-key map (kbd "w") 'justl--exec-recipe-with-args)
(define-key map (kbd "W") 'justl-no-exec-shell)
(define-key map (kbd "m") 'justl--show-modules)
(define-key map (kbd "RET") 'justl-go-to-recipe)
map)
"Keymap for `justl-mode'.")

(defun justl--buffer-name ()
(defun justl--buffer-name (is-module)
"Return justl buffer name."
(let ((justfile (justl--find-justfile default-directory)))
(format "*just [%s]*" justfile)))
(format "*just [%s] %s*" justfile (if is-module "(Module)" ""))))

(defun justl--tabulated-entries (recipes)
"Turn RECIPES to tabulated entries."
Expand All @@ -556,6 +557,16 @@ They are returned as objects, as per the JSON output of \"just --dump\"."
(or (justl--recipe-desc r) ""))))
recipes))

(defun justl--tabulated-modules-entries (modules)
"Turn MODULES to tabulated entries."
(mapcar (lambda (m)
(list
;; Comparison key, used to restore line number after refresh
(just-module-name m)
(vector (propertize (just-module-name m) 'module m)
(or (just-module-doc m) ""))))
modules))

(defun justl-exec-eshell (&optional no-send)
"Execute just recipe in eshell.
When NO-SEND is non-nil, the command is inserted ready for editing but is
Expand Down Expand Up @@ -653,10 +664,16 @@ is not executed."
("E" "Exec with shell" justl-exec-shell)
("w" "Exec with args" justl--exec-recipe-with-args)
("W" "Open shell with args" justl-no-exec-shell)
("m" "Show modules" justl--show-modules)
("RET" "Go to recipe" justl-go-to-recipe)
]
])

(defun justl--show-modules ()
"Open modules buffer."
(interactive)
(justl-module))

(defun justl--read-arg (arg)
"Read a value for ARG from the minibuffer."
(let ((default (justl--arg-default arg)))
Expand Down Expand Up @@ -714,22 +731,57 @@ is not executed."
(get-text-property 0 'recipe (aref entry 0))
(user-error "There is no recipe on the current line"))))

(defun justl--get-module-under-cursor ()
"Utility function to get the name of the module under the cursor."
(let ((entry (tabulated-list-get-entry)))
(if entry
(get-text-property 0 'module (aref entry 0))
(user-error "There is no module on the current line"))))

(defun justl--refresh-buffer ()
"Refresh justl buffer."
(interactive)
(let* ((justfile (justl--find-justfile default-directory))
(entries (justl--get-recipes justfile)))
(setq tabulated-list-entries (justl--tabulated-entries entries))
(tabulated-list-print t)))

(cl-defstruct just-module
;; Module name
name
;; Optional module documentation
doc
;; Source path of the module
source
)

(defun justl--module-refresh-buffer ()
"Refresh justl module buffer."
(interactive)
(let* ((justfile (justl--find-justfile default-directory))
(modules (justl--get-modules justfile)))
(setq tabulated-list-entries (justl--tabulated-modules-entries modules))
(tabulated-list-print t)
(message "justl-mode: Refreshed")))
(message "justl-module-mode: Refreshed")))

;;; todo: For easily integrating it, we need something like this
;;; integrated upstream:
;;; https://github.com/casey/just/issues/2252#issuecomment-2474171211
(defun justl--get-modules (justfile)
"Return all the modules from JUSTFILE.
They are returned as objects, as per the JSON output of \"just --dump\"."
(let-alist (justl--parse justfile)
(mapcar (lambda (x) (make-just-module :name (symbol-name (car x))
:doc (alist-get 'doc (cdr x))
:source (alist-get 'source (cdr x)))) .modules)))

;;;###autoload
(defun justl ()
"Invoke the justl buffer."
(interactive)
(unless (justl--find-justfile default-directory)
(error "No justfile found"))
(justl--pop-to-buffer (justl--buffer-name))
(justl--pop-to-buffer (justl--buffer-name nil))
(justl-mode)
(justl--refresh-buffer))

Expand All @@ -746,5 +798,85 @@ is not executed."
(tabulated-list-print t)
(hl-line-mode 1))

;;;###autoload
(defun justl-module ()
"Invoke the justl-module buffer."
(interactive)
(unless (justl--find-justfile default-directory)
(error "No justfile found"))
(justl--pop-to-buffer (justl--buffer-name t))
(justl-module-mode)
(justl--module-refresh-buffer))

(defvar justl-module-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "g") 'justl--module-refresh-buffer)
(define-key map (kbd "e") 'justl-exec-module)
(define-key map (kbd "?") 'justl-module-help-popup)
(define-key map (kbd "h") 'justl-module-help-popup)
(define-key map (kbd "o") 'justl--module-open-justl)
(define-key map (kbd "RET") 'justl--go-to-module)
map)
"Keymap for `justl-module-mode'.")

(define-derived-mode justl-module-mode tabulated-list-mode "Justl (M)"
"Special mode for justl module buffers."
:group 'justl
(buffer-disable-undo)
(setq truncate-lines t)
(setq tabulated-list-format
(vector (list "MODULES" justl-recipe-width t)
(list "DESCRIPTION" 20 t)))
(setq tabulated-list-sort-key nil)
(tabulated-list-init-header)
(tabulated-list-print t)
(hl-line-mode 1))

(transient-define-prefix justl-module-help-popup ()
"Justl Module Menu."
[["Arguments"
("-s" "Clear shell arguments" "--clear-shell-args")
("-d" "Dry run" "--dry-run")
("-e" "Disable .env file" "--no-dotenv")
("-h" "Highlight" "--highlight")
("-n" "Disable Highlight" "--no-highlight")
("-q" "Quiet" "--quiet")
("-v" "Verbose output" "--verbose")
("-u" "Unstable" "--unstable")
(justl--color)
]
["Actions"
;; global
("g" "Refresh" justl-module)
("e" "Exec" justl-exec-module)
("o" "Open justl buffer for the module" justl--module-open-justl)
("RET" "Go to module" justl--go-to-module)
]
])

(defun justl-exec-module ()
"Execute first recipe of the module."
(interactive)
(let* ((module (justl--get-module-under-cursor))
(default-directory (f-dirname (just-module-source module))))
(justl--exec
justl-executable
(just-module-name module)
(append (transient-args 'justl-module-help-popup) (cons (just-module-name module) nil)))))

(defun justl--go-to-module ()
"Go to the module path."
(interactive)
(let* ((module (justl--get-module-under-cursor)))
(find-file (just-module-source module))
(goto-char (point-min))))

(defun justl--module-open-justl ()
"Open justl buffer for that specific module."
(interactive)
(let* ((module (justl--get-module-under-cursor))
(default-directory (f-dirname (just-module-source module))))
(justl)))

(provide 'justl)
;;; justl.el ends here
32 changes: 16 additions & 16 deletions test/justl-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@

(ert-deftest justl--lists-recipe ()
(justl)
(with-current-buffer (justl--buffer-name)
(with-current-buffer (justl--buffer-name nil)
(let ((buf-string (buffer-string)))
(should (search-forward "plan" nil t))))
(kill-buffer (justl--buffer-name)))
(kill-buffer (justl--buffer-name nil)))

(defun justl--wait-till-exit (buffer)
"Wait till the BUFFER has exited."
Expand All @@ -47,38 +47,38 @@

(ert-deftest justl--execute-recipe ()
(justl)
(with-current-buffer (justl--buffer-name)
(with-current-buffer (justl--buffer-name nil)
(search-forward "plan")
(justl-exec-recipe)
(justl--wait-till-exit (justl--recipe-output-buffer "plan")))
(with-current-buffer (justl--recipe-output-buffer "plan")
(let ((buf-string (buffer-substring-no-properties (point-min) (point-max))))
(should (s-contains? "planner" buf-string))))
(kill-buffer (justl--buffer-name))
(kill-buffer (justl--buffer-name nil))
(kill-buffer (justl--recipe-output-buffer "plan")))

(ert-deftest justl--execute-test-exit-status ()
(justl)
(with-current-buffer (justl--buffer-name)
(with-current-buffer (justl--buffer-name nil)
(search-forward "plan")
(justl-exec-recipe)
(justl--wait-till-exit (justl--recipe-output-buffer "plan")))
(with-current-buffer (justl--recipe-output-buffer "plan")
(let ((buf-string (buffer-substring-no-properties (point-min) (point-max))))
(should (s-contains? "Target execution finished" buf-string))))
(kill-buffer (justl--buffer-name))
(kill-buffer (justl--buffer-name nil))
(kill-buffer (justl--recipe-output-buffer "plan")))

(ert-deftest justl--fail-recipe ()
(justl)
(with-current-buffer (justl--buffer-name)
(with-current-buffer (justl--buffer-name nil)
(search-forward "fail")
(justl-exec-recipe)
(justl--wait-till-exit (justl--recipe-output-buffer "fail"))
(with-current-buffer (justl--recipe-output-buffer "fail")
(let ((buf-string (buffer-substring-no-properties (point-min) (point-max))))
(should (s-contains? "exited abnormally" buf-string))))
(kill-buffer (justl--buffer-name))
(kill-buffer (justl--buffer-name nil))
(kill-buffer (justl--recipe-output-buffer "fail"))))

(ert-deftest justl--find-justfile-check ()
Expand All @@ -87,28 +87,28 @@
(ert-deftest justl--execute-recipe-which-prints-carriage-return ()
"Carriage return should be handled in a way that allows overwriting lines."
(justl)
(with-current-buffer (justl--buffer-name)
(with-current-buffer (justl--buffer-name nil)
(search-forward "carriage-return")
(justl-exec-recipe)
(justl--wait-till-exit (justl--recipe-output-buffer "carriage-return")))
(with-current-buffer (justl--recipe-output-buffer "carriage-return")
(let ((buf-string (buffer-substring-no-properties (point-min) (point-max))))
(should (s-contains? "DONE\n" buf-string))
(should-not (s-contains? "1/3\r2/3\r3/3\rDONE\n" buf-string))))
(kill-buffer (justl--buffer-name))
(kill-buffer (justl--buffer-name nil))
(kill-buffer (justl--recipe-output-buffer "carriage-return")))

(ert-deftest justl--execute-recipe-with-color ()
"A target printing color is handled properly."
(justl)
(with-current-buffer (justl--buffer-name)
(with-current-buffer (justl--buffer-name nil)
(search-forward "color")
(justl-exec-recipe)
(justl--wait-till-exit (justl--recipe-output-buffer "color")))
(with-current-buffer (justl--recipe-output-buffer "color")
(let ((buf-string (buffer-substring-no-properties (point-min) (point-max))))
(should (s-contains? "This is red text\n" buf-string))))
(kill-buffer (justl--buffer-name))
(kill-buffer (justl--buffer-name nil))
(kill-buffer (justl--recipe-output-buffer "color")))

(ert-deftest justl--execute-default-recipe ()
Expand Down Expand Up @@ -152,27 +152,27 @@
(let ((current justl-per-recipe-buffer))
(customize-set-variable 'justl-per-recipe-buffer 't)
(justl)
(with-current-buffer (justl--buffer-name)
(with-current-buffer (justl--buffer-name nil)
(search-forward "plan")
(justl-exec-recipe)
(justl--wait-till-exit "*just-plan*"))
(with-current-buffer "*just-plan*"
(let ((buf-string (buffer-substring-no-properties (point-min) (point-max))))
(should (s-contains? "Target execution finished" buf-string))))
(kill-buffer (justl--buffer-name))
(kill-buffer (justl--buffer-name nil))
(kill-buffer "*just-plan*")
(customize-set-variable 'justl-per-recipe-buffer current)))

(ert-deftest justl--no-private-recipe-by-default ()
(justl)
(with-current-buffer (justl--buffer-name)
(with-current-buffer (justl--buffer-name nil)
(let ((buf-string (buffer-substring-no-properties (point-min) (point-max))))
(should-not (s-contains? "_private" buf-string)))))

(ert-deftest justl--private-recipe-visible ()
(let ((justl-include-private-recipes t))
(justl))
(with-current-buffer (justl--buffer-name)
(with-current-buffer (justl--buffer-name nil)
(let ((buf-string (buffer-substring-no-properties (point-min) (point-max))))
(should (s-contains? "_private" buf-string)))))

Expand Down
Loading