Skip to content

Commit

Permalink
Several new features.
Browse files Browse the repository at this point in the history
* 1.0.0 release
* Menu
* Customization
* Documentation
  • Loading branch information
Second Planet committed Nov 12, 2011
1 parent f2794e1 commit dcfed58
Show file tree
Hide file tree
Showing 4 changed files with 362 additions and 23 deletions.
7 changes: 0 additions & 7 deletions LICENCE

This file was deleted.

127 changes: 125 additions & 2 deletions README.markdown
@@ -1,6 +1,129 @@
# elixir-mode -- Emacs major mode for [Elixir](https://github.com/josevalim/elixir) ![still maintained](http://stillmaintained.com/secondplanet/elixir-mode.png)

![elixir-mode]("https://img.skitch.com/20111112-tyhx1d5wqus29rx644f46ciu5c.png")

## Installation

Simply add to your load path and require the mode to install.

(add-to-list 'load-path "~/.emacs.d/path/to/elixir-mode")
(require 'elixir-mode)
In your shell...

```shell
% git clone git://github.com/secondplanet/elixir-mode ~/.emacs.d/elixir-mode
% $EDITOR ~/.emacs
```
In the editor...

```lisp
(add-to-list 'load-path "~/.emacs.d/elixir-mode")
(require 'elixir-mode)
```

Save and reload with `M-x load-file` `~/.emacs`.

## Usage

Any file that matches the glob `*.ex[s]` is automatically opened in
Elixir mode, but you can change this functionality easily.

```lisp
;; Highlights *.elixir as well
(add-to-list 'auto-mode-alist '("\\.elixir\\'" . elixir-mode))
```

### Commands

(For the `M-x` prompt.)

#### elixir-mode

Switches to elixir-mode.

#### elixir-cos-mode

Applies compile-on-save minor mode.

#### elixir-mode-iex

Launch `IEX` inside Emacs.

#### elixir-mode-opengithub

Open the GitHub page for Elixir.

#### elixir-mode-compile-file

Compile Elixir files. Works fine on `exs` files, too, if needed.

#### elixir-mode-open-elixir-home

Go to Elixir README in the browser.

#### elixir-mode-show-version

Print version info for elixir-mode.

#### elixir-mode-indent-line

Indent the current line. (Buggy right now.)

### Hooks

Hooks can be used to add functionality to elixir-mode. This example
adds compile on save.

```lisp
(defun elixir-mode-compile-on-save ()
"Elixir mode compile files on save."
(and (file-exists (buffer-file-name))
(file-exists (elixir-mode-compiled-file-name))
(elixir-cos-mode t)))
(add-hook 'elixir-mode-hook 'elixir-mode-compile-on-save)
```

### Configuration

Custom variables for elixir-mode.

#### elixir-compiler-command (string)
##### Default: `"elixirc"`

Command to compile Elixir code.

#### elixir-iex-command (string)
##### Default: `"iex"`

Command to start an interactive REPL in `IEX`.

#### elixir-mode-highlight-operators (boolean)
##### Default: `t`

Should operators be colored? (Currently not working properly.)

#### elixir-mode-cygwin-paths (boolean)
##### Default: `t`

Should Cygwin paths be used on Windows?

#### elixir-mode-cygwin-prefix (string)
##### Default: `"/cygdrive/C"

The prefix for Cygwin-style paths.

### Keymapping

Keymaps can be added to the `elixir-mode-map` variable.
There are no keyboard shortcuts included by default.

## Bugs

This is still very alpha software; there are probably several
bugs. Right now the indentation implementation needs some work, and
the operator and atom font-locking doesn't appear to be working
correctly.

## Notes

This is my first Emacs mode, so please excuse some of the messy bits
in the implementation. To help me out I had a look at and borrowed a
bit of code from io-mode, ruby-mode, and coffee-mode.
201 changes: 187 additions & 14 deletions elixir-mode.el
Expand Up @@ -5,31 +5,78 @@
;; URL: https://github.com/secondplanet/elixir-mode
;; Created: Mon Nov 7 2011
;; Keywords: languages elixir
;; Version: 0.1.1
;; Version: 1.0.0

;; This file is not a part of GNU Emacs.
;; It is distributed under the MIT license.
;; See https://github.com/secondplanet/elixir-mode/tree/master/LICENSE

;; 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 support, and navigation for Elixir programs.

;;; Code:

(defconst elixir-mode-version "0.1.1"
(require 'comint) ; for interactive REPL
(require 'easymenu) ; for menubar features

(defconst elixir-mode-version "1.0.0"
"Elixir mode version number.")
(defconst elixir-mode-date "2011-11-08"
(defconst elixir-mode-date "2011-11-12"
"Elixir mode version date.")

(defvar elixir-mode-hook nil)
(defvar elixir-mode-map (make-keymap)
"Elixir mode keymap.")

(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-iex-command "iex"
"Elixir mode command for interactive REPL. Must be in your path."
:type 'string
:group 'elixir)

(defcustom elixir-mode-highlight-operators t
"Elixir mode option for whether or not to highlight operators."
:type 'boolean
: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-keyword-names '(
"->"
"do"
"after"
"for"
"module"
"private"
"def"
"if"
"when"
Expand Down Expand Up @@ -80,16 +127,66 @@
(defvar elixir-mode-builtin-names '(
"Erlang")
"Elixir mode builtins.")
(defvar elixir-mode-operator-names '(
"+"
"-"
"/"
"*"
"div"
"rem"
"=="
"!="
"<="
"<"
">="
">"
"==="
"!=="
"and"
"or"
"andalso"
"orelse"
"not"
"&&"
"||"
"!"
"."
"#"
"="
":="
"<-")
"Elixir mode operators.")

(defvar font-lock-operator-face 'font-lock-operator-face)
(defface font-lock-operator-face
'((((type tty) (class color)) nil)
(((class color) (background light))
(:foreground "darkred"))
(t nil))
"For use with operators."
:group 'font-lock-faces)

(defvar font-lock-atom-face 'font-lock-atom-face)
(defface font-lock-operator-face
'((((type tty) (class color)) nil)
(((class color) (background light))
(:foreground "magenta"))
(t nil))
"For use with atoms."
:group 'font-lock-faces)

(defconst elixir-mode-font-lock-defaults
(list
'("%.*$" . font-lock-comment-face)
'("^\\s *def\\s +\\([^( \t\n]+\\)" . font-lock-function-name-face)
`(,(concat "\\<" (regexp-opt elixir-mode-keyword-names t) "\\>") . font-lock-keyword-face)
`(,(concat "\\<" (regexp-opt elixir-mode-builtin-names t) "\\>") . font-lock-builtin-face)
`(,(concat "\\<" (regexp-opt elixir-mode-module-names t) "\\>") . font-lock-type-face)
'("\\(\\w*\\)\\s-*:?=" . font-lock-variable-name-face)
'("\\<\\(true\\|false\\|nil\\)\\>" . font-lock-constant-face))
'("%.*$" . font-lock-comment-face) ; comments
'("^\\s *def\\s +\\([^( \t\n]+\\)" . font-lock-function-name-face) ; methods
`(,(concat "\\<" (regexp-opt elixir-mode-keyword-names t) "\\>") . font-lock-keyword-face) ; keywords
`(,(concat "\\<" (regexp-opt elixir-mode-builtin-names t) "\\>") . font-lock-builtin-face) ; builtins
`(,(concat "\\<" (regexp-opt elixir-mode-module-names t) "\\>") . font-lock-type-face) ; core modules
(when elixir-mode-highlight-operators `(,(concat "\\<" (regexp-opt elixir-mode-operator-names t) "\\>") . font-lock-operator-face)) ; operators
'("\\(\\w*\\)\\s-*:?=" . font-lock-variable-name-face) ; variables
'("-[Rr].*[ \n\t]" . font-lock-constant-face) ; regexes
'("\\<\\(true\\|false\\|nil\\)\\>" . font-lock-atom-face) ; atoms, boolean
'("'\\w*" . font-lock-atom-face)) ; atoms, generic
"Highlighting for Elixir mode.")

(defun elixir-mode-indent-line ()
Expand Down Expand Up @@ -123,6 +220,58 @@
(indent-line-to cur-indent)
(indent-line-to 0)))))

(defun elixir-mode-cygwin-path (expanded-file-name)
"Elixir mode get Cygwin absolute path 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."
(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."
(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)
(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-mode-iex ()
"Elixir mode interactive REPL."
(interactive)
(unless (comint-check-proc "*IEX*")
(set-buffer
(apply 'make-comint "IEX"
elixir-iex-command nil '())))
(pop-to-buffer "*IEX*"))

(defun elixir-mode-open-modegithub ()
"Elixir mode open GitHub page."
(interactive)
(browse-url "https://github.com/secondplanet/elixir-mode"))

(defun elixir-mode-open-elixir-home ()
"Elixir mode go to language home."
(interactive)
(browse-url "https://github.com/josevalim/elixir#README"))

(defun elixir-mode-show-version ()
"Elixir mode print version."
(interactive)
(message (concat "elixir-mode v" elixir-mode-version " " elixir-mode-date " by Humza Yaqoob")))

(defvar elixir-mode-syntax-table
(let ((elixir-mode-syntax-table (make-syntax-table)))
(modify-syntax-entry ?_ "w" elixir-mode-syntax-table)
Expand All @@ -137,6 +286,18 @@
elixir-mode-syntax-table)
"Elixir mode syntax table.")

(easy-menu-define elixir-mode-menu elixir-mode-map
"Elixir mode menu."
'("Elixir"
["Indent line" elixir-mode-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-show-version]
))

(defun elixir-mode ()
"Major mode for editing Elixir files."
(interactive)
Expand All @@ -148,7 +309,19 @@
(setq mode-name "Elixir")
(run-hooks 'elixir-mode-hook))

(add-to-list 'auto-mode-alist '("\\.ex\\'" . elixir-mode))
(add-to-list 'auto-mode-alist '("\\.exs\\'" . elixir-mode))
(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))))

(provide 'elixir-mode)

;; automatically opening ex and exs in elixir-mode
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.ex\\'" . elixir-mode))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.exs\\'" . elixir-mode))

0 comments on commit dcfed58

Please sign in to comment.