Skip to content

Commit

Permalink
replace async-shell-command' with define-compilation-mode'
Browse files Browse the repository at this point in the history
* introduce a `elixir-mix-compilation-mode' with `define-compilation-mode'
* much cleaner `elixir-mix-execute' function. Remove limitations
  about which tasks could be run through it.
* introduce `elixir-mix--build-runner-cmdlist' function to handle
  different parameter situations.
  • Loading branch information
tonini committed Oct 26, 2013
1 parent be631a3 commit 485a42b
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 49 deletions.
115 changes: 69 additions & 46 deletions elixir-mix.el
Expand Up @@ -100,20 +100,21 @@
;; ;;
;; M-x elixir-mix-execute ;; M-x elixir-mix-execute
;; ;;
;; Run any command in the context of the application, ;; Run any command in the context of the application.
;; except `help` and `new`.
;; Just run any command as you like, including arguments ;; Just run any command as you like, including arguments
;; for the specific command. (example: test --quick) ;; for the specific command. (example: test --quick)
;; ;;


;;; Code: ;;; Code:


(require 'compile)

(defcustom elixir-mix-command "mix" (defcustom elixir-mix-command "mix"
"The shell command for mix." "The shell command for mix."
:type 'string :type 'string
:group 'elixir-mix) :group 'elixir-mix)


(defvar elixir-mix-buffer-name "*MIX*" (defvar elixir-mix-buffer-name "*mix*"
"Name of the mix output buffer.") "Name of the mix output buffer.")


(defvar elixir-mix--elixir-project-root-indicator (defvar elixir-mix--elixir-project-root-indicator
Expand All @@ -128,36 +129,57 @@
'("local" "local.install" "local.rebar" "local.uninstall") '("local" "local.install" "local.rebar" "local.uninstall")
"List of all local.* available commands.") "List of all local.* available commands.")


(defvar elixir-mix--local-install-option-types (defvar elixir-mix--compilation-buffer-name nil
'("path" "url") "Used to store compilation name so recompilation works as expected.")
(make-variable-buffer-local 'elixir-mix--compilation-buffer-name)

(defvar elixir-mix--local-install-option-types '("path" "url")
"List of local.install option types.") "List of local.install option types.")


(defun elixir-mix--kill-any-orphan-proc ()
"Ensure any dangling buffer process is killed."
(let ((orphan-proc (get-buffer-process (buffer-name))))
(when orphan-proc
(kill-process orphan-proc))))

(define-compilation-mode elixir-mix-compilation-mode "ElixirMix"
"Mix compilation mode."
(progn
;; Set any bound buffer name buffer-locally
(setq elixir-mix--compilation-buffer-name elixir-mix--compilation-buffer-name)
(set (make-local-variable 'kill-buffer-hook)
'elixir-mix--compilation-kill-any-orphan-proc)))

(defun elixir-mix--elixir-project-root (&optional directory) (defun elixir-mix--elixir-project-root (&optional directory)
"Finds the root directory of the project by walking the "Finds the root directory of the project by walking the
directory tree until it finds a elixir project root indicator." directory tree until it finds a elixir project root indicator."
(let* ((directory (file-name-as-directory (or directory (expand-file-name default-directory))))) (let* ((directory (file-name-as-directory (or directory (expand-file-name default-directory)))))
(locate-dominating-file directory elixir-mix--elixir-project-root-indicator))) (locate-dominating-file directory elixir-mix--elixir-project-root-indicator)))


(defun elixir-mix--get-buffer (name) (defun elixir-mix--completing-read (prompt cmdlist)
"Get and kills a buffer if exists and returns a new one." (completing-read prompt cmdlist nil t nil nil (car cmdlist)))
(let ((buffer (get-buffer name)))
(when buffer (kill-buffer buffer)) (defun elixir-mix--build-runner-cmdlist (command)
(generate-new-buffer name))) "Build the commands list for the runner."

(remove "" (elixir-mix-flatten
(defun elixir-mix--buffer-setup (buffer) (list (if (stringp command)
"Setup the mix buffer before display." (split-string command)
(display-buffer buffer) command)))))
(with-current-buffer buffer
(setq buffer-read-only nil) (defun elixir-mix-task-runner (name cmdlist)
(local-set-key "q" 'quit-window))) "In a buffer identified by NAME, run CMDLIST in `elixir-mix-compilation-mode'.

Returns the compilation buffer."
(defun elixir-mix--run-command-async (command) (save-some-buffers (not compilation-ask-about-save)
(let ((buffer (elixir-mix--get-buffer elixir-mix-buffer-name))) (when (boundp 'compilation-save-buffers-predicate)
(async-shell-command (format "%s %s" elixir-mix-command command) buffer) compilation-save-buffers-predicate))
(elixir-mix--buffer-setup buffer))) (let* ((elixir-mix--compilation-buffer-name name))

(with-current-buffer
(defun elixir-mix--completing-read (prompt command-list) (compilation-start
(completing-read prompt command-list nil t nil nil (car command-list))) (mapconcat 'shell-quote-argument
(append (list elixir-mix-command) cmdlist)
" ")
'elixir-mix-compilation-mode
(lambda (b) elixir-mix--compilation-buffer-name)))))


(defun elixir-mix-flatten (alist) (defun elixir-mix-flatten (alist)
(cond ((null alist) nil) (cond ((null alist) nil)
Expand All @@ -168,7 +190,7 @@
(defun elixir-mix-new (name) (defun elixir-mix-new (name)
"Create a new elixir project with mix." "Create a new elixir project with mix."
(interactive "Gmix new: ") (interactive "Gmix new: ")
(elixir-mix--run-command-async (format "new %s" name))) (elixir-mix-execute (list "new" (expand-file-name name))))


(defun elixir-mix-test () (defun elixir-mix-test ()
"Run the whole elixir test suite." "Run the whole elixir test suite."
Expand All @@ -183,22 +205,22 @@
(defun elixir-mix-test-file (filename) (defun elixir-mix-test-file (filename)
"Run <mix test> with the given `filename`" "Run <mix test> with the given `filename`"
(interactive "Fmix test: ") (interactive "Fmix test: ")
(elixir-mix--test-file filename)) (elixir-mix--test-file (expand-file-name filename)))


(defun elixir-mix--test-file (filename) (defun elixir-mix--test-file (filename)
(when (not (file-exists-p filename)) (when (not (file-exists-p filename))
(error "The given file doesn't exists")) (error "The given file doesn't exists"))
(elixir-mix-execute (format "test %s" filename))) (elixir-mix-execute (list "test" (expand-file-name filename))))


(defun elixir-mix-compile () (defun elixir-mix-compile (command)
"Compile the whole elixir project." "Compile the whole elixir project."
(interactive) (interactive "Mmix compile: ")
(elixir-mix-execute "compile")) (elixir-mix-execute (list "compile" command)))


(defun elixir-mix-run (code) (defun elixir-mix-run (command)
"Runs the given expression in the elixir application context." "Runs the given file or expression in the context of the application."
(interactive "Mmix run: ") (interactive "Mmix run: ")
(elixir-mix-execute (format "run -e '%s'" code))) (elixir-mix-execute (list "run" command)))


(defun elixir-mix-deps-with-prompt (command) (defun elixir-mix-deps-with-prompt (command)
"Prompt for mix deps commands." "Prompt for mix deps commands."
Expand Down Expand Up @@ -227,30 +249,31 @@
(defun elixir-mix-local-install-with-path (path) (defun elixir-mix-local-install-with-path (path)
"Runs local.install and prompt for a <path> as argument." "Runs local.install and prompt for a <path> as argument."
(interactive "fmix local.install PATH: ") (interactive "fmix local.install PATH: ")
(elixir-mix-execute (format "local.install %s" path))) (elixir-mix-execute (list "local.install" path)))


(defun elixir-mix-local-install-with-url (url) (defun elixir-mix-local-install-with-url (url)
"Runs local.install and prompt for a <url> as argument." "Runs local.install and prompt for a <url> as argument."
(interactive "Mmix local.install URL: ") (interactive "Mmix local.install URL: ")
(elixir-mix-execute (format "local.install %s" url))) (elixir-mix-execute (list "local.install" url)))


(defun elixir-mix-help (command) (defun elixir-mix-help (command)
"Show help output for a specific mix command." "Show help output for a specific mix command."
(interactive "Mmix help: ") (interactive "Mmix help: ")
(elixir-mix--run-command-async (format "help %s" command))) (elixir-mix-execute (list "help" command)))

(defun elixir-mix--establish-project-root-directory ()
"Set the default-directory to the Elixir project root."
(let ((project-root (elixir-mix--elixir-project-root)))
(if (not project-root)
(error "Couldn't find any elixir project root")
(setq default-directory project-root))))


(defun elixir-mix-execute (command) (defun elixir-mix-execute (command)
"Run a mix command." "Run a mix command."
(interactive "Mmix: ") (interactive "Mmix: ")
(cond ((string= command "") (error "There is no such command")) (elixir-mix--establish-project-root-directory)
((string-match "^new" command) (elixir-mix-task-runner elixir-mix-buffer-name
(error "Please use the `elixir-mix-new (name)` function to create a new elixir project")) (elixir-mix--build-runner-cmdlist command)))
((string-match "^help" command)
(error "Please use the `elixir-mix-help (command)` function to get a mix command specific help")))
(let ((project-root (elixir-mix--elixir-project-root)))
(when (not project-root) (error "Couldn't find any elixir project root"))
(setq default-directory (elixir-mix--elixir-project-root))
(elixir-mix--run-command-async command)))


;;;###autoload ;;;###autoload
(define-minor-mode global-elixir-mix-mode (define-minor-mode global-elixir-mix-mode
Expand Down
14 changes: 11 additions & 3 deletions test/elixir-mix-tests.el
Expand Up @@ -35,16 +35,24 @@


;;; Code: ;;; Code:


(provide 'elixir-mix-tests)

(require 'ert) (require 'ert)
(require 'elixir-mix)


(ert-deftest test-flatten-of-list () (ert-deftest test-flatten-of-list ()
(should (equal (elixir-mix-flatten '(1 2 (3 4) 5)) (should (equal (elixir-mix-flatten '(1 2 (3 4) 5))
'(1 2 3 4 5))) '(1 2 3 4 5)))
(should (equal (elixir-mix-flatten '(1 2 ("wood" "fire" (3)) 4 5)) (should (equal (elixir-mix-flatten '(1 2 ("wood" "fire" (3)) 4 5))
'(1 2 "wood" "fire" 3 4 5)))) '(1 2 "wood" "fire" 3 4 5))))


(ert-deftest test-mix-runner-cmdlist-builder ()
(should (equal (elixir-mix--build-runner-cmdlist "help")
'("help")))
(should (equal (elixir-mix--build-runner-cmdlist '("run"))
'("run")))
(should (equal (elixir-mix--build-runner-cmdlist "help do")
'("help" "do")))
(should (equal (elixir-mix--build-runner-cmdlist '("help" ""))
'("help"))))

(provide 'elixir-mix-tests)


;;; elixir-mix-tests.el ends here ;;; elixir-mix-tests.el ends here

0 comments on commit 485a42b

Please sign in to comment.