Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 385 lines (346 sloc) 11.047 kb
8938610 @secondplanet Initial commit
secondplanet authored
1 ;;; elixir-mode.el -- Major mode for editing Elixir files
2
3 ;; Copyright (c) 2011 secondplanet
4 ;; Author: Humza Yaqoob
5 ;; URL: https://github.com/secondplanet/elixir-mode
6 ;; Created: Mon Nov 7 2011
7 ;; Keywords: languages elixir
dcfed58 @secondplanet Several new features.
secondplanet authored
8 ;; Version: 1.0.0
8938610 @secondplanet Initial commit
secondplanet authored
9
10 ;; This file is not a part of GNU Emacs.
dcfed58 @secondplanet Several new features.
secondplanet authored
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.
8938610 @secondplanet Initial commit
secondplanet authored
25
26 ;;; Commentary:
27
28 ;; Provides font-locking, indentation support, and navigation for Elixir programs.
29
30 ;;; Code:
31
dcfed58 @secondplanet Several new features.
secondplanet authored
32 (require 'comint) ; for interactive REPL
33 (require 'easymenu) ; for menubar features
34
35 (defconst elixir-mode-version "1.0.0"
8938610 @secondplanet Initial commit
secondplanet authored
36 "Elixir mode version number.")
dcfed58 @secondplanet Several new features.
secondplanet authored
37 (defconst elixir-mode-date "2011-11-12"
8b2609d @secondplanet Fixes
secondplanet authored
38 "Elixir mode version date.")
8938610 @secondplanet Initial commit
secondplanet authored
39
40 (defvar elixir-mode-hook nil)
dcfed58 @secondplanet Several new features.
secondplanet authored
41 (defvar elixir-mode-map (make-keymap)
42 "Elixir mode keymap.")
43
44 (defgroup elixir nil
45 "Elixir major mode."
46 :group 'languages)
47
48 (defcustom elixir-compiler-command "elixirc"
49 "Elixir mode command to compile code. Must be in your path."
50 :type 'string
51 :group 'elixir)
52
53 (defcustom elixir-iex-command "iex"
54 "Elixir mode command for interactive REPL. Must be in your path."
55 :type 'string
56 :group 'elixir)
57
58 (defcustom elixir-mode-highlight-operators t
59 "Elixir mode option for whether or not to highlight operators."
60 :type 'boolean
61 :group 'elixir)
62
63 (defcustom elixir-mode-cygwin-paths t
64 "Elixir mode use Cygwin style paths on Windows operating systems."
65 :type 'boolean
66 :group 'elixir)
67
68 (defcustom elixir-mode-cygwin-prefix "/cygdrive/C"
69 "Elixir mode Cygwin prefix."
70 :type 'string
71 :group 'elixir)
8938610 @secondplanet Initial commit
secondplanet authored
72
73 (defvar elixir-mode-keyword-names '(
a9d3b92 @secondplanet Fixes
secondplanet authored
74 "->"
d20d388 @k1complete new syntax keyword
k1complete authored
75 "bc"
76 "lc"
77 "in"
78 "fn"
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
79 "quote"
80 "unquote"
81 "unquote_splicing"
82 "var"
a9d3b92 @secondplanet Fixes
secondplanet authored
83 "do"
84 "after"
85 "for"
d20d388 @k1complete new syntax keyword
k1complete authored
86 "def"
4f56cca @k1complete add keywords
k1complete authored
87 "defdelegate"
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
88 "defimpl"
d20d388 @k1complete new syntax keyword
k1complete authored
89 "defmacro"
90 "defmacrop"
91 "defmodule"
92 "defoverridable"
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
93 "defp"
d20d388 @k1complete new syntax keyword
k1complete authored
94 "defprotocol"
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
95 "defrecord"
d20d388 @k1complete new syntax keyword
k1complete authored
96 "destructure"
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
97 "refer"
98 "require"
99 "import"
100 "use"
a9d3b92 @secondplanet Fixes
secondplanet authored
101 "if"
f57e6ad @k1complete add keyword loop/recur
k1complete authored
102 "loop"
103 "recur"
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
104 "true"
105 "false"
a9d3b92 @secondplanet Fixes
secondplanet authored
106 "when"
107 "case"
d20d388 @k1complete new syntax keyword
k1complete authored
108 "cond"
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
109 "throw"
a9d3b92 @secondplanet Fixes
secondplanet authored
110 "then"
111 "else"
112 "elsif"
113 "try"
114 "catch"
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
115 "rescue"
116 "fn"
117 "receive"
a9d3b92 @secondplanet Fixes
secondplanet authored
118 "end")
8938610 @secondplanet Initial commit
secondplanet authored
119 "Elixir mode keywords.")
120 (defvar elixir-mode-module-names '(
a9d3b92 @secondplanet Fixes
secondplanet authored
121 "Atom"
122 "BitString"
123 "Code"
124 "Date"
125 "DateTime"
126 "EEx"
215ff72 @k1complete ?" string escape fix
k1complete authored
127 "Enum"
a9d3b92 @secondplanet Fixes
secondplanet authored
128 "ETS"
129 "ExUnit"
130 "File"
131 "Float"
132 "Function"
133 "GenServer"
134 "GenTCP"
135 "IEX"
136 "Integer"
137 "IO"
138 "List"
139 "Math"
140 "Method"
141 "Module"
142 "Numeric"
143 "OrderedDict"
144 "OS"
145 "Port"
146 "Process"
147 "Record"
148 "Reference"
149 "Regexp"
150 "Set"
151 "String"
152 "Timer"
153 "Tuple"
d20d388 @k1complete new syntax keyword
k1complete authored
154 "URI"
a9d3b92 @secondplanet Fixes
secondplanet authored
155 "UnboundMethod")
8938610 @secondplanet Initial commit
secondplanet authored
156 "Elixir mode modules.")
157 (defvar elixir-mode-builtin-names '(
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
158 "Erlang"
159 "__MODULE__"
160 "__FUNCTION__"
161 "__LINE__"
162 "__FILE__"
163 "__MAIN__"
164 "__LOCAL__"
165 )
8938610 @secondplanet Initial commit
secondplanet authored
166 "Elixir mode builtins.")
dcfed58 @secondplanet Several new features.
secondplanet authored
167 (defvar elixir-mode-operator-names '(
168 "+"
d20d388 @k1complete new syntax keyword
k1complete authored
169 "++"
170 "<>"
dcfed58 @secondplanet Several new features.
secondplanet authored
171 "-"
172 "/"
173 "*"
174 "div"
175 "rem"
176 "=="
177 "!="
178 "<="
179 "<"
180 ">="
181 ">"
182 "==="
183 "!=="
184 "and"
185 "or"
186 "andalso"
187 "orelse"
188 "not"
189 "&&"
190 "||"
191 "!"
192 "."
193 "#"
194 "="
195 ":="
196 "<-")
197 "Elixir mode operators.")
0a21c18 @k1complete rename find-last-indent to elixir-mode-find-last-indent
k1complete authored
198 (defvar elixir-basic-offset default-tab-width)
199 (defvar elixir-key-label-offset 2)
dcfed58 @secondplanet Several new features.
secondplanet authored
200
201 (defvar font-lock-operator-face 'font-lock-operator-face)
202 (defface font-lock-operator-face
203 '((((type tty) (class color)) nil)
204 (((class color) (background light))
205 (:foreground "darkred"))
206 (t nil))
207 "For use with operators."
208 :group 'font-lock-faces)
209
210 (defvar font-lock-atom-face 'font-lock-atom-face)
211 (defface font-lock-operator-face
212 '((((type tty) (class color)) nil)
213 (((class color) (background light))
214 (:foreground "magenta"))
215 (t nil))
216 "For use with atoms."
217 :group 'font-lock-faces)
8938610 @secondplanet Initial commit
secondplanet authored
218
219 (defconst elixir-mode-font-lock-defaults
a9d3b92 @secondplanet Fixes
secondplanet authored
220 (list
eff1b7a @k1complete comment % -> #
k1complete authored
221 '("#.*$" . font-lock-comment-face) ; comments
215ff72 @k1complete ?" string escape fix
k1complete authored
222 '("^\\s *defp?\\s +\\([^( \t\n]+\\)" . font-lock-function-name-face) ; methods
dcfed58 @secondplanet Several new features.
secondplanet authored
223 `(,(concat "\\<" (regexp-opt elixir-mode-keyword-names t) "\\>") . font-lock-keyword-face) ; keywords
224 `(,(concat "\\<" (regexp-opt elixir-mode-builtin-names t) "\\>") . font-lock-builtin-face) ; builtins
225 `(,(concat "\\<" (regexp-opt elixir-mode-module-names t) "\\>") . font-lock-type-face) ; core modules
215ff72 @k1complete ?" string escape fix
k1complete authored
226 (when elixir-mode-highlight-operators `(,(concat "\\<" (regexp-opt elixir-mode-operator-names t) "\\>") . font-lock-operator-face)) ; operators
dcfed58 @secondplanet Several new features.
secondplanet authored
227 '("\\(\\w*\\)\\s-*:?=" . font-lock-variable-name-face) ; variables
228 '("-[Rr].*[ \n\t]" . font-lock-constant-face) ; regexes
229 '("\\<\\(true\\|false\\|nil\\)\\>" . font-lock-atom-face) ; atoms, boolean
230 '("'\\w*" . font-lock-atom-face)) ; atoms, generic
a9d3b92 @secondplanet Fixes
secondplanet authored
231 "Highlighting for Elixir mode.")
0a21c18 @k1complete rename find-last-indent to elixir-mode-find-last-indent
k1complete authored
232 (defun elixir-mode-find-last-indent (s)
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
233 "find last indent for s"
234 (let ((f nil))
235 (progn (while (not (or (setq f (looking-at s)) (bobp)))
236 (forward-line -1))
237 f)))
238
8938610 @secondplanet Initial commit
secondplanet authored
239 (defun elixir-mode-indent-line ()
8b2609d @secondplanet Fixes
secondplanet authored
240 "Indent current line as Elixir code."
241 (interactive)
242 (beginning-of-line)
243 (if (bobp)
a9d3b92 @secondplanet Fixes
secondplanet authored
244 (indent-line-to 0)
245 (let ((not-indented t) cur-indent)
d20d388 @k1complete new syntax keyword
k1complete authored
246 (cond ((looking-at "^[ \t]*\\(->\\|else\\|elsif\\|after\\|catch\\|rescue\\).*")
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
247 (progn
248 (save-excursion
249 (forward-line -1)
d20d388 @k1complete new syntax keyword
k1complete authored
250 (if (elixir-mode-find-last-indent "^[ \t]*\\(case\\|cond\\|loop\\|receive\\|try\\).*")
0a21c18 @k1complete rename find-last-indent to elixir-mode-find-last-indent
k1complete authored
251 (setq cur-indent (+ (current-indentation) elixir-key-label-offset))
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
252 (setq not-indented nil)))))
253 ((looking-at "^[ \t]*end$")
254 (progn
255 (save-excursion
256 (forward-line -1)
257 (setq cur-indent (- (current-indentation) elixir-basic-offset)))
258 (if (< cur-indent 0)
259 (setq cur-indent 0))))
260 (t (save-excursion
261 (while not-indented
262 (forward-line -1)
263 (if (looking-at "^[ \t]*end$")
264 (progn
265 (setq cur-indent (current-indentation))
266 (setq not-indented nil))
f57e6ad @k1complete add keyword loop/recur
k1complete authored
267 (if (looking-at "^.*[^:]\\(do\\|->\\)$")
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
268 (progn
269 (setq cur-indent (+ (current-indentation) elixir-basic-offset))
270 (setq not-indented nil))
271 (if (bobp)
272 (setq not-indented nil))))))))
a9d3b92 @secondplanet Fixes
secondplanet authored
273 (if cur-indent
f7bb1c4 @k1complete fix indent for "case" syntax
k1complete authored
274 (indent-line-to cur-indent)
a9d3b92 @secondplanet Fixes
secondplanet authored
275 (indent-line-to 0)))))
8938610 @secondplanet Initial commit
secondplanet authored
276
dcfed58 @secondplanet Several new features.
secondplanet authored
277 (defun elixir-mode-cygwin-path (expanded-file-name)
278 "Elixir mode get Cygwin absolute path name."
279 (replace-regexp-in-string "^[a-zA-Z]:" elixir-mode-cygwin-prefix expanded-file-name t))
280
281 (defun elixir-mode-universal-path (file-name)
282 "Elixir mode multi-OS path handler."
283 (let ((full-file-name (expand-file-name file-name)))
284 (if (and (equal system-type 'windows-nt)
285 elixir-mode-cygwin-paths)
286 (elixir-mode-cygwin-path full-file-name)
287 full-file-name)))
288
289 (defun elixir-mode-command-compile (file-name)
290 "Elixir mode command to compile a file."
291 (let ((full-file-name (elixir-mode-universal-path file-name)))
292 (mapconcat 'identity (append (list elixir-compiler-command) (list full-file-name)) " ")))
293
294 (defun elixir-mode-compiled-file-name (&optional filename)
295 "Elixir mode compiled filename."
296 (concat (file-name-sans-extension (or filename (buffer-file-name))) ".beam"))
297
298 (defun elixir-mode-compile-file ()
299 "Elixir mode compile and save current file."
300 (interactive)
301 (let ((compiler-output (shell-command-to-string (elixir-mode-command-compile (buffer-file-name)))))
302 (when (string= compiler-output "")
303 (message "Compiled and saved as %s" (elixir-mode-compiled-file-name)))))
304
305 (defun elixir-mode-iex ()
306 "Elixir mode interactive REPL."
307 (interactive)
308 (unless (comint-check-proc "*IEX*")
309 (set-buffer
310 (apply 'make-comint "IEX"
311 elixir-iex-command nil '())))
312 (pop-to-buffer "*IEX*"))
313
314 (defun elixir-mode-open-modegithub ()
315 "Elixir mode open GitHub page."
316 (interactive)
317 (browse-url "https://github.com/secondplanet/elixir-mode"))
318
319 (defun elixir-mode-open-elixir-home ()
320 "Elixir mode go to language home."
321 (interactive)
322 (browse-url "https://github.com/josevalim/elixir#README"))
323
324 (defun elixir-mode-show-version ()
325 "Elixir mode print version."
326 (interactive)
327 (message (concat "elixir-mode v" elixir-mode-version " " elixir-mode-date " by Humza Yaqoob")))
328
8938610 @secondplanet Initial commit
secondplanet authored
329 (defvar elixir-mode-syntax-table
8b2609d @secondplanet Fixes
secondplanet authored
330 (let ((elixir-mode-syntax-table (make-syntax-table)))
215ff72 @k1complete ?" string escape fix
k1complete authored
331 (modify-syntax-entry ?? "\\" elixir-mode-syntax-table)
8b2609d @secondplanet Fixes
secondplanet authored
332 (modify-syntax-entry ?_ "w" elixir-mode-syntax-table)
d20d388 @k1complete new syntax keyword
k1complete authored
333 ; (modify-syntax-entry ?# "<" elixir-mode-syntax-table)
334 ; (modify-syntax-entry ?\n ">" elixir-mode-syntax-table)
8b2609d @secondplanet Fixes
secondplanet authored
335 (modify-syntax-entry ?\( "()" elixir-mode-syntax-table)
336 (modify-syntax-entry ?\) ")(" elixir-mode-syntax-table)
337 (modify-syntax-entry ?\{ "(}" elixir-mode-syntax-table)
338 (modify-syntax-entry ?\} "){" elixir-mode-syntax-table)
339 (modify-syntax-entry ?\[ "(]" elixir-mode-syntax-table)
340 (modify-syntax-entry ?\] ")[" elixir-mode-syntax-table)
341 elixir-mode-syntax-table)
342 "Elixir mode syntax table.")
8938610 @secondplanet Initial commit
secondplanet authored
343
dcfed58 @secondplanet Several new features.
secondplanet authored
344 (easy-menu-define elixir-mode-menu elixir-mode-map
345 "Elixir mode menu."
346 '("Elixir"
347 ["Indent line" elixir-mode-indent-line]
348 ["Compile file" elixir-mode-compile-file]
349 ["IEX" elixir-mode-iex]
350 "---"
351 ["elixir-mode on GitHub" elixir-mode-open-modegithub]
352 ["Elixir homepage" elixir-mode-open-elixirhome]
353 ["About" elixir-mode-show-version]
354 ))
355
8938610 @secondplanet Initial commit
secondplanet authored
356 (defun elixir-mode ()
8b2609d @secondplanet Fixes
secondplanet authored
357 "Major mode for editing Elixir files."
f75b823 @secondplanet Fix typo
secondplanet authored
358 (interactive)
32cdb08 @secondplanet whitespace
secondplanet authored
359 (kill-all-local-variables)
360 (set-syntax-table elixir-mode-syntax-table)
361 (set (make-local-variable 'indent-line-function) 'elixir-mode-indent-line)
362 (set (make-local-variable 'font-lock-defaults) '(elixir-mode-font-lock-defaults))
363 (setq major-mode 'elixir-mode)
364 (setq mode-name "Elixir")
365 (run-hooks 'elixir-mode-hook))
8b2609d @secondplanet Fixes
secondplanet authored
366
dcfed58 @secondplanet Several new features.
secondplanet authored
367 (define-minor-mode elixir-cos-mode
368 "Elixir mode toggle compile on save."
369 :group 'elixir-cos :lighter " CoS"
370 (cond
371 (elixir-cos-mode
372 (add-hook 'after-save-hook 'elixir-mode-compile-file nil t))
373 (t
374 (remove-hook 'after-save-hook 'elixir-mode-compile-file t))))
8938610 @secondplanet Initial commit
secondplanet authored
375
376 (provide 'elixir-mode)
dcfed58 @secondplanet Several new features.
secondplanet authored
377
378 ;; automatically opening ex and exs in elixir-mode
379 ;;;###autoload
380 (add-to-list 'auto-mode-alist '("\\.ex\\'" . elixir-mode))
381 ;;;###autoload
382 (add-to-list 'auto-mode-alist '("\\.exs\\'" . elixir-mode))
51fa031 @secondplanet End
secondplanet authored
383
384 ;;; elixir-mode.el ends here
Something went wrong with that request. Please try again.