Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 695 lines (566 sloc) 22.738 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
89203e8 @rrthomas Make version consistent and bump it to 0.4.1 (Fixes #61).
rrthomas authored
5 ;; Version: 0.4.1
4a11c70 @defunkt documentation
authored
6 ;; Keywords: CoffeeScript major mode
7 ;; Author: Chris Wanstrath <chris@ozmm.org>
1d2aed3 @defunkt Use correct URL. Fixes #71
authored
8 ;; URL: http://github.com/defunkt/coffee-mode
4a11c70 @defunkt documentation
authored
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
a6c6911 @defunkt tweaks
authored
48 ;; Also thanks to Jason Blevins's markdown-mode.el and Steve Yegge's
49 ;; js2-mode for guidance.
38ce8da @defunkt small tweaks
authored
50
12bd5d0 @defunkt todo
authored
51 ;; TODO:
a6c6911 @defunkt tweaks
authored
52 ;; - Execute {buffer,region,line} and show output in new buffer
12bd5d0 @defunkt todo
authored
53 ;; - Make prototype accessor assignments like `String::length: -> 10` pretty.
5b00ae2 @defunkt more todo
authored
54 ;; - mirror-mode - close brackets and parens automatically
12bd5d0 @defunkt todo
authored
55
56 ;;; Code:
57
6639c36 @mkhl Silence byte-compiler warnings.
mkhl authored
58 (require 'comint)
38ce8da @defunkt small tweaks
authored
59 (require 'easymenu)
60 (require 'font-lock)
6639c36 @mkhl Silence byte-compiler warnings.
mkhl authored
61
62 (eval-when-compile
63 (require 'cl))
0480381 @defunkt mini docs
authored
64
7557530 @defunkt compilation commands
authored
65 ;;
38ce8da @defunkt small tweaks
authored
66 ;; Customizable Variables
7557530 @defunkt compilation commands
authored
67 ;;
68
89203e8 @rrthomas Make version consistent and bump it to 0.4.1 (Fixes #61).
rrthomas authored
69 (defconst coffee-mode-version "0.4.1"
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
70 "The version of `coffee-mode'.")
5f14029 @defunkt Menu
authored
71
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
72 (defgroup coffee nil
73 "A CoffeeScript major mode."
74 :group 'languages)
75
76 (defcustom coffee-tab-width tab-width
77 "The tab width to use when indenting."
78 :type 'integer
79 :group 'coffee)
80
81 (defcustom coffee-command "coffee"
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
82 "The CoffeeScript command used for evaluating code."
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
83 :type 'string
84 :group 'coffee)
7557530 @defunkt compilation commands
authored
85
2c204ef @mizchi add coffee-js2coffee-replace-region
mizchi authored
86 (defcustom js2coffee-command "js2coffee"
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
87 "The js2coffee command used for evaluating code."
2c204ef @mizchi add coffee-js2coffee-replace-region
mizchi authored
88 :type 'string
89 :group 'coffee)
90
3b0962d @defunkt Rename `args` variables to be more consistent.
authored
91 (defcustom coffee-args-repl '("-i")
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
92 "The arguments to pass to `coffee-command' to start a REPL."
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
93 :type 'list
94 :group 'coffee)
28485fa @defunkt `coffee-repl'
authored
95
227a360 @orlandohill Customize args for compiling files and display the first compiler error
orlandohill authored
96 (defcustom coffee-args-compile '("-c")
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
97 "The arguments to pass to `coffee-command' to compile a file."
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
98 :type 'list
99 :group 'coffee)
5f14029 @defunkt Menu
authored
100
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
101 (defcustom coffee-compiled-buffer-name "*coffee-compiled*"
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
102 "The name of the scratch buffer used for compiled CoffeeScript."
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
103 :type 'string
104 :group 'coffee)
7557530 @defunkt compilation commands
authored
105
14a0d56 @errge Added coffee-compile-jump-to-error.
errge authored
106 (defcustom coffee-compile-jump-to-error t
107 "Whether to jump to the first error if compilation fails.
e5f93e8 @rrthomas Improve the coffee-compile-jump-to-error docstring.
rrthomas authored
108 Since the coffee compiler does not always include a line number in
109 its error messages, this is not always possible."
14a0d56 @errge Added coffee-compile-jump-to-error.
errge authored
110 :type 'boolean
111 :group 'coffee)
112
0b06b86 @semperos Add support for coffee --watch, and in process also add function for run...
semperos authored
113 (defcustom coffee-watch-buffer-name "*coffee-watch*"
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
114 "The name of the scratch buffer used when using the --watch flag
115 with CoffeeScript."
0b06b86 @semperos Add support for coffee --watch, and in process also add function for run...
semperos authored
116 :type 'string
117 :group 'coffee)
118
6d1d92d @rrthomas Make coffee-mode-hook customizable.
rrthomas authored
119 (defcustom coffee-mode-hook nil
120 "Hook called by `coffee-mode'."
121 :type 'hook
122 :group 'coffee)
1b887a5 @defunkt clean whitespace on save
authored
123
677cf42 fix some really obnoxious indentation
Justine Tunney authored
124 (defvar coffee-mode-map
125 (let ((map (make-sparse-keymap)))
126 ;; key bindings
127 (define-key map (kbd "A-r") 'coffee-compile-buffer)
128 (define-key map (kbd "A-R") 'coffee-compile-region)
129 (define-key map (kbd "A-M-r") 'coffee-repl)
130 (define-key map [remap comment-dwim] 'coffee-comment-dwim)
131 (define-key map [remap newline-and-indent] 'coffee-newline-and-indent)
132 (define-key map "\C-m" 'coffee-newline-and-indent)
133 (define-key map "\C-c\C-o\C-s" 'coffee-cos-mode)
67e8727 backspace now de-indents instead of just going back a space.
Shawn Krisman authored
134 (define-key map "\177" 'coffee-dedent-line-backspace)
677cf42 fix some really obnoxious indentation
Justine Tunney authored
135 map)
eee29e0 @defunkt defvar the keymap
authored
136 "Keymap for CoffeeScript major mode.")
137
38ce8da @defunkt small tweaks
authored
138 ;;
139 ;; Commands
140 ;;
141
28485fa @defunkt `coffee-repl'
authored
142 (defun coffee-repl ()
143 "Launch a CoffeeScript REPL using `coffee-command' as an inferior mode."
144 (interactive)
145
17150cf @defunkt docs and starting to implement indenters
authored
146 (unless (comint-check-proc "*CoffeeREPL*")
28485fa @defunkt `coffee-repl'
authored
147 (set-buffer
17150cf @defunkt docs and starting to implement indenters
authored
148 (apply 'make-comint "CoffeeREPL"
d06825b @fred-o Workaround to avoid getting garbage chars in the comint buffer.
fred-o authored
149 "env"
150 nil (append (list "NODE_NO_READLINE=1" coffee-command) coffee-args-repl))))
28485fa @defunkt `coffee-repl'
authored
151
8a3d6f5 Updating coffee-repl to pop-to-buffer using the name '*CoffeeREPL*' inst...
Nick Parker authored
152 (pop-to-buffer "*CoffeeREPL*"))
38ce8da @defunkt small tweaks
authored
153
62c84fb @knu Add a function coffee-compiled-file-name for ease of scripting.
knu authored
154 (defun coffee-compiled-file-name (&optional filename)
155 "Returns the name of the JavaScript file compiled from a CoffeeScript file.
156 If FILENAME is omitted, the current buffer's file name is used."
157 (concat (file-name-sans-extension (or filename (buffer-file-name))) ".js"))
158
cbd31f9 @defunkt coffee-compile-file
authored
159 (defun coffee-compile-file ()
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
160 "Compiles and saves the current file to disk."
cbd31f9 @defunkt coffee-compile-file
authored
161 (interactive)
227a360 @orlandohill Customize args for compiling files and display the first compiler error
orlandohill authored
162 (let ((compiler-output (shell-command-to-string (coffee-command-compile (buffer-file-name)))))
163 (if (string= compiler-output "")
62c84fb @knu Add a function coffee-compiled-file-name for ease of scripting.
knu authored
164 (message "Compiled and saved %s" (coffee-compiled-file-name))
14a0d56 @errge Added coffee-compile-jump-to-error.
errge authored
165 (let* ((msg (car (split-string compiler-output "[\n\r]+")))
66c326b @rrthomas Remove custom debug code; should use the standard Emacs debugging tools ...
rrthomas authored
166 (line (and (string-match "on line \\([0-9]+\\)" msg)
167 (string-to-number (match-string 1 msg)))))
168 (message msg)
169 (when (and coffee-compile-jump-to-error line (> line 0))
170 (goto-char (point-min))
171 (forward-line (1- line)))))))
cbd31f9 @defunkt coffee-compile-file
authored
172
7557530 @defunkt compilation commands
authored
173 (defun coffee-compile-buffer ()
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
174 "Compiles the current buffer and displays the JavaScript in a buffer
175 called `coffee-compiled-buffer-name'."
7557530 @defunkt compilation commands
authored
176 (interactive)
177 (save-excursion
178 (coffee-compile-region (point-min) (point-max))))
179
180 (defun coffee-compile-region (start end)
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
181 "Compiles a region and displays the JavaScript in a buffer called
182 `coffee-compiled-buffer-name'."
7557530 @defunkt compilation commands
authored
183 (interactive "r")
184
185 (let ((buffer (get-buffer coffee-compiled-buffer-name)))
186 (when buffer
187 (kill-buffer buffer)))
188
b4270de @semperos Allow existing `coffee-args-compile` to be used for `coffee-compile-regi...
semperos authored
189 (apply (apply-partially 'call-process-region start end coffee-command nil
190 (get-buffer-create coffee-compiled-buffer-name)
191 nil)
192 (append coffee-args-compile (list "-s" "-p")))
e3c21f8 @tav Change so that the compiled buffer doesn't open in a new frame.
tav authored
193 (switch-to-buffer (get-buffer coffee-compiled-buffer-name))
eb912a1 @bretthoerner Fix let paren placement in let form.
bretthoerner authored
194 (let ((buffer-file-name "tmp.js")) (set-auto-mode))
6639c36 @mkhl Silence byte-compiler warnings.
mkhl authored
195 (goto-char (point-min)))
3a47b28 @defunkt docs
authored
196
2c204ef @mizchi add coffee-js2coffee-replace-region
mizchi authored
197 (defun coffee-js2coffee-replace-region (start end)
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
198 "Convert JavaScript in the region into CoffeeScript."
2c204ef @mizchi add coffee-js2coffee-replace-region
mizchi authored
199 (interactive "r")
200
201 (let ((buffer (get-buffer coffee-compiled-buffer-name)))
202 (when buffer
203 (kill-buffer buffer)))
204
66c326b @rrthomas Remove custom debug code; should use the standard Emacs debugging tools ...
rrthomas authored
205 (call-process-region start end
2c204ef @mizchi add coffee-js2coffee-replace-region
mizchi authored
206 js2coffee-command nil
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
207 (current-buffer))
208 (delete-region start end))
2c204ef @mizchi add coffee-js2coffee-replace-region
mizchi authored
209
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
210 (defun coffee-version ()
211 "Show the `coffee-mode' version in the echo area."
5f14029 @defunkt Menu
authored
212 (interactive)
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
213 (message (concat "coffee-mode version " coffee-mode-version)))
5f14029 @defunkt Menu
authored
214
0b06b86 @semperos Add support for coffee --watch, and in process also add function for run...
semperos authored
215 (defun coffee-watch (dir-or-file)
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
216 "Run `coffee-run-cmd' with the --watch flag on a directory or file."
0b06b86 @semperos Add support for coffee --watch, and in process also add function for run...
semperos authored
217 (interactive "fDirectory or File: ")
218 (let ((coffee-compiled-buffer-name coffee-watch-buffer-name)
66c326b @rrthomas Remove custom debug code; should use the standard Emacs debugging tools ...
rrthomas authored
219 (args (mapconcat 'identity (append coffee-args-compile (list "--watch" (expand-file-name dir-or-file))) " ")))
0b06b86 @semperos Add support for coffee --watch, and in process also add function for run...
semperos authored
220 (coffee-run-cmd args)))
221
5f14029 @defunkt Menu
authored
222 ;;
223 ;; Menubar
224 ;;
225
226 (easy-menu-define coffee-mode-menu coffee-mode-map
227 "Menu for CoffeeScript mode"
228 '("CoffeeScript"
cbd31f9 @defunkt coffee-compile-file
authored
229 ["Compile File" coffee-compile-file]
5f14029 @defunkt Menu
authored
230 ["Compile Buffer" coffee-compile-buffer]
231 ["Compile Region" coffee-compile-region]
5256afd @defunkt tweaks
authored
232 ["REPL" coffee-repl]
5f14029 @defunkt Menu
authored
233 "---"
234 ["Version" coffee-show-version]
235 ))
236
3a47b28 @defunkt docs
authored
237 ;;
238 ;; Define Language Syntax
239 ;;
240
c5831bb @sstephenson Fix for string literals with escaped quotes
sstephenson authored
241 ;; String literals
242 (defvar coffee-string-regexp "\"\\([^\\]\\|\\\\.\\)*?\"\\|'\\([^\\]\\|\\\\.\\)*?'")
243
3a47b28 @defunkt docs
authored
244 ;; Instance variables (implicit this)
2bb69be Regex for "this" variable includes underscore.
Ryan Koopmans authored
245 (defvar coffee-this-regexp "@\\(\\w\\|_\\)*\\|this")
3a47b28 @defunkt docs
authored
246
dc85f42 @tav Added support for the shorthand::syntax for .prototype.
tav authored
247 ;; Prototype::access
248 (defvar coffee-prototype-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\)::\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
249
88e7b95 @defunkt better regexps, @blah: and {blah: true, blah2:true}
authored
250 ;; Assignment
37b481e @defunkt Better assignment highlighting for `:`
authored
251 (defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\|$\\)+?\s*\\):")
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
252
7c5b19b local variable assignment is now highlighted.
Shawn Krisman authored
253 ;; Local Assignment
279bd3c allow member assignment to be highlighted just like local vars.
Shawn Krisman authored
254 (defvar coffee-local-assign-regexp "\\(\\(_\\|\\w\\|\\$\\)+\\)\s+=")
7c5b19b local variable assignment is now highlighted.
Shawn Krisman authored
255
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
256 ;; Lambda
00c197b @defunkt elisp regexps are fun
authored
257 (defvar coffee-lambda-regexp "\\((.+)\\)?\\s *\\(->\\|=>\\)")
88e7b95 @defunkt better regexps, @blah: and {blah: true, blah2:true}
authored
258
76ed341 @defunkt class support in imenu
authored
259 ;; Namespaces
260 (defvar coffee-namespace-regexp "\\b\\(class\\s +\\(\\S +\\)\\)\\b")
261
af34f91 @defunkt Booleans, better colors
authored
262 ;; Booleans
3900a8c @Wilfred adding undefined to reserved words as part of coffee-boolean-regexp (not...
Wilfred authored
263 (defvar coffee-boolean-regexp "\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\|null\\|undefined\\)\\b")
3a47b28 @defunkt docs
authored
264
dbb4ec5 @defunkt comment tweaks
authored
265 ;; Regular Expressions
1fb4956 @levskaya small fix of coffee-regexp-regexp so it doesn't cause massive hangs when...
levskaya authored
266 (defvar coffee-regexp-regexp "\\/\\(\\\\.\\|\\[\\(\\\\.\\|.\\)+?\\]\\|[^/
267 ]\\)+?\\/")
3a47b28 @defunkt docs
authored
268
cf028f8 @defunkt basics
authored
269 ;; JavaScript Keywords
d6b78ed @defunkt defvars and basic indentation
authored
270 (defvar coffee-js-keywords
af34f91 @defunkt Booleans, better colors
authored
271 '("if" "else" "new" "return" "try" "catch"
cf028f8 @defunkt basics
authored
272 "finally" "throw" "break" "continue" "for" "in" "while"
273 "delete" "instanceof" "typeof" "switch" "super" "extends"
7803688 Until and loop are keywords.
Ryan Koopmans authored
274 "class" "until" "loop"))
cf028f8 @defunkt basics
authored
275
276 ;; Reserved keywords either by JS or CS.
d6b78ed @defunkt defvars and basic indentation
authored
277 (defvar coffee-js-reserved
cf028f8 @defunkt basics
authored
278 '("case" "default" "do" "function" "var" "void" "with"
279 "const" "let" "debugger" "enum" "export" "import" "native"
280 "__extends" "__hasProp"))
281
282 ;; CoffeeScript keywords.
d6b78ed @defunkt defvars and basic indentation
authored
283 (defvar coffee-cs-keywords
0a39a40 add support for the "own" keyword (for own k, v of obj ...)
Justine Tunney authored
284 '("then" "unless" "and" "or" "is" "own"
134d8a8 "where" isn't a coffeescript keyword
Justine Tunney authored
285 "isnt" "not" "of" "by" "when"))
cf028f8 @defunkt basics
authored
286
80ebae6 Added support for iced coffeescript await and defer keywords.
Marius Kjeldahl authored
287 ;; Iced CoffeeScript keywords
288 (defvar iced-coffee-cs-keywords
289 '("await" "defer"))
290
0480381 @defunkt mini docs
authored
291 ;; Regular expression combining the above three lists.
fad39cc keywords can now be member names.
Shawn Krisman authored
292 (defvar coffee-keywords-regexp
293 ;; keywords can be member names.
0686a8a only the keywords are highlighted instead of text before them.
Shawn Krisman authored
294 (concat "[^.]"
295 (regexp-opt (append coffee-js-reserved
296 coffee-js-keywords
297 coffee-cs-keywords
298 iced-coffee-cs-keywords) 'words)))
cf028f8 @defunkt basics
authored
299
300
ff61700 @defunkt that was bothering me
authored
301 ;; Create the list for font-lock. Each class of keyword is given a
302 ;; particular face.
5256afd @defunkt tweaks
authored
303 (defvar coffee-font-lock-keywords
ff61700 @defunkt that was bothering me
authored
304 ;; *Note*: order below matters. `coffee-keywords-regexp' goes last
305 ;; because otherwise the keyword "state" in the function
306 ;; "state_entry" would be highlighted.
c5831bb @sstephenson Fix for string literals with escaped quotes
sstephenson authored
307 `((,coffee-string-regexp . font-lock-string-face)
308 (,coffee-this-regexp . font-lock-variable-name-face)
dc85f42 @tav Added support for the shorthand::syntax for .prototype.
tav authored
309 (,coffee-prototype-regexp . font-lock-variable-name-face)
ff61700 @defunkt that was bothering me
authored
310 (,coffee-assign-regexp . font-lock-type-face)
279bd3c allow member assignment to be highlighted just like local vars.
Shawn Krisman authored
311 (,coffee-local-assign-regexp 1 font-lock-variable-name-face)
ff61700 @defunkt that was bothering me
authored
312 (,coffee-regexp-regexp . font-lock-constant-face)
313 (,coffee-boolean-regexp . font-lock-constant-face)
bdb258b color -> and => as functions.
Shawn Krisman authored
314 (,coffee-lambda-regexp . (2 font-lock-function-name-face))
0686a8a only the keywords are highlighted instead of text before them.
Shawn Krisman authored
315 (,coffee-keywords-regexp 1 font-lock-keyword-face)))
cf028f8 @defunkt basics
authored
316
3a47b28 @defunkt docs
authored
317 ;;
318 ;; Helper Functions
319 ;;
320
9ff612a @defunkt single quotes
authored
321 (defun coffee-comment-dwim (arg)
322 "Comment or uncomment current line or region in a smart way.
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
323 For details, see `comment-dwim'."
9ff612a @defunkt single quotes
authored
324 (interactive "*P")
325 (require 'newcomment)
326 (let ((deactivate-mark nil) (comment-start "#") (comment-end ""))
327 (comment-dwim arg)))
84ab684 @defunkt comments
authored
328
227a360 @orlandohill Customize args for compiling files and display the first compiler error
orlandohill authored
329 (defun coffee-command-compile (file-name)
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
330 "Run `coffee-command' to compile FILE."
66c326b @rrthomas Remove custom debug code; should use the standard Emacs debugging tools ...
rrthomas authored
331 (let ((full-file-name (expand-file-name file-name)))
2d489a8 @semperos Add support for Cygwin-style absolute paths, which makes using the file ...
semperos authored
332 (mapconcat 'identity (append (list coffee-command) coffee-args-compile (list full-file-name)) " ")))
5b00ae2 @defunkt more todo
authored
333
0b06b86 @semperos Add support for coffee --watch, and in process also add function for run...
semperos authored
334 (defun coffee-run-cmd (args)
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
335 "Run `coffee-command' with the given arguments, and display the
336 output in a compilation buffer."
0b06b86 @semperos Add support for coffee --watch, and in process also add function for run...
semperos authored
337 (interactive "sArguments: ")
338 (let ((compilation-buffer-name-function (lambda (this-mode)
339 (generate-new-buffer-name coffee-compiled-buffer-name))))
340 (compile (concat coffee-command " " args))))
341
2504ebe @defunkt explain indentation plan
authored
342 ;;
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
343 ;; imenu support
344 ;;
345
346 ;; This is a pretty naive but workable way of doing it. First we look
347 ;; for any lines that starting with `coffee-assign-regexp' that include
348 ;; `coffee-lambda-regexp' then add those tokens to the list.
349 ;;
350 ;; Should cover cases like these:
351 ;;
352 ;; minus: (x, y) -> x - y
353 ;; String::length: -> 10
354 ;; block: ->
355 ;; print('potion')
356 ;;
357 ;; Next we look for any line that starts with `class' or
358 ;; `coffee-assign-regexp' followed by `{` and drop into a
359 ;; namespace. This means we search one indentation level deeper for
360 ;; more assignments and add them to the alist prefixed with the
361 ;; namespace name.
362 ;;
363 ;; Should cover cases like these:
364 ;;
365 ;; class Person
366 ;; print: ->
367 ;; print 'My name is ' + this.name + '.'
368 ;;
369 ;; class Policeman extends Person
370 ;; constructor: (rank) ->
371 ;; @rank: rank
372 ;; print: ->
373 ;; print 'My name is ' + this.name + " and I'm a " + this.rank + '.'
374 ;;
76ed341 @defunkt class support in imenu
authored
375 ;; TODO:
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
376 ;; app = {
377 ;; window: {width: 200, height: 200}
378 ;; para: -> 'Welcome.'
379 ;; button: -> 'OK'
380 ;; }
381
382 (defun coffee-imenu-create-index ()
383 "Create an imenu index of all methods in the buffer."
384 (interactive)
385
386 ;; This function is called within a `save-excursion' so we're safe.
6639c36 @mkhl Silence byte-compiler warnings.
mkhl authored
387 (goto-char (point-min))
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
388
76ed341 @defunkt class support in imenu
authored
389 (let ((index-alist '()) assign pos indent ns-name ns-indent)
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
390 ;; Go through every assignment that includes -> or => on the same
c6562af @defunkt Make `coffee-debug' a macro
authored
391 ;; line or starts with `class'.
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
392 (while (re-search-forward
76ed341 @defunkt class support in imenu
authored
393 (concat "^\\(\\s *\\)"
394 "\\("
395 coffee-assign-regexp
396 ".+?"
397 coffee-lambda-regexp
398 "\\|"
399 coffee-namespace-regexp
400 "\\)")
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
401 (point-max)
402 t)
403
76ed341 @defunkt class support in imenu
authored
404 ;; If this is the start of a new namespace, save the namespace's
405 ;; indentation level and name.
7f5e1b3 @defunkt Bugfix: Clear old namespace when a new one is found
authored
406 (when (match-string 8)
407 ;; Set the name.
408 (setq ns-name (match-string 8))
409
76ed341 @defunkt class support in imenu
authored
410 ;; If this is a class declaration, add :: to the namespace.
411 (setq ns-name (concat ns-name "::"))
412
413 ;; Save the indentation level.
66c326b @rrthomas Remove custom debug code; should use the standard Emacs debugging tools ...
rrthomas authored
414 (setq ns-indent (length (match-string 1))))
76ed341 @defunkt class support in imenu
authored
415
416 ;; If this is an assignment, save the token being
417 ;; assigned. `Please.print:` will be `Please.print`, `block:`
418 ;; will be `block`, etc.
419 (when (setq assign (match-string 3))
420 ;; The position of the match in the buffer.
421 (setq pos (match-beginning 3))
422
423 ;; The indent level of this match
424 (setq indent (length (match-string 1)))
425
426 ;; If we're within the context of a namespace, add that to the
427 ;; front of the assign, e.g.
428 ;; constructor: => Policeman::constructor
429 (when (and ns-name (> indent ns-indent))
430 (setq assign (concat ns-name assign)))
431
432 ;; Clear the namespace if we're no longer indented deeper
433 ;; than it.
434 (when (and ns-name (<= indent ns-indent))
435 (setq ns-name nil)
436 (setq ns-indent nil))
437
438 ;; Add this to the alist. Done.
439 (push (cons assign pos) index-alist)))
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
440
441 ;; Return the alist.
442 index-alist))
443
444 ;;
d6b78ed @defunkt defvars and basic indentation
authored
445 ;; Indentation
2504ebe @defunkt explain indentation plan
authored
446 ;;
447
dbb4ec5 @defunkt comment tweaks
authored
448 ;;; The theory is explained in the README.
97a1001 @defunkt basic indentation with TAB
authored
449
d6b78ed @defunkt defvars and basic indentation
authored
450 (defun coffee-indent-line ()
7b03a71 @defunkt indentation theory
authored
451 "Indent current line as CoffeeScript."
d6b78ed @defunkt defvars and basic indentation
authored
452 (interactive)
453
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
454 (if (= (point) (point-at-bol))
455 (insert-tab)
456 (save-excursion
3f4271f @rrthomas Simplify coffee-indent-line and coffee-previous-indent.
rrthomas authored
457 (let ((prev-indent (coffee-previous-indent))
458 (cur-indent (current-indentation)))
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
459 ;; Shift one column to the left
460 (beginning-of-line)
461 (insert-tab)
462
463 (when (= (point-at-bol) (point))
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
464 (forward-char coffee-tab-width))
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
465
466 ;; We're too far, remove all indentation.
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
467 (when (> (- (current-indentation) prev-indent) coffee-tab-width)
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
468 (backward-to-indentation 0)
469 (delete-region (point-at-bol) (point)))))))
b7ee8b8 @defunkt start cleaning up indentation code
authored
470
471 (defun coffee-previous-indent ()
472 "Return the indentation level of the previous non-blank line."
473 (save-excursion
474 (forward-line -1)
d063614 @superbobry Fix hanging of `coffee-previous-indent` at start of buffer.
superbobry authored
475 (if (bobp)
476 0
477 (progn
3f4271f @rrthomas Simplify coffee-indent-line and coffee-previous-indent.
rrthomas authored
478 (while (and (looking-at "^[ \t]*$") (not (bobp))) (forward-line -1))
d063614 @superbobry Fix hanging of `coffee-previous-indent` at start of buffer.
superbobry authored
479 (current-indentation)))))
b7ee8b8 @defunkt start cleaning up indentation code
authored
480
17150cf @defunkt docs and starting to implement indenters
authored
481 (defun coffee-newline-and-indent ()
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
482 "Insert a newline and indent it to the same level as the previous line."
17150cf @defunkt docs and starting to implement indenters
authored
483 (interactive)
484
485 ;; Remember the current line indentation level,
486 ;; insert a newline, and indent the newline to the same
487 ;; level as the previous line.
488 (let ((prev-indent (current-indentation)) (indent-next nil))
74a9135 @piranha do not leave trailing whitespaces on newline
piranha authored
489 (delete-horizontal-space t)
17150cf @defunkt docs and starting to implement indenters
authored
490 (newline)
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
491 (insert-tab (/ prev-indent coffee-tab-width))
3a47b28 @defunkt docs
authored
492
17150cf @defunkt docs and starting to implement indenters
authored
493 ;; We need to insert an additional tab because the last line was special.
494 (when (coffee-line-wants-indent)
495 (insert-tab)))
496
497 ;; Last line was a comment so this one should probably be,
498 ;; too. Makes it easy to write multi-line comments (like the one I'm
499 ;; writing right now).
500 (when (coffee-previous-line-is-comment)
501 (insert "# ")))
502
67e8727 backspace now de-indents instead of just going back a space.
Shawn Krisman authored
503 (defun coffee-dedent-line-backspace ()
504 "We want to be backspacing full tabs not just single characters."
505 (interactive)
506 (if (and (<= (point-marker) (save-excursion
507 (back-to-indentation)
508 (point-marker)))
509 (> (current-column) 0))
510 (backward-delete-char-untabify coffee-tab-width)
511 (backward-delete-char-untabify 1)))
512
17150cf @defunkt docs and starting to implement indenters
authored
513 ;; Indenters help determine whether the current line should be
514 ;; indented further based on the content of the previous line. If a
515 ;; line starts with `class', for instance, you're probably going to
516 ;; want to indent the next line.
517
9eca4aa @theJohnnyBrown indent following while statement
theJohnnyBrown authored
518 (defvar coffee-indenters-bol '("class" "for" "if" "try" "while")
7d338d1 @defunkt coffee-indenters
authored
519 "Keywords or syntax whose presence at the start of a line means the
520 next line should probably be indented.")
521
522 (defun coffee-indenters-bol-regexp ()
523 "Builds a regexp out of `coffee-indenters-bol' words."
27df14a @defunkt Fix coffee-indenters-bol-regexp. Closes #36
authored
524 (regexp-opt coffee-indenters-bol 'words))
7d338d1 @defunkt coffee-indenters
authored
525
5e170be @defunkt get it working (with a fake function though)
authored
526 (defvar coffee-indenters-eol '(?> ?{ ?\[)
527 "Single characters at the end of a line that mean the next line
528 should probably be indented.")
7d338d1 @defunkt coffee-indenters
authored
529
17150cf @defunkt docs and starting to implement indenters
authored
530 (defun coffee-line-wants-indent ()
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
531 "Return t if the current line should be indented relative to the
532 previous line."
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
533 (interactive)
534
17150cf @defunkt docs and starting to implement indenters
authored
535 (save-excursion
536 (let ((indenter-at-bol) (indenter-at-eol))
537 ;; Go back a line and to the first character.
538 (forward-line -1)
539 (backward-to-indentation 0)
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
540
17150cf @defunkt docs and starting to implement indenters
authored
541 ;; If the next few characters match one of our magic indenter
542 ;; keywords, we want to indent the line we were on originally.
543 (when (looking-at (coffee-indenters-bol-regexp))
66c326b @rrthomas Remove custom debug code; should use the standard Emacs debugging tools ...
rrthomas authored
544 (setq indenter-at-bol t))
17150cf @defunkt docs and starting to implement indenters
authored
545
546 ;; If that didn't match, go to the back of the line and check to
5e170be @defunkt get it working (with a fake function though)
authored
547 ;; see if the last character matches one of our indenter
548 ;; characters.
17150cf @defunkt docs and starting to implement indenters
authored
549 (when (not indenter-at-bol)
550 (end-of-line)
551
5e170be @defunkt get it working (with a fake function though)
authored
552 ;; Optimized for speed - checks only the last character.
65797fa @jaeyeom Fix missing function `some' issue when loading compiled elisp.
jaeyeom authored
553 (let ((indenters coffee-indenters-eol))
554 (while indenters
df0dfbc resolved issue #63. Fixed inspired by tzeskimo 6c5eb29.
Keith Simmons authored
555 (if (and (char-before) (/= (char-before) (car indenters)))
65797fa @jaeyeom Fix missing function `some' issue when loading compiled elisp.
jaeyeom authored
556 (setq indenters (cdr indenters))
557 (setq indenter-at-eol t)
558 (setq indenters nil)))))
17150cf @defunkt docs and starting to implement indenters
authored
559
560 ;; If we found an indenter, return `t'.
561 (or indenter-at-bol indenter-at-eol))))
562
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
563 (defun coffee-previous-line-is-comment ()
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
564 "Return t if the previous line is a CoffeeScript comment."
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
565 (save-excursion
566 (forward-line -1)
567 (coffee-line-is-comment)))
568
569 (defun coffee-line-is-comment ()
579e270 @rrthomas Overhaul the docstrings.
rrthomas authored
570 "Return t if the current line is a CoffeeScript comment."
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
571 (save-excursion
572 (backward-to-indentation 0)
573 (= (char-after) (string-to-char "#"))))
574
168b32d @disnet fixing triple quoted strings issue with code from python-mode
disnet authored
575
c5fb056 remove triple quotes, seems to be doing strange things to python-mode
Justine Tunney authored
576 ;; (defun coffee-quote-syntax (n)
577 ;; "Put `syntax-table' property correctly on triple quote.
578 ;; Used for syntactic keywords. N is the match number (1, 2 or 3)."
579 ;; ;; From python-mode...
580 ;; ;;
581 ;; ;; Given a triple quote, we have to check the context to know
582 ;; ;; whether this is an opening or closing triple or whether it's
583 ;; ;; quoted anyhow, and should be ignored. (For that we need to do
584 ;; ;; the same job as `syntax-ppss' to be correct and it seems to be OK
585 ;; ;; to use it here despite initial worries.) We also have to sort
586 ;; ;; out a possible prefix -- well, we don't _have_ to, but I think it
587 ;; ;; should be treated as part of the string.
588
589 ;; ;; Test cases:
590 ;; ;; ur"""ar""" x='"' # """
591 ;; ;; x = ''' """ ' a
592 ;; ;; '''
593 ;; ;; x '"""' x """ \"""" x
594 ;; (save-excursion
595 ;; (goto-char (match-beginning 0))
596 ;; (cond
597 ;; ;; Consider property for the last char if in a fenced string.
598 ;; ((= n 3)
599 ;; (let* ((font-lock-syntactic-keywords nil)
600 ;; (syntax (syntax-ppss)))
601 ;; (when (eq t (nth 3 syntax)) ; after unclosed fence
602 ;; (goto-char (nth 8 syntax)) ; fence position
603 ;; ;; (skip-chars-forward "uUrR") ; skip any prefix
604 ;; ;; Is it a matching sequence?
605 ;; (if (eq (char-after) (char-after (match-beginning 2)))
606 ;; (eval-when-compile (string-to-syntax "|"))))))
607 ;; ;; Consider property for initial char, accounting for prefixes.
608 ;; ((or (and (= n 2) ; leading quote (not prefix)
609 ;; (not (match-end 1))) ; prefix is null
610 ;; (and (= n 1) ; prefix
611 ;; (match-end 1))) ; non-empty
612 ;; (let ((font-lock-syntactic-keywords nil))
613 ;; (unless (eq 'string (syntax-ppss-context (syntax-ppss)))
614 ;; (eval-when-compile (string-to-syntax "|")))))
615 ;; ;; Otherwise (we're in a non-matching string) the property is
616 ;; ;; nil, which is OK.
617 ;; )))
168b32d @disnet fixing triple quoted strings issue with code from python-mode
disnet authored
618
3a47b28 @defunkt docs
authored
619 ;;
620 ;; Define Major Mode
621 ;;
622
af021a5 @josh magic autoload comments
josh authored
623 ;;;###autoload
cf028f8 @defunkt basics
authored
624 (define-derived-mode coffee-mode fundamental-mode
4631aa1 Use "Coffee" as mode name rather than the idiosynchratic "coffee-mode".
Daniel Brockman authored
625 "Coffee"
626 "Major mode for editing CoffeeScript."
cf028f8 @defunkt basics
authored
627
628 ;; code for syntax highlighting
629 (setq font-lock-defaults '((coffee-font-lock-keywords)))
630
1c8aea3 @chellmuth Fix syntax highlighting for variables containing keywords bounded by
chellmuth authored
631 ;; treat "_" as part of a word
632 (modify-syntax-entry ?_ "w" coffee-mode-syntax-table)
633
84ab684 @defunkt comments
authored
634 ;; perl style comment: "# ..."
635 (modify-syntax-entry ?# "< b" coffee-mode-syntax-table)
636 (modify-syntax-entry ?\n "> b" coffee-mode-syntax-table)
40a5bf1 @defunkt comment-start is buffer local. fixes #10
authored
637 (make-local-variable 'comment-start)
0480381 @defunkt mini docs
authored
638 (setq comment-start "#")
84ab684 @defunkt comments
authored
639
9ff612a @defunkt single quotes
authored
640 ;; single quote strings
641 (modify-syntax-entry ?' "\"" coffee-mode-syntax-table)
642
c5fb056 remove triple quotes, seems to be doing strange things to python-mode
Justine Tunney authored
643 ;; (setq font-lock-syntactic-keywords
644 ;; ;; Make outer chars of matching triple-quote sequences into generic
645 ;; ;; string delimiters.
646 ;; ;; First avoid a sequence preceded by an odd number of backslashes.
647 ;; `((,(concat "\\(?:^\\|[^\\]\\(?:\\\\.\\)*\\)" ;Prefix.
648 ;; "\\(?:\\('\\)\\('\\)\\('\\)\\|\\(?1:\"\\)\\(?2:\"\\)\\(?3:\"\\)\\)")
649 ;; (1 (coffee-quote-syntax 1) nil lax)
650 ;; (2 (coffee-quote-syntax 2))
651 ;; (3 (coffee-quote-syntax 3)))))
168b32d @disnet fixing triple quoted strings issue with code from python-mode
disnet authored
652
d6b78ed @defunkt defvars and basic indentation
authored
653 ;; indentation
654 (make-local-variable 'indent-line-function)
655 (setq indent-line-function 'coffee-indent-line)
b4b2a53 @kelleyk Small patch to fix indentation behavior; before, the global tab-width se...
kelleyk authored
656 (set (make-local-variable 'tab-width) coffee-tab-width)
d6b78ed @defunkt defvars and basic indentation
authored
657
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
658 ;; imenu
659 (make-local-variable 'imenu-create-index-function)
660 (setq imenu-create-index-function 'coffee-imenu-create-index)
661
d6b78ed @defunkt defvars and basic indentation
authored
662 ;; no tabs
be2305f @rrthomas Remove support for removing trailing whitespace: whitepace-mode does tha...
rrthomas authored
663 (setq indent-tabs-mode nil))
eaf28ab @defunkt register as .coffee handler
authored
664
6eb6d99 @knu Introduce a minor mode `coffee-cos-mode'.
knu authored
665 ;;
666 ;; Compile-on-Save minor mode
667 ;;
668
669 (defvar coffee-cos-mode-line " CoS")
670 (make-variable-buffer-local 'coffee-cos-mode-line)
671
672 (define-minor-mode coffee-cos-mode
673 "Toggle compile-on-save for coffee-mode."
674 :group 'coffee-cos :lighter coffee-cos-mode-line
675 (cond
676 (coffee-cos-mode
677 (add-hook 'after-save-hook 'coffee-compile-file nil t))
678 (t
679 (remove-hook 'after-save-hook 'coffee-compile-file t))))
680
27ffada @defunkt provide something
authored
681 (provide 'coffee-mode)
682
eaf28ab @defunkt register as .coffee handler
authored
683 ;;
684 ;; On Load
685 ;;
686
687 ;; Run coffee-mode for files ending in .coffee.
af021a5 @josh magic autoload comments
josh authored
688 ;;;###autoload
eaf28ab @defunkt register as .coffee handler
authored
689 (add-to-list 'auto-mode-alist '("\\.coffee$" . coffee-mode))
af021a5 @josh magic autoload comments
josh authored
690 ;;;###autoload
95bbfe3 autoload coffee-mode for .iced files (IcedCoffeeScript)
Justine Tunney authored
691 (add-to-list 'auto-mode-alist '("\\.iced$" . coffee-mode))
692 ;;;###autoload
605a330 @defunkt highlight Cakefile too
authored
693 (add-to-list 'auto-mode-alist '("Cakefile" . coffee-mode))
a9c8f48 Formatting changes for complians with elp/Marmalade
Scott Barron authored
694 ;;; coffee-mode.el ends here
Something went wrong with that request. Please try again.