Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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