Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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