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