;;; elixir-mode.el --- Major mode for editing Elixir files
|
|
|
|
;; Copyright 2011-2015 secondplanet
|
|
;; 2013-2015 Samuel Tonini, Matt DeBoard, Andreas Fuchs
|
|
;; Authors: Humza Yaqoob,
|
|
;; Andreas Fuchs <asf@boinkor.net>,
|
|
;; Matt DeBoard
|
|
;; Samuel Tonini <tonini.samuel@gmail.com>
|
|
|
|
;; URL: https://github.com/elixir-lang/emacs-elixir
|
|
;; Created: Mon Nov 7 2011
|
|
;; Keywords: languages elixir
|
|
;; Version: 2.3.0-cvs
|
|
|
|
;; This file is not a part of GNU Emacs.
|
|
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation; either version 2, or (at your option)
|
|
;; any later version.
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program; if not, write to the Free Software
|
|
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
;;; Commentary:
|
|
|
|
;; Provides font-locking, indentation and navigation support
|
|
;; for the Elixir programming language.
|
|
|
|
;;; Code:
|
|
|
|
(require 'comint) ; for interactive REPL
|
|
(require 'easymenu) ; for menubar features
|
|
|
|
(require 'elixir-smie) ; syntax and indentation support
|
|
(require 'elixir-deprecated) ; deprecated messages
|
|
|
|
(defgroup elixir-mode nil
|
|
"Provides font-locking, indentation and navigation support
|
|
for the Elixir programming language."
|
|
:prefix "elixir-mode-"
|
|
:group 'applications
|
|
:link '(url-link :tag "Github" "https://github.com/elixir-lang/emacs-elixir")
|
|
:link '(emacs-commentary-link :tag "Commentary" "elixir-mode"))
|
|
|
|
(defvar elixir-mqode--website-url
|
|
"http://elixir-lang.org")
|
|
|
|
(defvar elixir-mode-hook nil)
|
|
|
|
(defvar elixir-mode-map
|
|
(let ((map (make-sparse-keymap)))
|
|
(define-key map (kbd "C-c ,r") 'elixir-mode-eval-on-region)
|
|
(define-key map (kbd "C-c ,c") 'elixir-mode-eval-on-current-line)
|
|
(define-key map (kbd "C-c ,b") 'elixir-mode-eval-on-current-buffer)
|
|
(define-key map (kbd "C-c ,a") 'elixir-mode-string-to-quoted-on-region)
|
|
(define-key map (kbd "C-c ,l") 'elixir-mode-string-to-quoted-on-current-line)
|
|
map)
|
|
"Keymap used in `elixir-mode'.")
|
|
|
|
(defvar elixir-imenu-generic-expression
|
|
'(("Modules" "^\\s-*defmodule[ \n\t]+\\([A-Z][A-Za-z0-9._]+\\)\\s-+do.*$" 1)
|
|
("Public Functions" "^\\s-*def[ \n\t]+\\([a-z0-9_]+\\)\\(([^)]*)\\)*[ \t\n]+do.*" 1)
|
|
("Private Functions" "^\\s-*defp[ \n\t]+\\([a-z0-9_]+\\)\\(([^)]*)\\)*[ \t\n]+do.*" 1)
|
|
("Public Macros" "^\\s-*defmacro[ \n\t]+\\([a-z0-9_]+\\)\\(([^)]*)\\)*[ \t\n]+do.*" 1)
|
|
("Private Macros" "^\\s-*defmacrop[ \n\t]+\\([a-z0-9_]+\\)\\(([^)]*)\\)*[ \t\n]+do.*" 1)
|
|
("Delegates" "^\\s-*defdelegate[ \n\t]+\\([a-z0-9_]+\\)\\(([^)]*)\\)*[ \t\n]+do.*" 1)
|
|
("Overridables" "^\\s-*defoverridable[ \n\t]+\\([a-z0-9_]+\\)\\(([^)]*)\\)*[ \t\n]+do.*" 1)
|
|
("Tests" "^\\s-*test[ \t\n]+\"?\\(:?[a-z0-9_@+() \t-]+\\)\"?[ \t\n]+do.*" 1))
|
|
"Imenu pattern for `elixir-mode'.")
|
|
|
|
(defgroup elixir nil
|
|
"Elixir major mode."
|
|
:group 'languages)
|
|
|
|
(defcustom elixir-compiler-command "elixirc"
|
|
"Elixir mode command to compile code. Must be in your path."
|
|
:type 'string
|
|
:group 'elixir)
|
|
|
|
(defcustom elixir-mode-command "elixir"
|
|
"The command for elixir."
|
|
:type 'string
|
|
:group 'elixir)
|
|
|
|
(defcustom elixir-iex-command "iex"
|
|
"Elixir mode command for interactive REPL. Must be in your path."
|
|
:type 'string
|
|
:group 'elixir)
|
|
|
|
(defcustom elixir-mode-cygwin-paths t
|
|
"Elixir mode use Cygwin style paths on Windows operating systems."
|
|
:type 'boolean
|
|
:group 'elixir)
|
|
|
|
(defcustom elixir-mode-cygwin-prefix "/cygdrive/C"
|
|
"Elixir mode Cygwin prefix."
|
|
:type 'string
|
|
:group 'elixir)
|
|
|
|
(defvar elixir-mode--eval-filename "elixir-mode-tmp-eval-file.exs")
|
|
|
|
(defvar elixir-quoted--buffer-name "*elixir-quoted*")
|
|
|
|
(defvar elixir-basic-offset 2)
|
|
(defvar elixir-key-label-offset 0)
|
|
(defvar elixir-match-label-offset 2)
|
|
|
|
(defvar elixir-operator-face 'elixir-operator-face)
|
|
(defface elixir-operator-face
|
|
'((((class color) (min-colors 88) (background light))
|
|
:foreground "darkred")
|
|
(((class color) (background dark))
|
|
(:foreground "lemonchiffon1"))
|
|
(t nil))
|
|
"For use with operators."
|
|
:group 'font-lock-faces)
|
|
|
|
(defvar elixir-negation-face 'elixir-negation-face)
|
|
(defface elixir-negation-face
|
|
'((((class color) (min-colors 88) (background light))
|
|
:foreground "#ff4500")
|
|
(((class color) (background dark))
|
|
(:foreground "#ff4500"))
|
|
(t nil))
|
|
"For use with standalone \"?\" to indicate code point."
|
|
:group 'font-lock-faces)
|
|
|
|
(defvar elixir-attribute-face 'elixir-attribute-face)
|
|
(defface elixir-attribute-face
|
|
'((((class color) (min-colors 88) (background light))
|
|
:foreground "MediumPurple4")
|
|
(((class color) (background dark))
|
|
(:foreground "thistle"))
|
|
(t nil))
|
|
"For use with module attribute tokens."
|
|
:group 'font-lock-faces)
|
|
|
|
(defvar elixir-atom-face 'elixir-atom-face)
|
|
(defface elixir-atom-face
|
|
'((((class color) (min-colors 88) (background light))
|
|
:foreground "RoyalBlue4")
|
|
(((class color) (background dark))
|
|
(:foreground "light sky blue"))
|
|
(t nil))
|
|
"For use with atoms & map keys."
|
|
:group 'font-lock-faces)
|
|
|
|
(defun elixir-syntax-propertize-interpolation ()
|
|
(let* ((beg (match-beginning 0))
|
|
(context (save-excursion (save-match-data (syntax-ppss beg)))))
|
|
(put-text-property beg (1+ beg) 'elixir-interpolation
|
|
(cons (nth 3 context) (match-data)))))
|
|
|
|
(defun elixir-syntax-propertize-function (start end)
|
|
(let ((case-fold-search nil))
|
|
(goto-char start)
|
|
(remove-text-properties start end '(elixir-interpolation))
|
|
(funcall
|
|
(syntax-propertize-rules
|
|
((rx (group "#{" (0+ (not (any "}"))) "}"))
|
|
(0 (ignore (elixir-syntax-propertize-interpolation)))))
|
|
start end)))
|
|
|
|
(defun elixir-match-interpolation (limit)
|
|
(let ((pos (next-single-char-property-change (point) 'elixir-interpolation
|
|
nil limit)))
|
|
(when (and pos (> pos (point)))
|
|
(goto-char pos)
|
|
(let ((value (get-text-property pos 'elixir-interpolation)))
|
|
(if (eq (car value) ?\")
|
|
(progn
|
|
(set-match-data (cdr value))
|
|
t)
|
|
(elixir-match-interpolation limit))))))
|
|
|
|
(eval-when-compile
|
|
(defconst elixir-rx-constituents
|
|
`(
|
|
(atoms . ,(rx ":"
|
|
(or
|
|
(one-or-more (any "a-z" "A-Z" "_" "\"" "'"))
|
|
(and "\"" (one-or-more (not (any "\""))) "\"")
|
|
(and "'" (one-or-more (not (any "'"))) "'"))))
|
|
(builtin . ,(rx symbol-start
|
|
(or "case" "cond" "for" "if" "unless" "try" "receive"
|
|
"raise" "quote" "unquote" "unquote_splicing" "throw"
|
|
"super")
|
|
symbol-end))
|
|
(builtin-declaration . ,(rx symbol-start
|
|
(or "def" "defp" "defmodule" "defprotocol"
|
|
"defmacro" "defmacrop" "defdelegate"
|
|
"defexception" "defstruct" "defimpl"
|
|
"defcallback")
|
|
symbol-end))
|
|
(builtin-modules . ,(rx symbol-start
|
|
(or "Agent" "Application" "Atom" "Base"
|
|
"Behaviour" "Bitwise" "Builtin" "Code" "Dict"
|
|
"EEx" "Elixir" "Enum" "ExUnit" "Exception"
|
|
"File" "File.Stat" "File.Stream" "Float"
|
|
"Function" "GenEvent" "GenServer" "GenTCP"
|
|
"HashDict" "HashSet" "IO" "IO.ANSI"
|
|
"IO.Stream" "Inspect.Algebra" "Inspect.Opts"
|
|
"Integer" "Kernel" "Kernel.ParallelCompiler"
|
|
"Kernel.ParallelRequire" "Kernel.SpecialForms"
|
|
"Kernel.Typespec" "Keyword" "List" "Macro"
|
|
"Macro.Env" "Map" "Math" "Module" "Node"
|
|
"OptionParser" "OrdDict" "Path" "Port"
|
|
"Process" "Protocol" "Range" "Record" "Regex"
|
|
"Set" "Stream" "String" "StringIO"
|
|
"Supervisor" "Supervisor.Spec" "System" "Task"
|
|
"Task.Supervisor" "Tuple" "URI"
|
|
"UnboundMethod" "Version")
|
|
symbol-end))
|
|
(builtin-namespace . ,(rx symbol-start
|
|
(or "import" "require" "use" "alias")
|
|
symbol-end))
|
|
;; Set aside code point syntax for `elixir-negation-face'.
|
|
(code-point . ,(rx symbol-start
|
|
"?"
|
|
anything
|
|
symbol-end))
|
|
(function-declaration . ,(rx symbol-start
|
|
(or "def" "defp")
|
|
symbol-end))
|
|
;; Match `@doc' or `@moduledoc' syntax, with or without triple quotes.
|
|
(heredocs . ,(rx symbol-start
|
|
(or "@doc" "@moduledoc" "~s")
|
|
symbol-end))
|
|
;; The first character of an identifier must be a letter or an underscore.
|
|
;; After that, they may contain any alphanumeric character + underscore.
|
|
;; Additionally, the final character may be either `?' or `!'.
|
|
(identifiers . ,(rx (one-or-more (any "A-Z" "a-z" "_"))
|
|
(zero-or-more (any "A-Z" "a-z" "0-9" "_"))
|
|
(optional (or "?" "!"))))
|
|
(keyword . ,(rx symbol-start
|
|
(or "fn" "do" "end" "after" "else" "rescue" "catch")
|
|
symbol-end))
|
|
(keyword-operator . ,(rx symbol-start
|
|
(or "not" "and" "or" "when" "in")
|
|
symbol-end))
|
|
;; Module and submodule names start with upper case letter. This
|
|
;; can then be followed by any combination of alphanumeric chars.
|
|
;; In turn, this can be followed by a `.' which begins the notation of
|
|
;; a submodule, which follows the same naming pattern of the module.
|
|
;; Finally, like other identifiers, it can be terminated with either `?'
|
|
;; or `!'.
|
|
(module-names . ,(rx symbol-start
|
|
(one-or-more (any "A-Z"))
|
|
(zero-or-more (any "A-Z" "a-z" "_" "0-9"))
|
|
(zero-or-more
|
|
(and "."
|
|
(one-or-more (any "A-Z" "_"))
|
|
(zero-or-more (any "A-Z" "a-z" "_" "0-9"))))
|
|
(optional (or "!" "?"))
|
|
symbol-end))
|
|
(operators1 . ,(rx symbol-start
|
|
(or "<" ">" "+" "-" "*" "/" "!" "^" "&")
|
|
symbol-end))
|
|
(operators2 . ,(rx symbol-start
|
|
(or
|
|
"==" "!=" "<=" ">=" "&&" "||" "<>" "++" "--" "|>" "=~"
|
|
"->" "<-" "|" "." "=")
|
|
symbol-end))
|
|
(operators3 . ,(rx symbol-start
|
|
(or "<<<" ">>>" "|||" "&&&" "^^^" "~~~" "===" "!==")
|
|
symbol-end))
|
|
(pseudo-var . ,(rx symbol-start
|
|
(or "_" "__MODULE__" "__DIR__" "__ENV__" "__CALLER__"
|
|
"__block__" "__aliases__")
|
|
symbol-end))
|
|
(punctuation . ,(rx symbol-start
|
|
(or "\\" "<<" ">>" "=>" "(" ")" ":" ";" "" "[" "]")
|
|
symbol-end))
|
|
(sigils . ,(rx "~" (or "B" "C" "R" "S" "b" "c" "r" "s" "w")))))
|
|
|
|
(defmacro elixir-rx (&rest sexps)
|
|
(let ((rx-constituents (append elixir-rx-constituents rx-constituents)))
|
|
(cond ((null sexps)
|
|
(error "No regexp"))
|
|
((cdr sexps)
|
|
(rx-to-string `(and ,@sexps) t))
|
|
(t
|
|
(rx-to-string (car sexps) t))))))
|
|
|
|
(defconst elixir-font-lock-keywords
|
|
`(
|
|
;; String interpolation
|
|
(elixir-match-interpolation 0 font-lock-variable-name-face t)
|
|
|
|
;; Module-defining & namespace builtins
|
|
(,(elixir-rx (or builtin-declaration builtin-namespace)
|
|
space
|
|
(group module-names))
|
|
1 font-lock-type-face)
|
|
|
|
;; Module attributes
|
|
(,(elixir-rx (group (or heredocs
|
|
(and "@" (1+ identifiers)))))
|
|
1 elixir-attribute-face)
|
|
|
|
;; Keywords
|
|
(,(elixir-rx (group (or builtin builtin-declaration builtin-namespace
|
|
keyword keyword-operator)))
|
|
1 font-lock-keyword-face)
|
|
|
|
;; Function names, i.e. `def foo do'.
|
|
(,(elixir-rx (group function-declaration)
|
|
space
|
|
(group identifiers))
|
|
2 font-lock-function-name-face)
|
|
|
|
;; Variable definitions
|
|
(,(elixir-rx (group identifiers)
|
|
(one-or-more space)
|
|
"="
|
|
(or (one-or-more space)
|
|
(one-or-more "\n")))
|
|
1 font-lock-variable-name-face)
|
|
|
|
;; Sigils
|
|
(,(elixir-rx (group sigils))
|
|
1 font-lock-builtin-face)
|
|
|
|
;; Regex patterns. Elixir has support for eight different regex delimiters.
|
|
;; This isn't a very DRY approach here but it gets the job done.
|
|
(,(elixir-rx "~r"
|
|
(and "/" (group (one-or-more (not (any "/")))) "/"))
|
|
1 font-lock-string-face)
|
|
(,(elixir-rx "~r"
|
|
(and "[" (group (one-or-more (not (any "]")))) "]"))
|
|
1 font-lock-string-face)
|
|
(,(elixir-rx "~r"
|
|
(and "{" (group (one-or-more (not (any "}")))) "}"))
|
|
1 font-lock-string-face)
|
|
(,(elixir-rx "~r"
|
|
(and "(" (group (one-or-more (not (any ")")))) ")"))
|
|
1 font-lock-string-face)
|
|
(,(elixir-rx "~r"
|
|
(and "|" (group (one-or-more (not (any "|")))) "|"))
|
|
1 font-lock-string-face)
|
|
(,(elixir-rx "~r"
|
|
(and "\"" (group (one-or-more (not (any "\"")))) "\""))
|
|
1 font-lock-string-face)
|
|
(,(elixir-rx "~r"
|
|
(and "'" (group (one-or-more (not (any "'")))) "'"))
|
|
1 font-lock-string-face)
|
|
(,(elixir-rx "~r"
|
|
(and "<" (group (one-or-more (not (any ">")))) ">"))
|
|
1 font-lock-string-face)
|
|
|
|
;; Atoms and singleton-like words like true/false/nil.
|
|
(,(elixir-rx (group atoms))
|
|
1 elixir-atom-face)
|
|
|
|
;; Map keys
|
|
(,(elixir-rx (group (and (one-or-more identifiers) ":")))
|
|
1 elixir-atom-face)
|
|
|
|
;; Built-in modules and pseudovariables
|
|
(,(elixir-rx (group (or builtin-modules pseudo-var)))
|
|
1 font-lock-constant-face)
|
|
|
|
;; Code points
|
|
(,(elixir-rx (group code-point))
|
|
1 elixir-negation-face)))
|
|
|
|
(defun elixir-mode-cygwin-path (expanded-file-name)
|
|
"Elixir mode get Cygwin absolute path name.
|
|
Argument EXPANDED-FILE-NAME ."
|
|
(replace-regexp-in-string "^[a-zA-Z]:" elixir-mode-cygwin-prefix expanded-file-name t))
|
|
|
|
(defun elixir-mode-universal-path (file-name)
|
|
"Elixir mode multi-OS path handler.
|
|
Argument FILE-NAME ."
|
|
(let ((full-file-name (expand-file-name file-name)))
|
|
(if (and (equal system-type 'windows-nt)
|
|
elixir-mode-cygwin-paths)
|
|
(elixir-mode-cygwin-path full-file-name)
|
|
full-file-name)))
|
|
|
|
(defun elixir-mode-command-compile (file-name)
|
|
"Elixir mode command to compile a file.
|
|
Argument FILE-NAME ."
|
|
(let ((full-file-name (elixir-mode-universal-path file-name)))
|
|
(mapconcat 'identity (append (list elixir-compiler-command) (list full-file-name)) " ")))
|
|
|
|
(defun elixir-mode-compiled-file-name (&optional filename)
|
|
"Elixir mode compiled FILENAME."
|
|
(concat (file-name-sans-extension (or filename (buffer-file-name))) ".beam"))
|
|
|
|
(defun elixir-mode-compile-file ()
|
|
"Elixir mode compile and save current file."
|
|
(interactive)
|
|
(elixir-deprecated-use-alchemist "elixir-mode-compile-file")
|
|
(let ((compiler-output (shell-command-to-string (elixir-mode-command-compile (buffer-file-name)))))
|
|
(when (string= compiler-output "")
|
|
(message "Compiled and saved as %s" (elixir-mode-compiled-file-name)))))
|
|
|
|
(defun elixir-quoted--initialize-buffer (quoted)
|
|
(pop-to-buffer elixir-quoted--buffer-name)
|
|
(setq buffer-undo-list nil) ; Get rid of undo information from
|
|
; previous expansions
|
|
(let ((inhibit-read-only t)
|
|
(buffer-undo-list t)) ; Ignore undo information
|
|
(erase-buffer)
|
|
(insert quoted)
|
|
(goto-char (point-min))
|
|
(elixir-mode)
|
|
(elixir-quoted-minor-mode 1)))
|
|
|
|
;;;###autoload
|
|
(defun elixir-mode-iex (&optional args-p)
|
|
"Elixir mode interactive REPL.
|
|
Optional argument ARGS-P ."
|
|
(interactive "P")
|
|
(let ((switches (if (equal args-p nil)
|
|
'()
|
|
(split-string (read-string "Additional args: ")))))
|
|
(unless (comint-check-proc "*IEX*")
|
|
(set-buffer
|
|
(apply 'make-comint "IEX"
|
|
elixir-iex-command nil switches))))
|
|
(pop-to-buffer "*IEX*")
|
|
(elixir-deprecated-use-alchemist "elixir-mode-iex"))
|
|
|
|
;;;###autoload
|
|
(defun elixir-mode-open-modegithub ()
|
|
"Elixir mode open GitHub page."
|
|
(interactive)
|
|
(browse-url "https://github.com/elixir-lang/emacs-elixir"))
|
|
|
|
;;;###autoload
|
|
(defun elixir-mode-open-elixir-home ()
|
|
"Elixir mode go to language home."
|
|
(interactive)
|
|
(browse-url elixir-mode--website-url))
|
|
|
|
;;;###autoload
|
|
(defun elixir-mode-open-docs-master ()
|
|
"Elixir mode go to master documentation."
|
|
(interactive)
|
|
(browse-url (concat elixir-mode--website-url "/docs/master/elixir")))
|
|
|
|
;;;###autoload
|
|
(defun elixir-mode-open-docs-stable ()
|
|
"Elixir mode go to stable documentation."
|
|
(interactive)
|
|
(browse-url (concat elixir-mode--website-url "/docs/stable/elixir")))
|
|
|
|
;;;###autoload
|
|
(defun elixir-mode-version (&optional show-version)
|
|
"Get the Elixir-Mode version as string.
|
|
|
|
If called interactively or if SHOW-VERSION is non-nil, show the
|
|
version in the echo area and the messages buffer.
|
|
|
|
The returned string includes both, the version from package.el
|
|
and the library version, if both a present and different.
|
|
|
|
If the version number could not be determined, signal an error,
|
|
if called interactively, or if SHOW-VERSION is non-nil, otherwise
|
|
just return nil."
|
|
(interactive (list t))
|
|
(let ((version (pkg-info-version-info 'elixir-mode)))
|
|
(when show-version
|
|
(message "Elixir-Mode version: %s" version))
|
|
version))
|
|
|
|
(defun elixir-mode--code-eval-string-command (file)
|
|
(format "%s -e 'IO.puts inspect(elem(Code.eval_string(File.read!(\"%s\")), 0))'"
|
|
elixir-mode-command
|
|
file))
|
|
|
|
(defun elixir-mode--code-string-to-quoted-command (file)
|
|
(format "%s -e 'IO.puts inspect(elem(Code.string_to_quoted(File.read!(\"%s\")), 1), pretty: true)'"
|
|
elixir-mode-command
|
|
file))
|
|
|
|
(defun elixir-mode--execute-elixir-with-code-eval-string (string)
|
|
(with-temp-file elixir-mode--eval-filename
|
|
(insert string))
|
|
(let ((output (shell-command-to-string (elixir-mode--code-eval-string-command elixir-mode--eval-filename))))
|
|
(delete-file elixir-mode--eval-filename)
|
|
output))
|
|
|
|
(defun elixir-mode--execute-elixir-with-code-string-to-quoted (string)
|
|
(with-temp-file elixir-mode--eval-filename
|
|
(insert string))
|
|
(let ((output (shell-command-to-string (elixir-mode--code-string-to-quoted-command elixir-mode--eval-filename))))
|
|
(delete-file elixir-mode--eval-filename)
|
|
output))
|
|
|
|
(defun elixir-mode--eval-string (string)
|
|
(let ((output (elixir-mode--execute-elixir-with-code-eval-string string)))
|
|
(message output)))
|
|
|
|
(defun elixir-mode--string-to-quoted (string)
|
|
(let* ((output (elixir-mode--execute-elixir-with-code-string-to-quoted string)))
|
|
(elixir-quoted--initialize-buffer output)))
|
|
|
|
(defun elixir-mode-eval-on-region (beg end)
|
|
"Evaluate the Elixir code on the marked region.
|
|
Argument BEG Start of the region.
|
|
Argument END End of the region."
|
|
(interactive (list (point) (mark)))
|
|
(elixir-deprecated-use-alchemist "elixir-mode-eval-on-region")
|
|
(unless (and beg end)
|
|
(error "The mark is not set now, so there is no region"))
|
|
(let* ((region (buffer-substring-no-properties beg end)))
|
|
(elixir-mode--eval-string region)))
|
|
|
|
(defun elixir-mode-eval-on-current-line ()
|
|
"Evaluate the Elixir code on the current line."
|
|
(interactive)
|
|
(elixir-deprecated-use-alchemist "elixir-mode-eval-on-current-line")
|
|
(let ((current-line (thing-at-point 'line)))
|
|
(elixir-mode--eval-string current-line)))
|
|
|
|
(defun elixir-mode-eval-on-current-buffer ()
|
|
"Evaluate the Elixir code on the current buffer."
|
|
(interactive)
|
|
(elixir-deprecated-use-alchemist "elixir-mode-eval-on-current-buffer")
|
|
(let ((current-buffer (buffer-substring-no-properties (point-max) (point-min))))
|
|
(elixir-mode--eval-string current-buffer)))
|
|
|
|
(defun elixir-mode-string-to-quoted-on-region (beg end)
|
|
"Get the representation of the expression on the marked region.
|
|
Argument BEG Start of the region.
|
|
Argument END End of the region."
|
|
(interactive (list (point) (mark)))
|
|
(elixir-deprecated-use-alchemist "elixir-mode-string-to-quoted-on-region")
|
|
(unless (and beg end)
|
|
(error "The mark is not set now, so there is no region"))
|
|
(let ((region (buffer-substring-no-properties beg end)))
|
|
(elixir-mode--string-to-quoted region)))
|
|
|
|
(defun elixir-mode-string-to-quoted-on-current-line ()
|
|
"Get the representation of the expression on the current line."
|
|
(interactive)
|
|
(elixir-deprecated-use-alchemist "elixir-mode-string-to-quoted-on-current-line")
|
|
(let ((current-line (thing-at-point 'line)))
|
|
(elixir-mode--string-to-quoted current-line)))
|
|
|
|
(easy-menu-define elixir-mode-menu elixir-mode-map
|
|
"Elixir mode menu."
|
|
'("Elixir"
|
|
["Indent line" smie-indent-line]
|
|
["Compile file" elixir-mode-compile-file]
|
|
["IEX" elixir-mode-iex]
|
|
"---"
|
|
["elixir-mode on GitHub" elixir-mode-open-modegithub]
|
|
["Elixir homepage" elixir-mode-open-elixirhome]
|
|
["About" elixir-mode-version]
|
|
))
|
|
|
|
;;;###autoload
|
|
(define-derived-mode elixir-mode prog-mode "Elixir"
|
|
"Major mode for editing Elixir code.
|
|
|
|
\\{elixir-mode-map}"
|
|
(set (make-local-variable 'font-lock-defaults)
|
|
'(elixir-font-lock-keywords))
|
|
(set (make-local-variable 'comment-start) "# ")
|
|
(set (make-local-variable 'comment-end) "")
|
|
(set (make-local-variable 'comment-start-skip) "#+ *")
|
|
(set (make-local-variable 'comment-use-syntax) t)
|
|
(set (make-local-variable 'tab-width) elixir-basic-offset)
|
|
(set (make-local-variable 'syntax-propertize-function)
|
|
#'elixir-syntax-propertize-function)
|
|
(set (make-local-variable 'imenu-generic-expression)
|
|
elixir-imenu-generic-expression)
|
|
(smie-setup elixir-smie-grammar 'verbose-elixir-smie-rules
|
|
:forward-token 'elixir-smie-forward-token
|
|
:backward-token 'elixir-smie-backward-token))
|
|
|
|
(define-minor-mode elixir-cos-mode
|
|
"Elixir mode toggle compile on save."
|
|
:group 'elixir-cos :lighter " CoS"
|
|
(cond
|
|
(elixir-cos-mode
|
|
(add-hook 'after-save-hook 'elixir-mode-compile-file nil t))
|
|
(t
|
|
(remove-hook 'after-save-hook 'elixir-mode-compile-file t))))
|
|
|
|
(define-minor-mode elixir-quoted-minor-mode
|
|
"Minor mode for displaying elixir quoted expressions"
|
|
:group 'elixir-quoted :lighter " quoted"
|
|
:keymap '(("q" . quit-window))
|
|
(setq buffer-read-only t))
|
|
|
|
;; Invoke elixir-mode when appropriate
|
|
|
|
;;;###autoload
|
|
(progn
|
|
(add-to-list 'auto-mode-alist '("\\.elixir\\'" . elixir-mode))
|
|
(add-to-list 'auto-mode-alist '("\\.ex\\'" . elixir-mode))
|
|
(add-to-list 'auto-mode-alist '("\\.exs\\'" . elixir-mode)))
|
|
|
|
(provide 'elixir-mode)
|
|
|
|
;;; elixir-mode.el ends here
|