Skip to content

HTTPS clone URL

Subversion checkout URL

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