Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 315 lines (239 sloc) 9.282 kB
4a11c70 @defunkt documentation
authored
1 ;;; coffee-mode.el --- Major mode to edit CoffeeScript files in Emacs
2
3 ;; Copyright (C) 2010 Chris Wanstrath
4
5 ;; Version 0.1.0
6 ;; Keywords: CoffeeScript major mode
7 ;; Author: Chris Wanstrath <chris@ozmm.org>
8 ;; URL: http://github.com/defunkt/coffee-script
9
10 ;; This file is not part of GNU Emacs.
11
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with this program; if not, write to the Free Software
24 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26 ;;; Commentary
27
28 ;; For commentary please see the README.md or
29 ;; http://github.com/defunkt/coffee-mode#readme
30
31 ;;; Installation
32
33 ;; In your shell:
34
35 ;; $ cd ~/.emacs.d/vendor
36 ;; $ git clone git://github.com/defunkt/coffee-mode.git
37
38 ;; In your emacs config:
39
40 ;; (add-to-list 'load-path "~/.emacs.d/vendor/coffee-mode")
41 ;; (require 'coffee-mode)
42
43 ;;; Thanks
44
0480381 @defunkt mini docs
authored
45 ;; Major thanks to http://xahlee.org/emacs/elisp_syntax_coloring.html
46 ;; the instructions.
4a11c70 @defunkt documentation
authored
47
38ce8da @defunkt small tweaks
authored
48 ;; Also thanks to Jason Blevins's markdown-mode.el for guidance.
49
50 (require 'easymenu)
51 (require 'font-lock)
0480381 @defunkt mini docs
authored
52
7557530 @defunkt compilation commands
authored
53 ;;
38ce8da @defunkt small tweaks
authored
54 ;; Customizable Variables
7557530 @defunkt compilation commands
authored
55 ;;
56
38ce8da @defunkt small tweaks
authored
57 (defconst coffee-mode-version "0.1.0"
5f14029 @defunkt Menu
authored
58 "The version of this `coffee-mode'.")
59
38ce8da @defunkt small tweaks
authored
60 (defvar coffee-mode-hook nil
61 "A hook for you to run your own code when the mode is loaded.")
62
7557530 @defunkt compilation commands
authored
63 (defvar coffee-command "coffee"
64 "The CoffeeScript command used for evaluating code. Must be in your
65 path.")
66
5f14029 @defunkt Menu
authored
67 (defvar coffee-command-args '("-s" "-p" "--no-wrap")
68 "The command line arguments to pass to `coffee-command' to get it to
69 print the compiled JavaScript.")
70
71 (defun coffee-command-full ()
72 "The full `coffee-command' complete with args."
73 (mapconcat 'identity (append (list coffee-command) coffee-command-args) " "))
74
7557530 @defunkt compilation commands
authored
75 (defvar coffee-js-mode 'js2-mode
76 "The mode to use when viewing compiled JavaScript.")
77
78 (defvar coffee-compiled-buffer-name "*coffee-compiled*"
79 "The name of the scratch buffer used when compiling CoffeeScript.")
80
eee29e0 @defunkt defvar the keymap
authored
81 (defvar coffee-mode-map (make-keymap)
82 "Keymap for CoffeeScript major mode.")
83
38ce8da @defunkt small tweaks
authored
84 ;;
85 ;; Commands
86 ;;
87
88
7557530 @defunkt compilation commands
authored
89 (defun coffee-compile-buffer ()
90 "Compiles the current buffer and displays the JS in the other buffer."
91 (interactive)
92 (save-excursion
93 (coffee-compile-region (point-min) (point-max))))
94
95 (defun coffee-compile-region (start end)
96 "Compiles a region and displays the JS in the other buffer."
97 (interactive "r")
98
99 (let ((buffer (get-buffer coffee-compiled-buffer-name)))
100 (when buffer
101 (kill-buffer buffer)))
102
103 (call-process-region start end coffee-command nil
104 (get-buffer-create coffee-compiled-buffer-name)
105 nil
106 "-s" "-p" "--no-wrap")
107 (switch-to-buffer-other-frame (get-buffer coffee-compiled-buffer-name))
108 (funcall coffee-js-mode)
109 (beginning-of-buffer))
3a47b28 @defunkt docs
authored
110
5f14029 @defunkt Menu
authored
111 (defun coffee-show-version ()
112 "Prints the `coffee-mode' version."
113 (interactive)
114 (message (concat "coffee-mode v" coffee-mode-version)))
115
fd314cc @defunkt menu tweaks
authored
116 (defun coffee-open-reference ()
117 "Open browser to CoffeeScript reference."
118 (interactive)
119 (browse-url "http://jashkenas.github.com/coffee-script/"))
120
5f14029 @defunkt Menu
authored
121 (defun coffee-open-github ()
fd314cc @defunkt menu tweaks
authored
122 "Open browser to `coffee-mode' project on GithHub."
5f14029 @defunkt Menu
authored
123 (interactive)
124 (browse-url "http://github.com/defunkt/coffee-mode"))
125
126 ;;
127 ;; Menubar
128 ;;
129
130 (easy-menu-define coffee-mode-menu coffee-mode-map
131 "Menu for CoffeeScript mode"
132 '("CoffeeScript"
133 ["Compile Buffer" coffee-compile-buffer]
134 ["Compile Region" coffee-compile-region]
135 "---"
fd314cc @defunkt menu tweaks
authored
136 ["CoffeeScript reference" coffee-open-reference]
137 ["coffee-mode on GitHub" coffee-open-github]
5f14029 @defunkt Menu
authored
138 ["Version" coffee-show-version]
139 ))
140
3a47b28 @defunkt docs
authored
141 ;;
142 ;; Define Language Syntax
143 ;;
144
145 ;; Instance variables (implicit this)
3ecaa32 @defunkt use more semantic names for parts of syntax
authored
146 (setq coffee-this-regexp "@\\w*\\|this")
3a47b28 @defunkt docs
authored
147
88e7b95 @defunkt better regexps, @blah: and {blah: true, blah2:true}
authored
148 ;; Assignment
3ecaa32 @defunkt use more semantic names for parts of syntax
authored
149 (setq coffee-assign-regexp "\\(\\w\\|\\.\\|_\\| \\|$\\)+?:")
88e7b95 @defunkt better regexps, @blah: and {blah: true, blah2:true}
authored
150
af34f91 @defunkt Booleans, better colors
authored
151 ;; Booleans
3ecaa32 @defunkt use more semantic names for parts of syntax
authored
152 (setq coffee-boolean-regexp "\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\)\\b")
3a47b28 @defunkt docs
authored
153
154 ;; Unused
76748c1 @defunkt cool, regexps
authored
155 (setq coffee-regexp-regexp "\\/.+?\\/")
3a47b28 @defunkt docs
authored
156
cf028f8 @defunkt basics
authored
157 ;; JavaScript Keywords
d6b78ed @defunkt defvars and basic indentation
authored
158 (defvar coffee-js-keywords
af34f91 @defunkt Booleans, better colors
authored
159 '("if" "else" "new" "return" "try" "catch"
cf028f8 @defunkt basics
authored
160 "finally" "throw" "break" "continue" "for" "in" "while"
161 "delete" "instanceof" "typeof" "switch" "super" "extends"
162 "class"))
163
164 ;; Reserved keywords either by JS or CS.
d6b78ed @defunkt defvars and basic indentation
authored
165 (defvar coffee-js-reserved
cf028f8 @defunkt basics
authored
166 '("case" "default" "do" "function" "var" "void" "with"
167 "const" "let" "debugger" "enum" "export" "import" "native"
168 "__extends" "__hasProp"))
169
170 ;; CoffeeScript keywords.
d6b78ed @defunkt defvars and basic indentation
authored
171 (defvar coffee-cs-keywords
af34f91 @defunkt Booleans, better colors
authored
172 '("then" "unless" "and" "or" "is"
cf028f8 @defunkt basics
authored
173 "isnt" "not" "of" "by" "where" "when"))
174
0480381 @defunkt mini docs
authored
175 ;; Regular expression combining the above three lists.
d6b78ed @defunkt defvars and basic indentation
authored
176 (defvar coffee-keywords-regexp (regexp-opt
cf028f8 @defunkt basics
authored
177 (append
178 coffee-js-reserved
179 coffee-js-keywords
180 coffee-cs-keywords) 'words))
181
182
0480381 @defunkt mini docs
authored
183 ;; Create the list for font-lock.
184 ;; Each class of keyword is given a particular face
3ecaa32 @defunkt use more semantic names for parts of syntax
authored
185 (setq coffee-font-lock-keywords
cf028f8 @defunkt basics
authored
186 `(
3ecaa32 @defunkt use more semantic names for parts of syntax
authored
187 (,coffee-this-regexp . font-lock-variable-name-face)
188 (,coffee-assign-regexp . font-lock-type-face)
028a53c @defunkt giggity
authored
189 (,coffee-regexp-regexp . font-lock-constant-face)
3ecaa32 @defunkt use more semantic names for parts of syntax
authored
190 (,coffee-boolean-regexp . font-lock-constant-face)
cf028f8 @defunkt basics
authored
191 (,coffee-keywords-regexp . font-lock-keyword-face)
192
193 ;; note: order above matters. `coffee-keywords-regexp' goes last because
194 ;; otherwise the keyword "state" in the function "state_entry"
195 ;; would be highlighted.
196 ))
197
3a47b28 @defunkt docs
authored
198 ;;
199 ;; Helper Functions
200 ;;
201
0480381 @defunkt mini docs
authored
202 ;; The command to comment/uncomment text
9ff612a @defunkt single quotes
authored
203 (defun coffee-comment-dwim (arg)
204 "Comment or uncomment current line or region in a smart way.
205 For detail, see `comment-dwim'."
206 (interactive "*P")
207 (require 'newcomment)
208 (let ((deactivate-mark nil) (comment-start "#") (comment-end ""))
209 (comment-dwim arg)))
84ab684 @defunkt comments
authored
210
2504ebe @defunkt explain indentation plan
authored
211 ;;
d6b78ed @defunkt defvars and basic indentation
authored
212 ;; Indentation
2504ebe @defunkt explain indentation plan
authored
213 ;;
214
7b03a71 @defunkt indentation theory
authored
215 ;; The theory is explained in the README.
97a1001 @defunkt basic indentation with TAB
authored
216
d6b78ed @defunkt defvars and basic indentation
authored
217 (defun coffee-indent-line ()
7b03a71 @defunkt indentation theory
authored
218 "Indent current line as CoffeeScript."
d6b78ed @defunkt defvars and basic indentation
authored
219 (interactive)
220
221 (save-excursion
222 (let ((prev-indent 0) (cur-indent 0))
97a1001 @defunkt basic indentation with TAB
authored
223 ;; Figure out the indentation of the previous line
d6b78ed @defunkt defvars and basic indentation
authored
224 (forward-line -1)
225 (setq prev-indent (current-indentation))
97a1001 @defunkt basic indentation with TAB
authored
226
227 ;; Figure out the current line's indentation
d6b78ed @defunkt defvars and basic indentation
authored
228 (forward-line 1)
229 (setq cur-indent (current-indentation))
230
97a1001 @defunkt basic indentation with TAB
authored
231 ;; Shift one column to the left
d6b78ed @defunkt defvars and basic indentation
authored
232 (backward-to-indentation 0)
97a1001 @defunkt basic indentation with TAB
authored
233 (insert-tab)
234
235 ;; We're too far, remove all indentation.
236 (when (> (- (current-indentation) prev-indent) tab-width)
237 (backward-to-indentation 0)
238 (delete-region (point-at-bol) (point))))))
3a47b28 @defunkt docs
authored
239
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
240 (defun coffee-newline-and-indent ()
241 "Inserts a newline and indents it to the same level as the previous line."
242 (interactive)
243
f92b25d @defunkt explain the new awesome newline-then-indent style
authored
244 ;; Remember the current line indentation level,
245 ;; insert a newline, and indent the newline to the same
246 ;; level as the previous line.
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
247 (let ((prev-indent (current-indentation)))
248 (newline)
249 (insert-tab (/ prev-indent tab-width)))
250
251 (when (coffee-previous-line-is-comment)
252 (insert "# ")))
253
254 (defun coffee-previous-line-is-comment ()
255 "Returns `t' if the previous line is a CoffeeScript comment."
256 (save-excursion
257 (forward-line -1)
258 (coffee-line-is-comment)))
259
260 (defun coffee-line-is-comment ()
261 "Returns `t' if the current line is a CoffeeScript comment."
262 (save-excursion
263 (backward-to-indentation 0)
264 (= (char-after) (string-to-char "#"))))
265
3a47b28 @defunkt docs
authored
266 ;;
267 ;; Define Major Mode
268 ;;
269
cf028f8 @defunkt basics
authored
270 (define-derived-mode coffee-mode fundamental-mode
271 "coffee-mode"
272 "Major mode for editing CoffeeScript..."
273
7557530 @defunkt compilation commands
authored
274 (define-key coffee-mode-map (kbd "A-r") 'coffee-compile-buffer)
eee29e0 @defunkt defvar the keymap
authored
275 (define-key coffee-mode-map (kbd "A-R") 'coffee-execute-line)
276 (define-key coffee-mode-map (kbd "A-M-r") 'coffee-repl)
7557530 @defunkt compilation commands
authored
277 (define-key coffee-mode-map [remap comment-dwim] 'coffee-comment-dwim)
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
278 (define-key coffee-mode-map "\C-m" 'coffee-newline-and-indent)
7557530 @defunkt compilation commands
authored
279
cf028f8 @defunkt basics
authored
280 ;; code for syntax highlighting
281 (setq font-lock-defaults '((coffee-font-lock-keywords)))
282
84ab684 @defunkt comments
authored
283 ;; perl style comment: "# ..."
284 (modify-syntax-entry ?# "< b" coffee-mode-syntax-table)
285 (modify-syntax-entry ?\n "> b" coffee-mode-syntax-table)
0480381 @defunkt mini docs
authored
286 (setq comment-start "#")
84ab684 @defunkt comments
authored
287
9ff612a @defunkt single quotes
authored
288 ;; single quote strings
289 (modify-syntax-entry ?' "\"" coffee-mode-syntax-table)
290 (modify-syntax-entry ?' "\"" coffee-mode-syntax-table)
291
d6b78ed @defunkt defvars and basic indentation
authored
292 ;; indentation
293 (make-local-variable 'indent-line-function)
294 (setq indent-line-function 'coffee-indent-line)
295
296 ;; no tabs
297 (setq indent-tabs-mode nil)
298
cf028f8 @defunkt basics
authored
299 ;; clear memory
300 (setq coffee-keywords-regexp nil)
301 (setq coffee-types-regexp nil)
302 (setq coffee-constants-regexp nil)
303 (setq coffee-events-regexp nil)
304 (setq coffee-functions-regexp nil))
eaf28ab @defunkt register as .coffee handler
authored
305
27ffada @defunkt provide something
authored
306 (provide 'coffee-mode)
307
eaf28ab @defunkt register as .coffee handler
authored
308 ;;
309 ;; On Load
310 ;;
311
312 ;; Run coffee-mode for files ending in .coffee.
313 (add-to-list 'auto-mode-alist '("\\.coffee$" . coffee-mode))
605a330 @defunkt highlight Cakefile too
authored
314 (add-to-list 'auto-mode-alist '("Cakefile" . coffee-mode))
Something went wrong with that request. Please try again.