Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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