Skip to content

HTTPS clone URL

Subversion checkout URL

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