Skip to content

HTTPS clone URL

Subversion checkout URL

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