Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 652 lines (516 sloc) 20.248 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
03f75e3 @defunkt 0.3.0
authored
5 ;; Version 0.3.0
4a11c70 @defunkt documentation
authored
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
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
03f75e3 @defunkt 0.3.0
authored
69 (defconst coffee-mode-version "0.3.0"
5f14029 @defunkt Menu
authored
70 "The version of this `coffee-mode'.")
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-debug-mode nil
77 "Whether to run in debug mode or not. Logs to `*Messages*'."
78 :type 'boolean
79 :group 'coffee-mode)
80
81 (defcustom coffee-js-mode 'js2-mode
82 "The mode to use when viewing compiled JavaScript."
83 :type 'string
84 :group 'coffee)
85
86 (defcustom coffee-cleanup-whitespace t
87 "Should we `delete-trailing-whitespace' on save? Probably."
88 :type 'boolean
89 :group 'coffee)
90
91 (defcustom coffee-tab-width tab-width
92 "The tab width to use when indenting."
93 :type 'integer
94 :group 'coffee)
95
96 (defcustom coffee-command "coffee"
7557530 @defunkt compilation commands
authored
97 "The CoffeeScript command used for evaluating code. Must be in your
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
98 path."
99 :type 'string
100 :group 'coffee)
7557530 @defunkt compilation commands
authored
101
3b0962d @defunkt Rename `args` variables to be more consistent.
authored
102 (defcustom coffee-args-repl '("-i")
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
103 "The command line arguments to pass to `coffee-command' to start a REPL."
104 :type 'list
105 :group 'coffee)
28485fa @defunkt `coffee-repl'
authored
106
227a360 @orlandohill Customize args for compiling files and display the first compiler error
orlandohill authored
107 (defcustom coffee-args-compile '("-c")
108 "The command line arguments to pass to `coffee-command' when compiling a file."
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
109 :type 'list
110 :group 'coffee)
5f14029 @defunkt Menu
authored
111
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
112 (defcustom coffee-compiled-buffer-name "*coffee-compiled*"
113 "The name of the scratch buffer used when compiling CoffeeScript."
114 :type 'string
115 :group 'coffee)
7557530 @defunkt compilation commands
authored
116
14a0d56 @errge Added coffee-compile-jump-to-error.
errge authored
117 (defcustom coffee-compile-jump-to-error t
118 "Whether to jump to the first error if compilation fails.
119 Please note that the coffee compiler doesn't always give a line
120 number for the issue and in that case it is not possible to jump
121 to the error, of course."
122 :type 'boolean
123 :group 'coffee)
124
1b887a5 @defunkt clean whitespace on save
authored
125 (defvar coffee-mode-hook nil
126 "A hook for you to run your own code when the mode is loaded.")
127
eee29e0 @defunkt defvar the keymap
authored
128 (defvar coffee-mode-map (make-keymap)
129 "Keymap for CoffeeScript major mode.")
130
38ce8da @defunkt small tweaks
authored
131 ;;
c5ffe04 @defunkt setd macro for logging variable values when setting them
authored
132 ;; Macros
5b00ae2 @defunkt more todo
authored
133 ;;
134
c5ffe04 @defunkt setd macro for logging variable values when setting them
authored
135 (defmacro setd (var val)
136 "Like setq but optionally logs the variable's value using `coffee-debug'."
cd06e4e @mkhl Fix compiling `coffee-mode' without loading it.
mkhl authored
137 (if (and (boundp 'coffee-debug-mode) coffee-debug-mode)
c6562af @defunkt Make `coffee-debug' a macro
authored
138 `(progn
139 (coffee-debug "%s: %s" ',var ,val)
140 (setq ,var ,val))
141 `(setq ,var ,val)))
142
2799609 @defunkt back out that macro change for now, something is funny
authored
143 (defun coffee-debug (string &rest args)
c6562af @defunkt Make `coffee-debug' a macro
authored
144 "Print a message when in debug mode."
145 (when coffee-debug-mode
2799609 @defunkt back out that macro change for now, something is funny
authored
146 (apply 'message (append (list string) args))))
c5ffe04 @defunkt setd macro for logging variable values when setting them
authored
147
b7ee8b8 @defunkt start cleaning up indentation code
authored
148 (defmacro coffee-line-as-string ()
149 "Returns the current line as a string."
150 `(buffer-substring (point-at-bol) (point-at-eol)))
151
5b00ae2 @defunkt more todo
authored
152 ;;
38ce8da @defunkt small tweaks
authored
153 ;; Commands
154 ;;
155
28485fa @defunkt `coffee-repl'
authored
156 (defun coffee-repl ()
157 "Launch a CoffeeScript REPL using `coffee-command' as an inferior mode."
158 (interactive)
159
17150cf @defunkt docs and starting to implement indenters
authored
160 (unless (comint-check-proc "*CoffeeREPL*")
28485fa @defunkt `coffee-repl'
authored
161 (set-buffer
17150cf @defunkt docs and starting to implement indenters
authored
162 (apply 'make-comint "CoffeeREPL"
3b0962d @defunkt Rename `args` variables to be more consistent.
authored
163 coffee-command nil coffee-args-repl)))
28485fa @defunkt `coffee-repl'
authored
164
8a3d6f5 Updating coffee-repl to pop-to-buffer using the name '*CoffeeREPL*' i…
Nick Parker authored
165 (pop-to-buffer "*CoffeeREPL*"))
38ce8da @defunkt small tweaks
authored
166
62c84fb @knu Add a function coffee-compiled-file-name for ease of scripting.
knu authored
167 (defun coffee-compiled-file-name (&optional filename)
168 "Returns the name of the JavaScript file compiled from a CoffeeScript file.
169 If FILENAME is omitted, the current buffer's file name is used."
170 (concat (file-name-sans-extension (or filename (buffer-file-name))) ".js"))
171
cbd31f9 @defunkt coffee-compile-file
authored
172 (defun coffee-compile-file ()
173 "Compiles and saves the current file to disk. Doesn't open in a buffer.."
174 (interactive)
227a360 @orlandohill Customize args for compiling files and display the first compiler error
orlandohill authored
175 (let ((compiler-output (shell-command-to-string (coffee-command-compile (buffer-file-name)))))
176 (if (string= compiler-output "")
62c84fb @knu Add a function coffee-compiled-file-name for ease of scripting.
knu authored
177 (message "Compiled and saved %s" (coffee-compiled-file-name))
14a0d56 @errge Added coffee-compile-jump-to-error.
errge authored
178 (let* ((msg (car (split-string compiler-output "[\n\r]+")))
179 (line (and (string-match "on line \\([0-9]+\\)" msg)
180 (string-to-number (match-string 1 msg)))))
181 (message msg)
182 (when (and coffee-compile-jump-to-error line (> line 0))
183 (goto-char (point-min))
184 (forward-line (1- line)))))))
cbd31f9 @defunkt coffee-compile-file
authored
185
7557530 @defunkt compilation commands
authored
186 (defun coffee-compile-buffer ()
17150cf @defunkt docs and starting to implement indenters
authored
187 "Compiles the current buffer and displays the JS in another buffer."
7557530 @defunkt compilation commands
authored
188 (interactive)
189 (save-excursion
190 (coffee-compile-region (point-min) (point-max))))
191
192 (defun coffee-compile-region (start end)
17150cf @defunkt docs and starting to implement indenters
authored
193 "Compiles a region and displays the JS in another buffer."
7557530 @defunkt compilation commands
authored
194 (interactive "r")
195
196 (let ((buffer (get-buffer coffee-compiled-buffer-name)))
197 (when buffer
198 (kill-buffer buffer)))
199
200 (call-process-region start end coffee-command nil
201 (get-buffer-create coffee-compiled-buffer-name)
202 nil
b874bf4 @defunkt --no-wrap is deprecated; please use --bare instead.
authored
203 "-s" "-p" "--bare")
e3c21f8 @tav Change so that the compiled buffer doesn't open in a new frame.
tav authored
204 (switch-to-buffer (get-buffer coffee-compiled-buffer-name))
7557530 @defunkt compilation commands
authored
205 (funcall coffee-js-mode)
6639c36 @mkhl Silence byte-compiler warnings.
mkhl authored
206 (goto-char (point-min)))
3a47b28 @defunkt docs
authored
207
5f14029 @defunkt Menu
authored
208 (defun coffee-show-version ()
209 "Prints the `coffee-mode' version."
210 (interactive)
211 (message (concat "coffee-mode v" coffee-mode-version)))
212
fd314cc @defunkt menu tweaks
authored
213 (defun coffee-open-reference ()
214 "Open browser to CoffeeScript reference."
215 (interactive)
216 (browse-url "http://jashkenas.github.com/coffee-script/"))
217
48c36c1 @defunkt open node.js api in browser
authored
218 (defun coffee-open-node-reference ()
1f9bc1a @markhellewell nodejs.org docs changed location.
markhellewell authored
219 "Open browser to node.js documentation."
48c36c1 @defunkt open node.js api in browser
authored
220 (interactive)
1f9bc1a @markhellewell nodejs.org docs changed location.
markhellewell authored
221 (browse-url "http://nodejs.org/docs/"))
48c36c1 @defunkt open node.js api in browser
authored
222
5f14029 @defunkt Menu
authored
223 (defun coffee-open-github ()
fd314cc @defunkt menu tweaks
authored
224 "Open browser to `coffee-mode' project on GithHub."
5f14029 @defunkt Menu
authored
225 (interactive)
226 (browse-url "http://github.com/defunkt/coffee-mode"))
227
228 ;;
229 ;; Menubar
230 ;;
231
232 (easy-menu-define coffee-mode-menu coffee-mode-map
233 "Menu for CoffeeScript mode"
234 '("CoffeeScript"
cbd31f9 @defunkt coffee-compile-file
authored
235 ["Compile File" coffee-compile-file]
5f14029 @defunkt Menu
authored
236 ["Compile Buffer" coffee-compile-buffer]
237 ["Compile Region" coffee-compile-region]
5256afd @defunkt tweaks
authored
238 ["REPL" coffee-repl]
5f14029 @defunkt Menu
authored
239 "---"
48c36c1 @defunkt open node.js api in browser
authored
240 ["CoffeeScript Reference" coffee-open-reference]
241 ["node.js Reference" coffee-open-node-reference]
fd314cc @defunkt menu tweaks
authored
242 ["coffee-mode on GitHub" coffee-open-github]
5f14029 @defunkt Menu
authored
243 ["Version" coffee-show-version]
244 ))
245
3a47b28 @defunkt docs
authored
246 ;;
247 ;; Define Language Syntax
248 ;;
249
c5831bb @sstephenson Fix for string literals with escaped quotes
sstephenson authored
250 ;; String literals
251 (defvar coffee-string-regexp "\"\\([^\\]\\|\\\\.\\)*?\"\\|'\\([^\\]\\|\\\\.\\)*?'")
252
3a47b28 @defunkt docs
authored
253 ;; Instance variables (implicit this)
2bb69be Regex for "this" variable includes underscore.
Ryan Koopmans authored
254 (defvar coffee-this-regexp "@\\(\\w\\|_\\)*\\|this")
3a47b28 @defunkt docs
authored
255
dc85f42 @tav Added support for the shorthand::syntax for .prototype.
tav authored
256 ;; Prototype::access
257 (defvar coffee-prototype-regexp "\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\)::\\(\\(\\w\\|\\.\\|_\\| \\|$\\)+?\\):")
258
88e7b95 @defunkt better regexps, @blah: and {blah: true, blah2:true}
authored
259 ;; Assignment
37b481e @defunkt Better assignment highlighting for `:`
authored
260 (defvar coffee-assign-regexp "\\(\\(\\w\\|\\.\\|_\\|$\\)+?\s*\\):")
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
261
262 ;; Lambda
00c197b @defunkt elisp regexps are fun
authored
263 (defvar coffee-lambda-regexp "\\((.+)\\)?\\s *\\(->\\|=>\\)")
88e7b95 @defunkt better regexps, @blah: and {blah: true, blah2:true}
authored
264
76ed341 @defunkt class support in imenu
authored
265 ;; Namespaces
266 (defvar coffee-namespace-regexp "\\b\\(class\\s +\\(\\S +\\)\\)\\b")
267
af34f91 @defunkt Booleans, better colors
authored
268 ;; Booleans
af81c6a @defunkt Highlight null. closes #4
authored
269 (defvar coffee-boolean-regexp "\\b\\(true\\|false\\|yes\\|no\\|on\\|off\\|null\\)\\b")
3a47b28 @defunkt docs
authored
270
dbb4ec5 @defunkt comment tweaks
authored
271 ;; Regular Expressions
88e1c8c @mooz Fix for regexp literals with slashes in brackets.
mooz authored
272 (defvar coffee-regexp-regexp "\\/\\(\\\\.\\|\\[\\(\\\\.\\|.\\)+?\\]\\|[^/]\\)+?\\/")
3a47b28 @defunkt docs
authored
273
cf028f8 @defunkt basics
authored
274 ;; JavaScript Keywords
d6b78ed @defunkt defvars and basic indentation
authored
275 (defvar coffee-js-keywords
af34f91 @defunkt Booleans, better colors
authored
276 '("if" "else" "new" "return" "try" "catch"
cf028f8 @defunkt basics
authored
277 "finally" "throw" "break" "continue" "for" "in" "while"
278 "delete" "instanceof" "typeof" "switch" "super" "extends"
7803688 Until and loop are keywords.
Ryan Koopmans authored
279 "class" "until" "loop"))
cf028f8 @defunkt basics
authored
280
281 ;; Reserved keywords either by JS or CS.
d6b78ed @defunkt defvars and basic indentation
authored
282 (defvar coffee-js-reserved
cf028f8 @defunkt basics
authored
283 '("case" "default" "do" "function" "var" "void" "with"
284 "const" "let" "debugger" "enum" "export" "import" "native"
285 "__extends" "__hasProp"))
286
287 ;; CoffeeScript keywords.
d6b78ed @defunkt defvars and basic indentation
authored
288 (defvar coffee-cs-keywords
af34f91 @defunkt Booleans, better colors
authored
289 '("then" "unless" "and" "or" "is"
cf028f8 @defunkt basics
authored
290 "isnt" "not" "of" "by" "where" "when"))
291
0480381 @defunkt mini docs
authored
292 ;; Regular expression combining the above three lists.
d6b78ed @defunkt defvars and basic indentation
authored
293 (defvar coffee-keywords-regexp (regexp-opt
cf028f8 @defunkt basics
authored
294 (append
295 coffee-js-reserved
296 coffee-js-keywords
297 coffee-cs-keywords) 'words))
298
299
ff61700 @defunkt that was bothering me
authored
300 ;; Create the list for font-lock. Each class of keyword is given a
301 ;; particular face.
5256afd @defunkt tweaks
authored
302 (defvar coffee-font-lock-keywords
ff61700 @defunkt that was bothering me
authored
303 ;; *Note*: order below matters. `coffee-keywords-regexp' goes last
304 ;; because otherwise the keyword "state" in the function
305 ;; "state_entry" would be highlighted.
c5831bb @sstephenson Fix for string literals with escaped quotes
sstephenson authored
306 `((,coffee-string-regexp . font-lock-string-face)
307 (,coffee-this-regexp . font-lock-variable-name-face)
dc85f42 @tav Added support for the shorthand::syntax for .prototype.
tav authored
308 (,coffee-prototype-regexp . font-lock-variable-name-face)
ff61700 @defunkt that was bothering me
authored
309 (,coffee-assign-regexp . font-lock-type-face)
310 (,coffee-regexp-regexp . font-lock-constant-face)
311 (,coffee-boolean-regexp . font-lock-constant-face)
312 (,coffee-keywords-regexp . font-lock-keyword-face)))
cf028f8 @defunkt basics
authored
313
3a47b28 @defunkt docs
authored
314 ;;
315 ;; Helper Functions
316 ;;
317
1b887a5 @defunkt clean whitespace on save
authored
318 (defun coffee-before-save ()
319 "Hook run before file is saved. Deletes whitespace if
320 `coffee-cleanup-whitespace' is non-nil."
321 (when coffee-cleanup-whitespace
322 (delete-trailing-whitespace)))
323
9ff612a @defunkt single quotes
authored
324 (defun coffee-comment-dwim (arg)
325 "Comment or uncomment current line or region in a smart way.
326 For detail, see `comment-dwim'."
327 (interactive "*P")
328 (require 'newcomment)
329 (let ((deactivate-mark nil) (comment-start "#") (comment-end ""))
330 (comment-dwim arg)))
84ab684 @defunkt comments
authored
331
227a360 @orlandohill Customize args for compiling files and display the first compiler error
orlandohill authored
332 (defun coffee-command-compile (file-name)
333 "The `coffee-command' with args to compile a file."
334 (mapconcat 'identity (append (list coffee-command) coffee-args-compile (list file-name)) " "))
5b00ae2 @defunkt more todo
authored
335
2504ebe @defunkt explain indentation plan
authored
336 ;;
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
337 ;; imenu support
338 ;;
339
340 ;; This is a pretty naive but workable way of doing it. First we look
341 ;; for any lines that starting with `coffee-assign-regexp' that include
342 ;; `coffee-lambda-regexp' then add those tokens to the list.
343 ;;
344 ;; Should cover cases like these:
345 ;;
346 ;; minus: (x, y) -> x - y
347 ;; String::length: -> 10
348 ;; block: ->
349 ;; print('potion')
350 ;;
351 ;; Next we look for any line that starts with `class' or
352 ;; `coffee-assign-regexp' followed by `{` and drop into a
353 ;; namespace. This means we search one indentation level deeper for
354 ;; more assignments and add them to the alist prefixed with the
355 ;; namespace name.
356 ;;
357 ;; Should cover cases like these:
358 ;;
359 ;; class Person
360 ;; print: ->
361 ;; print 'My name is ' + this.name + '.'
362 ;;
363 ;; class Policeman extends Person
364 ;; constructor: (rank) ->
365 ;; @rank: rank
366 ;; print: ->
367 ;; print 'My name is ' + this.name + " and I'm a " + this.rank + '.'
368 ;;
76ed341 @defunkt class support in imenu
authored
369 ;; TODO:
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
370 ;; app = {
371 ;; window: {width: 200, height: 200}
372 ;; para: -> 'Welcome.'
373 ;; button: -> 'OK'
374 ;; }
375
376 (defun coffee-imenu-create-index ()
377 "Create an imenu index of all methods in the buffer."
378 (interactive)
379
380 ;; This function is called within a `save-excursion' so we're safe.
6639c36 @mkhl Silence byte-compiler warnings.
mkhl authored
381 (goto-char (point-min))
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
382
76ed341 @defunkt class support in imenu
authored
383 (let ((index-alist '()) assign pos indent ns-name ns-indent)
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
384 ;; Go through every assignment that includes -> or => on the same
c6562af @defunkt Make `coffee-debug' a macro
authored
385 ;; line or starts with `class'.
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
386 (while (re-search-forward
76ed341 @defunkt class support in imenu
authored
387 (concat "^\\(\\s *\\)"
388 "\\("
389 coffee-assign-regexp
390 ".+?"
391 coffee-lambda-regexp
392 "\\|"
393 coffee-namespace-regexp
394 "\\)")
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
395 (point-max)
396 t)
397
e1b9c83 @defunkt print full match to debug
authored
398 (coffee-debug "Match: %s" (match-string 0))
399
76ed341 @defunkt class support in imenu
authored
400 ;; If this is the start of a new namespace, save the namespace's
401 ;; indentation level and name.
7f5e1b3 @defunkt Bugfix: Clear old namespace when a new one is found
authored
402 (when (match-string 8)
403 ;; Set the name.
404 (setq ns-name (match-string 8))
405
76ed341 @defunkt class support in imenu
authored
406 ;; If this is a class declaration, add :: to the namespace.
407 (setq ns-name (concat ns-name "::"))
408
409 ;; Save the indentation level.
410 (setq ns-indent (length (match-string 1)))
411
412 ;; Debug
413 (coffee-debug "ns: Found %s with indent %s" ns-name ns-indent))
414
415 ;; If this is an assignment, save the token being
416 ;; assigned. `Please.print:` will be `Please.print`, `block:`
417 ;; will be `block`, etc.
418 (when (setq assign (match-string 3))
419 ;; The position of the match in the buffer.
420 (setq pos (match-beginning 3))
421
422 ;; The indent level of this match
423 (setq indent (length (match-string 1)))
424
425 ;; If we're within the context of a namespace, add that to the
426 ;; front of the assign, e.g.
427 ;; constructor: => Policeman::constructor
428 (when (and ns-name (> indent ns-indent))
429 (setq assign (concat ns-name assign)))
430
431 (coffee-debug "=: Found %s with indent %s" assign indent)
432
433 ;; Clear the namespace if we're no longer indented deeper
434 ;; than it.
435 (when (and ns-name (<= indent ns-indent))
436 (coffee-debug "ns: Clearing %s" ns-name)
437 (setq ns-name nil)
438 (setq ns-indent nil))
439
440 ;; Add this to the alist. Done.
441 (push (cons assign pos) index-alist)))
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
442
443 ;; Return the alist.
444 index-alist))
445
446 ;;
d6b78ed @defunkt defvars and basic indentation
authored
447 ;; Indentation
2504ebe @defunkt explain indentation plan
authored
448 ;;
449
dbb4ec5 @defunkt comment tweaks
authored
450 ;;; The theory is explained in the README.
97a1001 @defunkt basic indentation with TAB
authored
451
d6b78ed @defunkt defvars and basic indentation
authored
452 (defun coffee-indent-line ()
7b03a71 @defunkt indentation theory
authored
453 "Indent current line as CoffeeScript."
d6b78ed @defunkt defvars and basic indentation
authored
454 (interactive)
455
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
456 (if (= (point) (point-at-bol))
457 (insert-tab)
458 (save-excursion
459 (let ((prev-indent 0) (cur-indent 0))
460 ;; Figure out the indentation of the previous line
461 (setd prev-indent (coffee-previous-indent))
97ef92b @defunkt Bugfix: Indentation works when point is at beginning of the line
authored
462
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
463 ;; Figure out the current line's indentation
464 (setd cur-indent (current-indentation))
97ef92b @defunkt Bugfix: Indentation works when point is at beginning of the line
authored
465
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
466 ;; Shift one column to the left
467 (beginning-of-line)
468 (insert-tab)
469
470 (coffee-debug "point: %s" (point))
471 (coffee-debug "point-at-bol: %s" (point-at-bol))
472
473 (when (= (point-at-bol) (point))
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
474 (forward-char coffee-tab-width))
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
475
476 (coffee-debug "New indent: %s" (current-indentation))
b7ee8b8 @defunkt start cleaning up indentation code
authored
477
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
478 ;; We're too far, remove all indentation.
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
479 (when (> (- (current-indentation) prev-indent) coffee-tab-width)
df7ae3b @defunkt Bugfix: Indenting blank lines with TAB
authored
480 (backward-to-indentation 0)
481 (delete-region (point-at-bol) (point)))))))
b7ee8b8 @defunkt start cleaning up indentation code
authored
482
483 (defun coffee-previous-indent ()
484 "Return the indentation level of the previous non-blank line."
97ef92b @defunkt Bugfix: Indentation works when point is at beginning of the line
authored
485
b7ee8b8 @defunkt start cleaning up indentation code
authored
486 (save-excursion
487 (forward-line -1)
d063614 @superbobry Fix hanging of `coffee-previous-indent` at start of buffer.
superbobry authored
488 (if (bobp)
489 0
490 (progn
f4597a0 @typester Fixed inf loop in coffee-previous-indent
typester authored
491 (while (and (coffee-line-empty-p) (not (bobp))) (forward-line -1))
d063614 @superbobry Fix hanging of `coffee-previous-indent` at start of buffer.
superbobry authored
492 (current-indentation)))))
b7ee8b8 @defunkt start cleaning up indentation code
authored
493
494 (defun coffee-line-empty-p ()
495 "Is this line empty? Returns non-nil if so, nil if not."
496 (or (bobp)
497 (string-match "^\\s *$" (coffee-line-as-string))))
df08186 @defunkt indenters
authored
498
17150cf @defunkt docs and starting to implement indenters
authored
499 (defun coffee-newline-and-indent ()
500 "Inserts a newline and indents it to the same level as the previous line."
501 (interactive)
502
503 ;; Remember the current line indentation level,
504 ;; insert a newline, and indent the newline to the same
505 ;; level as the previous line.
506 (let ((prev-indent (current-indentation)) (indent-next nil))
74a9135 @piranha do not leave trailing whitespaces on newline
piranha authored
507 (delete-horizontal-space t)
17150cf @defunkt docs and starting to implement indenters
authored
508 (newline)
7976bc4 @defunkt Make config options available from `customize-group`, document in README
authored
509 (insert-tab (/ prev-indent coffee-tab-width))
3a47b28 @defunkt docs
authored
510
17150cf @defunkt docs and starting to implement indenters
authored
511 ;; We need to insert an additional tab because the last line was special.
512 (when (coffee-line-wants-indent)
513 (insert-tab)))
514
515 ;; Last line was a comment so this one should probably be,
516 ;; too. Makes it easy to write multi-line comments (like the one I'm
517 ;; writing right now).
518 (when (coffee-previous-line-is-comment)
519 (insert "# ")))
520
521 ;; Indenters help determine whether the current line should be
522 ;; indented further based on the content of the previous line. If a
523 ;; line starts with `class', for instance, you're probably going to
524 ;; want to indent the next line.
525
526 (defvar coffee-indenters-bol '("class" "for" "if" "try")
7d338d1 @defunkt coffee-indenters
authored
527 "Keywords or syntax whose presence at the start of a line means the
528 next line should probably be indented.")
529
530 (defun coffee-indenters-bol-regexp ()
531 "Builds a regexp out of `coffee-indenters-bol' words."
27df14a @defunkt Fix coffee-indenters-bol-regexp. Closes #36
authored
532 (regexp-opt coffee-indenters-bol 'words))
7d338d1 @defunkt coffee-indenters
authored
533
5e170be @defunkt get it working (with a fake function though)
authored
534 (defvar coffee-indenters-eol '(?> ?{ ?\[)
535 "Single characters at the end of a line that mean the next line
536 should probably be indented.")
7d338d1 @defunkt coffee-indenters
authored
537
17150cf @defunkt docs and starting to implement indenters
authored
538 (defun coffee-line-wants-indent ()
539 "Does the current line want to be indented deeper than the previous
df08186 @defunkt indenters
authored
540 line? Returns `t' or `nil'. See the README for more details."
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
541 (interactive)
542
17150cf @defunkt docs and starting to implement indenters
authored
543 (save-excursion
544 (let ((indenter-at-bol) (indenter-at-eol))
545 ;; Go back a line and to the first character.
546 (forward-line -1)
547 (backward-to-indentation 0)
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
548
17150cf @defunkt docs and starting to implement indenters
authored
549 ;; If the next few characters match one of our magic indenter
550 ;; keywords, we want to indent the line we were on originally.
551 (when (looking-at (coffee-indenters-bol-regexp))
c5ffe04 @defunkt setd macro for logging variable values when setting them
authored
552 (setd indenter-at-bol t))
17150cf @defunkt docs and starting to implement indenters
authored
553
554 ;; 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
555 ;; see if the last character matches one of our indenter
556 ;; characters.
17150cf @defunkt docs and starting to implement indenters
authored
557 (when (not indenter-at-bol)
558 (end-of-line)
559
5e170be @defunkt get it working (with a fake function though)
authored
560 ;; Optimized for speed - checks only the last character.
14ab5a0 @defunkt Use Common Lisp's `some` despite its inferior API.
authored
561 (when (some (lambda (char)
562 (= (char-before) char))
563 coffee-indenters-eol)
c5ffe04 @defunkt setd macro for logging variable values when setting them
authored
564 (setd indenter-at-eol t)))
17150cf @defunkt docs and starting to implement indenters
authored
565
566 ;; If we found an indenter, return `t'.
567 (or indenter-at-bol indenter-at-eol))))
568
8bfb7ed @defunkt Keep same indentation of last line when creating a new line
authored
569 (defun coffee-previous-line-is-comment ()
570 "Returns `t' if the previous line is a CoffeeScript comment."
571 (save-excursion
572 (forward-line -1)
573 (coffee-line-is-comment)))
574
575 (defun coffee-line-is-comment ()
576 "Returns `t' if the current line is a CoffeeScript comment."
577 (save-excursion
578 (backward-to-indentation 0)
579 (= (char-after) (string-to-char "#"))))
580
3a47b28 @defunkt docs
authored
581 ;;
582 ;; Define Major Mode
583 ;;
584
af021a5 @josh magic autoload comments
josh authored
585 ;;;###autoload
cf028f8 @defunkt basics
authored
586 (define-derived-mode coffee-mode fundamental-mode
4631aa1 Use "Coffee" as mode name rather than the idiosynchratic "coffee-mode".
Daniel Brockman authored
587 "Coffee"
588 "Major mode for editing CoffeeScript."
cf028f8 @defunkt basics
authored
589
1b887a5 @defunkt clean whitespace on save
authored
590 ;; key bindings
7557530 @defunkt compilation commands
authored
591 (define-key coffee-mode-map (kbd "A-r") 'coffee-compile-buffer)
79333bf @defunkt Bugfix: Bad binding
authored
592 (define-key coffee-mode-map (kbd "A-R") 'coffee-compile-region)
eee29e0 @defunkt defvar the keymap
authored
593 (define-key coffee-mode-map (kbd "A-M-r") 'coffee-repl)
7557530 @defunkt compilation commands
authored
594 (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
595 (define-key coffee-mode-map "\C-m" 'coffee-newline-and-indent)
6eb6d99 @knu Introduce a minor mode `coffee-cos-mode'.
knu authored
596 (define-key coffee-mode-map "\C-c\C-o\C-s" 'coffee-cos-mode)
7557530 @defunkt compilation commands
authored
597
cf028f8 @defunkt basics
authored
598 ;; code for syntax highlighting
599 (setq font-lock-defaults '((coffee-font-lock-keywords)))
600
84ab684 @defunkt comments
authored
601 ;; perl style comment: "# ..."
602 (modify-syntax-entry ?# "< b" coffee-mode-syntax-table)
603 (modify-syntax-entry ?\n "> b" coffee-mode-syntax-table)
40a5bf1 @defunkt comment-start is buffer local. fixes #10
authored
604 (make-local-variable 'comment-start)
0480381 @defunkt mini docs
authored
605 (setq comment-start "#")
84ab684 @defunkt comments
authored
606
9ff612a @defunkt single quotes
authored
607 ;; single quote strings
608 (modify-syntax-entry ?' "\"" coffee-mode-syntax-table)
609
d6b78ed @defunkt defvars and basic indentation
authored
610 ;; indentation
611 (make-local-variable 'indent-line-function)
612 (setq indent-line-function 'coffee-indent-line)
b4b2a53 @kelleyk Small patch to fix indentation behavior; before, the global tab-width…
kelleyk authored
613 (set (make-local-variable 'tab-width) coffee-tab-width)
d6b78ed @defunkt defvars and basic indentation
authored
614
30d2af5 @defunkt Basic imenu support - makes things like `textmate-goto-symbol' work!
authored
615 ;; imenu
616 (make-local-variable 'imenu-create-index-function)
617 (setq imenu-create-index-function 'coffee-imenu-create-index)
618
d6b78ed @defunkt defvars and basic indentation
authored
619 ;; no tabs
620 (setq indent-tabs-mode nil)
621
1b887a5 @defunkt clean whitespace on save
authored
622 ;; hooks
adf9654 @defunkt blah
authored
623 (set (make-local-variable 'before-save-hook) 'coffee-before-save))
eaf28ab @defunkt register as .coffee handler
authored
624
6eb6d99 @knu Introduce a minor mode `coffee-cos-mode'.
knu authored
625 ;;
626 ;; Compile-on-Save minor mode
627 ;;
628
629 (defvar coffee-cos-mode-line " CoS")
630 (make-variable-buffer-local 'coffee-cos-mode-line)
631
632 (define-minor-mode coffee-cos-mode
633 "Toggle compile-on-save for coffee-mode."
634 :group 'coffee-cos :lighter coffee-cos-mode-line
635 (cond
636 (coffee-cos-mode
637 (add-hook 'after-save-hook 'coffee-compile-file nil t))
638 (t
639 (remove-hook 'after-save-hook 'coffee-compile-file t))))
640
27ffada @defunkt provide something
authored
641 (provide 'coffee-mode)
642
eaf28ab @defunkt register as .coffee handler
authored
643 ;;
644 ;; On Load
645 ;;
646
647 ;; Run coffee-mode for files ending in .coffee.
af021a5 @josh magic autoload comments
josh authored
648 ;;;###autoload
eaf28ab @defunkt register as .coffee handler
authored
649 (add-to-list 'auto-mode-alist '("\\.coffee$" . coffee-mode))
af021a5 @josh magic autoload comments
josh authored
650 ;;;###autoload
605a330 @defunkt highlight Cakefile too
authored
651 (add-to-list 'auto-mode-alist '("Cakefile" . coffee-mode))
Something went wrong with that request. Please try again.