Skip to content

Commit 0c31b83

Browse files
anildigitalckrusedragonwasrobot
committed
$Add elixir-format function to format Elixir 1.6 files.
Co-Authored-By: Christian Kruse <[email protected]> Co-Authored-By: Peter Urbak <[email protected]>
1 parent e9deded commit 0c31b83

File tree

5 files changed

+261
-166
lines changed

5 files changed

+261
-166
lines changed

README.md

Lines changed: 1 addition & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -1,166 +1 @@
1-
[![License GPL 3][badge-license]](http://www.gnu.org/licenses/gpl-3.0.txt)
2-
[![Build Status](https://travis-ci.org/elixir-editors/emacs-elixir.svg?branch=master)](https://travis-ci.org/elixir-editors/emacs-elixir)
3-
[![MELPA Stable](http://stable.melpa.org/packages/elixir-mode-badge.svg)](http://stable.melpa.org/#/elixir-mode)
4-
[![MELPA](http://melpa.org/packages/elixir-mode-badge.svg)](http://melpa.org/#/elixir-mode)
5-
6-
# Elixir Mode
7-
8-
Provides font-locking, indentation and navigation support for the
9-
[Elixir programming language.](http://elixir-lang.org/)
10-
11-
- [Installation](#installation)
12-
- [Via package.el](#via-packageel)
13-
- [Via el-get](#via-el-get)
14-
- [Manual](#manual)
15-
- [Usage](#usage)
16-
- [Interactive Commands](#interactive-commands)
17-
- [Configuration](#configuration)
18-
- [Keymapping](#keymapping)
19-
- [Notes](#notes)
20-
- [Elixir Tooling Integration](#elixir-tooling-integration)
21-
- [History](#history)
22-
- [Contributing](#contributing)
23-
- [License](#license)
24-
25-
## Installation
26-
27-
### Via package.el
28-
29-
`package.el` is the built-in package manager in Emacs.
30-
31-
`elixir-mode` is available on the two major community maintained repositories -
32-
[MELPA STABLE](melpa-stable.milkbox.net) and [MELPA](http://melpa.milkbox.net).
33-
34-
You can install `elixir-mode` with the following command:
35-
36-
<kbd>M-x package-install [RET] elixir-mode [RET]</kbd>
37-
38-
or by adding this bit of Emacs Lisp code to your Emacs initialization file
39-
(`.emacs` or `init.el`):
40-
41-
```el
42-
(unless (package-installed-p 'elixir-mode)
43-
(package-install 'elixir-mode))
44-
```
45-
46-
If the installation doesn't work try refreshing the package list:
47-
48-
<kbd>M-x package-refresh-contents [RET]</kbd>
49-
50-
Keep in mind that MELPA packages are built automatically from
51-
the `master` branch, meaning bugs might creep in there from time to
52-
time. Never-the-less, installing from MELPA is the recommended way of
53-
obtaining `Elixir-Mode`, as the `master` branch is normally quite stable and
54-
"stable" (tagged) builds are released somewhat infrequently.
55-
56-
With the most recent builds of Emacs, you can pin `Elixir-Mode` to always
57-
use MELPA Stable by adding this to your Emacs initialization:
58-
59-
```el
60-
(add-to-list 'package-pinned-packages '(elixir-mode . "melpa-stable") t)
61-
```
62-
63-
### Via el-get
64-
65-
[el-get](https://github.com/dimitri/el-get) is another popular package manager for Emacs. If you're an el-get
66-
user just do <kbd>M-x el-get-install [RET] elixir-mode [RET]</kbd>.
67-
68-
### Manual
69-
70-
You can install `Elixir-Mode` manually by placing `Elixir-Mode` on your `load-path` and
71-
`require` ing it. Many people favour the folder `~/.emacs.d/vendor`.
72-
73-
```el
74-
(add-to-list 'load-path "~/.emacs.d/vendor")
75-
(require 'elixir-mode)
76-
```
77-
78-
## Usage
79-
80-
### Interactive Commands
81-
82-
<table>
83-
<tr>
84-
<th>Command (For the <code>M-x</code> prompt.)</th>
85-
<th>Description</th>
86-
</tr>
87-
<tr>
88-
<td><code>elixir-mode</code></td>
89-
<td>Switches to elixir-mode.</td>
90-
</tr>
91-
<tr>
92-
<td><code>elixir-mode-open-github</code></td>
93-
<td>Open the GitHub page for Elixir.</td>
94-
</tr>
95-
</tr>
96-
<tr>
97-
<td><code>elixir-mode-open-elixir-home</code></td>
98-
<td>Go to Elixir README in the browser.</td>
99-
</tr>
100-
<tr>
101-
<td><code>elixir-mode-open-docs-master</code></td>
102-
<td>Open the Elixir documentation for the master.</td>
103-
</tr>
104-
<tr>
105-
<td><code>elixir-mode-open-docs-stable</code></td>
106-
<td>Open the Elixir documentation for the latest stable release.</td>
107-
</tr>
108-
<tr>
109-
<td><code>elixir-mode-show-version</code></td>
110-
<td>Print version info for elixir-mode.</td>
111-
</tr>
112-
</table>
113-
114-
### Configuration
115-
116-
Any file that matches the glob `*.ex[s]` or `*.elixir` is
117-
automatically opened in elixir-mode, but you can change this
118-
functionality easily.
119-
120-
```lisp
121-
;; Highlights *.elixir2 as well
122-
(add-to-list 'auto-mode-alist '("\\.elixir2\\'" . elixir-mode))
123-
```
124-
125-
### Keymapping
126-
127-
Keymaps can be added to the `elixir-mode-map` variable.
128-
129-
### Pairing
130-
131-
[Smartparens](https://github.com/Fuco1/smartparens) has direct support for Elixir.
132-
133-
Alternatively, if you want to use `ruby-end-mode`, you can add the following to your `elixir-mode-hook`:
134-
135-
```lisp
136-
(add-to-list 'elixir-mode-hook
137-
(defun auto-activate-ruby-end-mode-for-elixir-mode ()
138-
(set (make-variable-buffer-local 'ruby-end-expand-keywords-before-re)
139-
"\\(?:^\\|\\s-+\\)\\(?:do\\)")
140-
(set (make-variable-buffer-local 'ruby-end-check-statement-modifiers) nil)
141-
(ruby-end-mode +1)))
142-
```
143-
144-
## Elixir Tooling Integration
145-
146-
If you looking for elixir tooling integration for Emacs, check: [alchemist.el](https://github.com/tonini/alchemist.el)
147-
148-
You can use [web-mode.el](http://web-mode.org) to edit elixir templates (eex files).
149-
150-
## History
151-
152-
This mode is based on the
153-
[Emacs mode by secondplanet](https://github.com/secondplanet/elixir-mode).
154-
155-
## Contributing
156-
157-
Please read [CONTRIBUTING.md](https://github.com/elixir-lang/emacs-elixir/blob/master/CONTRIBUTING.md) for guidelines on how to contribute to this project.
158-
159-
## License
160-
161-
Copyright © 2011-2017 Samuel Tonini, Matt DeBoard, Andreas Fuchs, secondplanet and
162-
[contributors](https://github.com/elixir-lang/emacs-elixir/contributors).
163-
164-
Distributed under the GNU General Public License, version 3
165-
166-
[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg
1+
[![License GPL 3][badge-license]](http://www.gnu.org/licenses/gpl-3.0.txt)[![Build Status](https://travis-ci.org/elixir-editors/emacs-elixir.svg?branch=master)](https://travis-ci.org/elixir-editors/emacs-elixir)[![MELPA Stable](http://stable.melpa.org/packages/elixir-mode-badge.svg)](http://stable.melpa.org/#/elixir-mode)[![MELPA](http://melpa.org/packages/elixir-mode-badge.svg)](http://melpa.org/#/elixir-mode)# Elixir ModeProvides font-locking, indentation and navigation support for the[Elixir programming language.](http://elixir-lang.org/)- [Installation](#installation) - [Via package.el](#via-packageel) - [Via el-get](#via-el-get) - [Manual](#manual)- [Usage](#usage) - [Interactive Commands](#interactive-commands) - [Configuration](#configuration) - [Keymapping](#keymapping)- [Notes](#notes)- [Elixir Tooling Integration](#elixir-tooling-integration)- [Elixir Format](#elixir-format)- [History](#history)- [Contributing](#contributing)- [License](#license)## Installation### Via package.el`package.el` is the built-in package manager in Emacs.`elixir-mode` is available on the two major community maintained repositories -[MELPA STABLE](melpa-stable.milkbox.net) and [MELPA](http://melpa.milkbox.net).You can install `elixir-mode` with the following command:<kbd>M-x package-install [RET] elixir-mode [RET]</kbd>or by adding this bit of Emacs Lisp code to your Emacs initialization file(`.emacs` or `init.el`):```el(unless (package-installed-p 'elixir-mode) (package-install 'elixir-mode))```If the installation doesn't work try refreshing the package list:<kbd>M-x package-refresh-contents [RET]</kbd>Keep in mind that MELPA packages are built automatically fromthe `master` branch, meaning bugs might creep in there from time totime. Never-the-less, installing from MELPA is the recommended way ofobtaining `Elixir-Mode`, as the `master` branch is normally quite stable and"stable" (tagged) builds are released somewhat infrequently.With the most recent builds of Emacs, you can pin `Elixir-Mode` to alwaysuse MELPA Stable by adding this to your Emacs initialization:```el(add-to-list 'package-pinned-packages '(elixir-mode . "melpa-stable") t)```### Via el-get[el-get](https://github.com/dimitri/el-get) is another popular package manager for Emacs. If you're an el-getuser just do <kbd>M-x el-get-install [RET] elixir-mode [RET]</kbd>.### ManualYou can install `Elixir-Mode` manually by placing `Elixir-Mode` on your `load-path` and`require` ing it. Many people favour the folder `~/.emacs.d/vendor`.```el(add-to-list 'load-path "~/.emacs.d/vendor")(require 'elixir-mode)```## Usage### Interactive Commands<table> <tr> <th>Command (For the <code>M-x</code> prompt.)</th> <th>Description</th> </tr> <tr> <td><code>elixir-mode</code></td> <td>Switches to elixir-mode.</td> </tr> <tr> <td><code>elixir-mode-open-github</code></td> <td>Open the GitHub page for Elixir.</td> </tr> </tr> <tr> <td><code>elixir-mode-open-elixir-home</code></td> <td>Go to Elixir README in the browser.</td> </tr> <tr> <td><code>elixir-mode-open-docs-master</code></td> <td>Open the Elixir documentation for the master.</td> </tr> <tr> <td><code>elixir-mode-open-docs-stable</code></td> <td>Open the Elixir documentation for the latest stable release.</td> </tr> <tr> <td><code>elixir-mode-show-version</code></td> <td>Print version info for elixir-mode.</td> </tr></table>### ConfigurationAny file that matches the glob `*.ex[s]` or `*.elixir` isautomatically opened in elixir-mode, but you can change thisfunctionality easily.```lisp;; Highlights *.elixir2 as well(add-to-list 'auto-mode-alist '("\\.elixir2\\'" . elixir-mode))```### KeymappingKeymaps can be added to the `elixir-mode-map` variable.### Pairing[Smartparens](https://github.com/Fuco1/smartparens) has direct support for Elixir.Alternatively, if you want to use `ruby-end-mode`, you can add the following to your `elixir-mode-hook`:```lisp(add-to-list 'elixir-mode-hook (defun auto-activate-ruby-end-mode-for-elixir-mode () (set (make-variable-buffer-local 'ruby-end-expand-keywords-before-re) "\\(?:^\\|\\s-+\\)\\(?:do\\)") (set (make-variable-buffer-local 'ruby-end-check-statement-modifiers) nil) (ruby-end-mode +1)))```## Elixir Tooling IntegrationIf you looking for elixir tooling integration for Emacs, check: [alchemist.el](https://github.com/tonini/alchemist.el)You can use [web-mode.el](http://web-mode.org) to edit elixir templates (eex files).## Elixir Format### Setup of elixir-formatCustomize the elixir and mix pathsIn Emacs, run following command to customize option``` elispM-x customize-optionCustomize-variable: elixir-format-elixir-path```and set your elixir executable path there. After that run:``` elispM-x customize-optionCustomize-variable: elixir-format-mix-path```and set your mix executable path there.Your machine's elixir and mix executable paths can be found with `which` command as shown below``` shell$ which elixir/usr/local/bin/elixir$ which mix/usr/local/bin/mix```Alternavively you can define variables as below``` elisp(setq elixir-format-elixir-path "/usr/local/bin/elixir")(setq elixir-format-mix-path "/usr/local/bin/mix")```### Use it``` elispM-x elixir-format```### Add elixir-mode hook to run elixir format on file save``` elisp;; Create a buffer-local hook to run elixir-format on save, only when we enable elixir-mode.(add-hook 'elixir-mode-hook (lambda () (add-hook 'before-save-hook 'elixir-format nil t)))```To use a `.formatter.exs` you can either set `elixir-format-arguments` globally to a path like this:``` elisp(setq elixir-format-arguments (list "--dot-formatter" "/path/to/.formatter.exs"))```or you set `elixir-format-arguments` in a hook like this:``` elisp(add-hook elixir-format-hook '(lambda () (if (projectile-project-p) (setq elixir-format-arguments (list "--dot-formatter" (concat (projectile-project-root) "/.formatter.exs"))) (setq elixir-format-arguments nil))))```In this example we use [Projectile](https://github.com/bbatsov/projectile) to get the project root and set `elixir-format-arguments` accordingly.## HistoryThis mode is based on the[Emacs mode by secondplanet](https://github.com/secondplanet/elixir-mode).## ContributingPlease read [CONTRIBUTING.md](https://github.com/elixir-lang/emacs-elixir/blob/master/CONTRIBUTING.md) for guidelines on how to contribute to this project.## LicenseCopyright © 2011-2017 Samuel Tonini, Matt DeBoard, Andreas Fuchs, secondplanet and[contributors](https://github.com/elixir-lang/emacs-elixir/contributors).Distributed under the GNU General Public License, version 3[badge-license]: https://img.shields.io/badge/license-GPL_3-green.svg

elixir-format.el

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
;;; elixir-format.el --- Emacs plugin to mix format Elixir files
2+
3+
;; Copyright 2017-2018 Anil Wadghule, Christian Kruse
4+
5+
;; This file is NOT part of GNU Emacs.
6+
7+
;; This program is free software; you can redistribute it and/or modify
8+
;; it under the terms of the GNU General Public License as published by
9+
;; the Free Software Foundation; either version 2, or (at your option)
10+
;; any later version.
11+
12+
;; This program is distributed in the hope that it will be useful,
13+
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
;; GNU General Public License for more details.
16+
17+
;;; Commentary:
18+
19+
;; The elixir-format function formats the elixir files with Elixir's `mix format`
20+
;; command
21+
22+
;; e.g.
23+
;; M-x elixir-format
24+
;;
25+
26+
(defcustom elixir-format-elixir-path "elixir"
27+
"Path to the Elixir interpreter."
28+
:type 'string
29+
:group 'elixir-format)
30+
31+
(defcustom elixir-format-mix-path "/usr/bin/mix"
32+
"Path to the 'mix' executable."
33+
:type 'string
34+
:group 'elixir-format)
35+
36+
(defcustom elixir-format-arguments nil
37+
"Additional arguments to 'mix format'"
38+
:type '(repeat string)
39+
:group 'elixir-format)
40+
41+
(defcustom elixir-format-hook nil
42+
"Hook called by `elixir-format'."
43+
:type 'hook
44+
:group 'elixir-format)
45+
46+
47+
;;; Code
48+
49+
(defun elixir-format--goto-line (line)
50+
(goto-char (point-min))
51+
(forward-line (1- line)))
52+
53+
(defun elixir-format--delete-whole-line (&optional arg)
54+
"Delete the current line without putting it in the `kill-ring'.
55+
Derived from function `kill-whole-line'. ARG is defined as for that
56+
function.
57+
58+
Shamelessly stolen from go-mode (https://github.com/dominikh/go-mode.el)"
59+
(setq arg (or arg 1))
60+
(if (and (> arg 0)
61+
(eobp)
62+
(save-excursion (forward-visible-line 0) (eobp)))
63+
(signal 'end-of-buffer nil))
64+
(if (and (< arg 0)
65+
(bobp)
66+
(save-excursion (end-of-visible-line) (bobp)))
67+
(signal 'beginning-of-buffer nil))
68+
(cond ((zerop arg)
69+
(delete-region (progn (forward-visible-line 0) (point))
70+
(progn (end-of-visible-line) (point))))
71+
((< arg 0)
72+
(delete-region (progn (end-of-visible-line) (point))
73+
(progn (forward-visible-line (1+ arg))
74+
(unless (bobp)
75+
(backward-char))
76+
(point))))
77+
(t
78+
(delete-region (progn (forward-visible-line 0) (point))
79+
(progn (forward-visible-line arg) (point))))))
80+
81+
(defun elixir-format--apply-rcs-patch (patch-buffer)
82+
"Apply an RCS-formatted diff from PATCH-BUFFER to the current buffer.
83+
Shamelessly stolen from go-mode (https://github.com/dominikh/go-mode.el)"
84+
85+
(let ((target-buffer (current-buffer))
86+
;; Relative offset between buffer line numbers and line numbers
87+
;; in patch.
88+
;;
89+
;; Line numbers in the patch are based on the source file, so
90+
;; we have to keep an offset when making changes to the
91+
;; buffer.
92+
;;
93+
;; Appending lines decrements the offset (possibly making it
94+
;; negative), deleting lines increments it. This order
95+
;; simplifies the forward-line invocations.
96+
(line-offset 0))
97+
(save-excursion
98+
(with-current-buffer patch-buffer
99+
(goto-char (point-min))
100+
(while (not (eobp))
101+
(unless (looking-at "^\\([ad]\\)\\([0-9]+\\) \\([0-9]+\\)")
102+
(error "Invalid rcs patch or internal error in elixir-format--apply-rcs-patch"))
103+
(forward-line)
104+
(let ((action (match-string 1))
105+
(from (string-to-number (match-string 2)))
106+
(len (string-to-number (match-string 3))))
107+
(cond
108+
((equal action "a")
109+
(let ((start (point)))
110+
(forward-line len)
111+
(let ((text (buffer-substring start (point))))
112+
(with-current-buffer target-buffer
113+
(cl-decf line-offset len)
114+
(goto-char (point-min))
115+
(forward-line (- from len line-offset))
116+
(insert text)))))
117+
((equal action "d")
118+
(with-current-buffer target-buffer
119+
(elixir-format--goto-line (- from line-offset))
120+
(cl-incf line-offset len)
121+
(elixir-format--delete-whole-line len)))
122+
(t
123+
(error "Invalid rcs patch or internal error in elixir-format--apply-rcs-patch"))))))))
124+
)
125+
126+
;;;###autoload
127+
(defun elixir-format (&optional is-interactive)
128+
(interactive "p")
129+
130+
(let ((outbuff (get-buffer-create "*elixir-format-output*"))
131+
(errbuff (get-buffer-create "*elixir-format-errors*"))
132+
(tmpfile (make-temp-file "elixir-format" nil ".ex"))
133+
(our-elixir-format-arguments (list elixir-format-mix-path "format"))
134+
(output nil))
135+
136+
(unwind-protect
137+
(save-restriction
138+
(with-current-buffer outbuff
139+
(erase-buffer))
140+
141+
(with-current-buffer errbuff
142+
(setq buffer-read-only nil)
143+
(erase-buffer))
144+
145+
(write-region nil nil tmpfile)
146+
147+
(run-hooks 'elixir-format-hook)
148+
149+
(when elixir-format-arguments
150+
(setq our-elixir-format-arguments (append our-elixir-format-arguments elixir-format-arguments)))
151+
(setq our-elixir-format-arguments (append our-elixir-format-arguments (list tmpfile)))
152+
153+
(if (zerop (apply #'call-process elixir-format-elixir-path nil errbuff nil our-elixir-format-arguments))
154+
(progn
155+
(if (zerop (call-process-region (point-min) (point-max) "diff" nil outbuff nil "-n" "-" tmpfile))
156+
(message "File is already formatted")
157+
(progn
158+
(elixir-format--apply-rcs-patch outbuff)
159+
(message "mix format applied")))
160+
(kill-buffer errbuff))
161+
162+
(progn
163+
(with-current-buffer errbuff
164+
(setq buffer-read-only t)
165+
(ansi-color-apply-on-region (point-min) (point-max))
166+
(special-mode))
167+
168+
(if is-interactive
169+
(display-buffer errbuff)
170+
(error "elixir-format failed: see %s" (buffer-name errbuff)))))
171+
172+
(delete-file tmpfile)
173+
(kill-buffer outbuff)))))
174+
175+
(provide 'elixir-format)
176+
177+
;;; elixir-format.el ends here

elixir-mode.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
(require 'easymenu) ; Elixir Mode menu definition
4040
(require 'elixir-smie) ; Syntax and indentation support
4141
(require 'pkg-info) ; Display Elixir Mode package version
42+
(require 'elixir-format) ; Elixir Format functions
4243

4344
(defgroup elixir nil
4445
"Major mode for editing Elixir code."

0 commit comments

Comments
 (0)