forked from kototama/cljsbuild-mode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcljsbuild-mode.el
184 lines (163 loc) · 7.71 KB
/
cljsbuild-mode.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
;;; cljsbuild-mode.el --- Utils for the ClojureScript 'lein cljsbuild' command
;; Copyright 2012 Kototama, Birdseye Software..
;; Authors: Kototama <kototamo gmail com>, <roman at birdeseye-sw com>
;; Version: 0.1.5
;; Package-version: 0.1.5
;; Package-Requires: ((multi-term "0.8.8") (multi-term "0.1.0") (notify.el ""))
;; Keywords: clojure, clojurescript, leiningen, compilation
;; URL: http://github.com/BirdseyeSoftware/cljsbuild-mode
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;;
;; Emacs utils for the ClojureScript 'lein cljsbuild' command
;; that will automatically watch the compilation buffer, pops it when the
;; compilation failed and (optionally) hides it when the compilation
;; succeed.
(eval-when-compile (require 'cl))
(require 'multi-term)
(require 'multi-term-ext)
(require 'notify)
(defvar cljsbuild-mode-process-name "cljsbuild"
"Name that multi-term will be giving to the process that has cljsbuild.")
(defvar cljsbuild-mode-screen-name "cljsbuild"
"Name of the GNU screen session that will be created or accessed to.")
(defvar cljsbuild-mode-verbose t
"When true, prints cljsbuild results on the minibuffer")
(defvar cljsbuild-mode-show-buffer-on-failure nil
"When true, pops the cljsbuild buffer when there is a compilation failure.")
(defvar cljsbuild-mode-show-buffer-on-warning nil
"When true, pops the cljsbuild buffer when there is a compilation warning.")
(defvar cljsbuild-mode-hide-buffer-on-success nil
"When true, hides the cljsbuild buffer when there is no errors.")
(defun -cljsbuild-mode-buffer-name ()
"Name of the buffer that will contain the terminal with cljsbuild."
(format "*%s*" cljsbuild-mode-process-name))
(defun -cljsbuild-mode-get-existing-term-buffer ()
"Returns the buffer that contains the cljsbuild process in case
it exists."
(car (remove-if-not
(lambda (buffer)
(string= (buffer-name buffer) (-cljsbuild-mode-buffer-name)))
(buffer-list))))
(defun -cljsbuild-mode-message (msg)
"Prints message to the minibuffer when cljsbuild-mode-verbose is true."
(if cljsbuild-mode-verbose
(notify "cljsbuild" msg)))
(defun -cljsbuild-mode-show-buffer (show?)
"Shows the cljsbuild buffer when given t as a parameter."
(let ((cljsbuild-buffer-visible (get-buffer-window (-cljsbuild-mode-buffer-name) 'visible)))
(when (and (not cljsbuild-buffer-visible)
show?)
(switch-to-buffer-other-window (-cljsbuild-mode-buffer-name) t))))
(defun -cljsbuild-mode-hide-buffer (hide?)
"Hides the cljsbuild buffer when given t as a parameter."
(let ((cljsbuild-buffer-visible (get-buffer-window (-cljsbuild-mode-buffer-name) 'visible)))
(when (and cljsbuild-buffer-visible
hide?)
(delete-windows-on (-cljsbuild-mode-buffer-name)))))
(defun -cljsbuild-mode-decorate-process-filter (term-proc)
"Decorates the existing process filter that exists on the term
buffer with the cljsbuild-mode one"
(set-process-filter term-proc
(-cljsbuild-mode-process-filter (process-filter term-proc))))
(defun -cljsbuild-mode-process-filter (orig-filter)
"This process filter tracks the key output of cljsbuild to do
various things (show cljsbuild buffer on errors, hide it on
success, display messages to the minibuffer, etc.)"
`(lambda (term-proc output)
(cond
((string-match "Successfully compiled \"\\(.+\\)\"" output)
(progn
(-cljsbuild-mode-message (format "\`%s\' compiled successfuly"
(match-string 1 output)))
(-cljsbuild-mode-hide-buffer cljsbuild-mode-hide-buffer-on-success)))
;;
((or (string-match "Reloading Clojure file \"\\(.+\\)\" failed" output)
(string-match "Compiling \"\\(.+\\)\" failed" output))
(progn
(-cljsbuild-mode-message (format "\`%s\' failed to compile"
(match-string 1 output)))
(-cljsbuild-mode-show-buffer cljsbuild-mode-show-buffer-on-failure)))
;;
((string-match "^WARNING:" output)
(progn
(-cljsbuild-mode-message "compilation warning")
(-cljsbuild-mode-show-buffer cljsbuild-mode-show-buffer-on-warning))))
;; call lower level process filter
(if (fboundp #',orig-filter) (funcall ',orig-filter term-proc output))))
(defun -cljsbuild-mode-create-multi-term ()
""
(if (string-match "scpc:" default-directory)
(progn
(string-match "/scpc:\\([^:]+\\)" d)
(let* ((host-address (match-string 1 d)))
(string-match "\\([^#]+\\)#?\\(.*\\)" host-address)
(let* ((multi-term-remote-ssh-port (match-string 2 host-address))
(host-address (match-string 1 host-address)))
(multi-term-remote-persistent
host-address cljsbuild-mode-screen-name))))
(multi-term-persistent cljsbuild-mode-screen-name)))
(defun -cljsbuild-mode-create-term-buffer ()
"Creates a new buffer that either creates a new GNU screen
session or connect to an existing one."
(let* ((term-buffer (save-window-excursion
(-cljsbuild-mode-create-multi-term)))
(term-process (get-buffer-process term-buffer)))
(with-current-buffer term-buffer
(-cljsbuild-mode-decorate-process-filter term-process)
(rename-buffer (-cljsbuild-mode-buffer-name)))
term-buffer))
(defun cljsbuild-mode-stop-process ()
"Will halt the `lein cljsbuild auto' command on the cljsbuild
buffer. It _will not_ kill the GNU screen session."
(interactive)
(let ((term-buffer (-cljsbuild-mode-get-existing-term-buffer)))
(when term-buffer
(progn
(with-current-buffer term-buffer
;; stop cljsbuild in the terminal
(term-send-raw-string (kbd "C-c"))
(term-send-raw-string (kbd "RET"))
(sit-for 0.5))))))
(defun cljsbuild-mode-start-process ()
"Executes the `lein cljsbuild auto' command on an existing
cljsbuild buffer, in case there is none, will do nothing."
(interactive)
(let ((term-buffer (-cljsbuild-mode-get-existing-term-buffer))
(dir default-directory))
(when term-buffer
(let* ((project-path (locate-dominating-file dir "project.clj"))
(project-path (if (string-match "/scpc:.+:\\(.+\\)" project-path)
(match-string 1 project-path)
project-path)))
(with-current-buffer term-buffer
;; cd to the root of the project
(term-send-raw-string
(format "cd %s\n" project-path))
;; start lein
(term-send-raw-string "lein cljsbuild auto\n"))))))
;;;###autoload
(defun cljsbuild-start ()
"Creates (or restarts) an existing cljsbuild session."
(interactive)
(let ((buffer (-cljsbuild-mode-get-existing-term-buffer)))
(if (not buffer)
(-cljsbuild-mode-create-term-buffer)
(and (interactive-p)
(y-or-n-p "Stop previous execution of cljsbuild? ")
(cljsbuild-mode-stop-process)))
(cljsbuild-mode-start-process)
(pop-to-buffer (or buffer (-cljsbuild-mode-get-existing-term-buffer)))))
(provide 'cljsbuild-mode)
;;; cljsbuild-mode.el ends here