;;; alchemist-buffer.el --- Custom compilation mode for Alchemist ;; Copyright © 2014-2015 Samuel Tonini ;; Author: Samuel Tonini . ;;; Commentary: ;; Custom compilation mode for Alchemist ;;; Code: (require 'compile) (require 'ansi-color) ;; Variables (defgroup alchemist-buffer nil "Custom compilation mode for Alchemist." :prefix "alchemist-buffer-" :group 'alchemist) (defcustom alchemist-buffer-status-modeline t "if t, the face of local `mode-name' variable will change with compilation status. For example, when `alchemist-mix-test' failes, the `mode-name' will be formated with the `alchemist-buffer--failed-face' face, to symbolize failing tests." :type 'boolean :group 'alchemist-buffer) (defvar alchemist-buffer--mode-name-face 'mode-line) (defvar alchemist-buffer--buffer-name nil "Used to store compilation name so recompilation works as expected.") (make-variable-buffer-local 'alchemist-buffer--buffer-name) (defvar alchemist-buffer--error-link-options '(elixir "^\\([-A-Za-z0-9./_]+\\):\\([0-9]+\\)\\(: warning\\)?$" 1 2 nil (3) 1) "File link matcher for `compilation-error-regexp-alist-alist' (matches path/to/file:line).") ;; Faces (defface alchemist-buffer--success-face '((t (:inherit font-lock-variable-name-face :bold t :background "darkgreen" :foreground "#e0ff00"))) "Face for successful compilation run." :group 'alchemist-buffer) (defface alchemist-buffer--failed-face '((t (:inherit font-lock-variable-name-face :bold t :background "red" :foreground "white"))) "Face for failed compilation run." :group 'alchemist-buffer) (defface alchemist-buffer--running-face '((t (:inherit font-lock-variable-name-face :bold nil :background "gray" :foreground "black"))) "Face for running compilation." :group 'alchemist-buffer) (defun alchemist-buffer--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)))) ;; Private functions (defvar alchemist-buffer--save-buffers-predicate (lambda () (not (string= (substring (buffer-name) 0 1) "*")))) (defun alchemist-buffer--remove-dispensable-output () (delete-matching-lines "\\(-*- mode:\\|Compiled \\|elixir-compilation;\\|Elixir started\\|^$\\)" (point-min) (point-max)) (remove-hook 'compilation-filter-hook 'alchemist-buffer--remove-dispensable-output t)) (defun alchemist-buffer--remove-dispensable-output-after-finish (buffer msg) (delete-matching-lines "\\(Excluding tags\\|Including tags\\|Elixir exited\\|Elixir finished\\)" (point-min) (point-max))) (defun alchemist-buffer--handle-compilation () (ansi-color-apply-on-region (point-min) (point-max))) (defun alchemist-buffer--set-modeline-color (buffer status) (setq alchemist-buffer--mode-name-face (if (string-prefix-p "finished" status) 'alchemist-buffer--success-face 'alchemist-buffer--failed-face)) (remove-hook 'compilation-finish-functions 'alchemist-buffer--set-modeline-color)) ;; Public functions (defun alchemist-buffer-initialize-modeline () "Initialize the mode-line face." (setq mode-name '(:eval (propertize "Elixir" 'face alchemist-buffer--mode-name-face)))) (defun alchemist-buffer-reset-modeline () "Reset the current mode-line face to default." (setq mode-name "Elixir")) (define-compilation-mode alchemist-buffer-mode "Elixir" "Elixir compilation mode." (progn (font-lock-add-keywords nil '(("^Finished in .*$" . font-lock-string-face))) ;; Set any bound buffer name buffer-locally (setq alchemist-buffer--buffer-name alchemist-buffer--buffer-name) (set (make-local-variable 'kill-buffer-hook) 'alchemist-buffer--kill-any-orphan-proc))) (defun alchemist-buffer-run (cmdlist buffer-name) "Run CMDLIST in `alchemist-buffer-mode'. Returns the compilation buffer. Argument BUFFER-NAME for the compilation." (save-some-buffers (not compilation-ask-about-save) alchemist-buffer--save-buffers-predicate) (let* ((alchemist-buffer--buffer-name buffer-name) (compilation-filter-start (point-min))) (with-current-buffer (compilation-start (mapconcat 'concat cmdlist " ") 'alchemist-buffer-mode (lambda (b) alchemist-buffer--buffer-name)) (setq-local compilation-error-regexp-alist-alist (cons alchemist-buffer--error-link-options compilation-error-regexp-alist-alist)) (setq-local compilation-error-regexp-alist (cons 'elixir compilation-error-regexp-alist)) (add-hook 'compilation-filter-hook 'alchemist-buffer--handle-compilation nil t) (add-hook 'compilation-filter-hook 'alchemist-buffer--remove-dispensable-output nil t) (add-to-list 'compilation-finish-functions 'alchemist-buffer--remove-dispensable-output-after-finish) (when alchemist-buffer-status-modeline (add-hook 'compilation-finish-functions 'alchemist-buffer--set-modeline-color nil t))))) (provide 'alchemist-buffer) ;;; alchemist-buffer.el ends here