Skip to content

Commit

Permalink
Merge pull request #175 from editorconfig/extensionfiletype
Browse files Browse the repository at this point in the history
Add feature to decide major-mode from file_type_ext [EXPERIMENTAL]
  • Loading branch information
10sr authored Sep 24, 2018
2 parents 0fb534d + eedc429 commit 1176245
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 18 deletions.
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Current Emacs plugin coverage for EditorConfig's [properties][]:
we just buffer-locally override any preferences that would auto-add them
to files `.editorconfig` marks as trailing-newline-free
* `max_line_length`
* `file_type_ext` (Experimental)
* `file_type_emacs` (Experimental)
* `root` (only used by EditorConfig core)

Expand All @@ -66,15 +67,25 @@ we might not yet cover some mode you use, but we try to add the
ones that show up on our radar. Similarly, we don't yet hook
in to all different packages for whitespace trimming to inform
them about editorconfig settings, but aim for better coverage
of things like [ws-trim](ftp://ftp.lysator.liu.se/pub/emacs/ws-trim.el).

This plugin also has an experimental support for `file_type_emacs`,
which specifies "file types" for files.
As for Emacs, it means `major-mode` can be specified: for example,
when `file_type_emacs` is set to `markdown` for `a.txt`,
`markdown-mode` will be enabled when opening `a.txt`.
This property is experimental and its meaning might change in
the future updates.
of things like
[ws-trim](ftp://ftp.lysator.liu.se/pub/emacs/ws-trim.el).


### File Type

This plugin also has experimental supports for `file_type_ext` and
`file_type_emacs`, which specify "file types" for files.
As for Emacs, it means `major-mode` can be set.

**file_type_ext** When it is set to `md` for `a.txt`, for example,
`major-mode` will be decided as if the file name would be `a.txt.md`
(and thus `markdown-mode` is likely to be used).

**file_type_emacs** When it is set to `markdown` for `a.txt`,
`markdown-mode` will be enabled when opening `a.txt`.

These property are experimental and their meanings might change in the
future updates. When both are specified, `file_type_ext` takes precedence.


## Customize
Expand Down
30 changes: 23 additions & 7 deletions doc/editorconfig.texi
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ trailing-newline-free
@item
@code{max_line_length}
@item
@code{file_type_ext} (Experimental)
@item
@code{file_type_emacs} (Experimental)
@item
@code{root} (only used by EditorConfig core)
Expand All @@ -100,14 +102,28 @@ on our radar. Similarly, we don't yet hook in to all different packages
for whitespace trimming to inform them about editorconfig settings, but
aim for better coverage of things like
@uref{ftp://ftp.lysator.liu.se/pub/emacs/ws-trim.el,ws-trim}.
@menu
* File Type::
@end menu

@node File Type
@subsection File Type
@anchor{#file-type}
This plugin also has experimental supports for @code{file_type_ext} and
@code{file_type_emacs}, which specify ``file types'' for files. As for
Emacs, it means @code{major-mode} can be set.

@strong{file_type_ext} When it is set to @code{md} for @code{a.txt}, for
example, @code{major-mode} will be decided as if the file name would be
@code{a.txt.md} (and thus @code{markdown-mode} is likely to be used).

@strong{file_type_emacs} When it is set to @code{markdown} for
@code{a.txt}, @code{markdown-mode} will be enabled when opening
@code{a.txt}.

This plugin also has an experimental support for @code{file_type_emacs},
which specifies ``file types'' for files. As for Emacs, it means
@code{major-mode} can be specified: for example, when
@code{file_type_emacs} is set to @code{markdown} for @code{a.txt},
@code{markdown-mode} will be enabled when opening @code{a.txt}. This
property is experimental and its meaning might change in the future
updates.
These property are experimental and their meanings might change in the
future updates. When both are specified, @code{file_type_ext} takes
precedence.

@node Customize
@section Customize
Expand Down
65 changes: 63 additions & 2 deletions editorconfig.el
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ number - `lisp-indent-offset' is not set only if indent_size is
equal to this number. For example, if this is set to 2,
`lisp-indent-offset'will not be set only if indent_size is 2.")

(defconst editorconfig-unset-value "unset"
"String used to unset properties in .editorconfig .")

(defun editorconfig-string-integer-p (string)
"Return non-nil if STRING represents integer."
(and (stringp string)
Expand Down Expand Up @@ -426,7 +429,7 @@ TRIM-TRAILING-WS."
(and parent
(editorconfig--is-a-mode-p parent want)))))

(defun editorconfig-set-major-mode (filetype)
(defun editorconfig-set-major-mode-from-name (filetype)
"Set buffer `major-mode' by FILETYPE.
FILETYPE should be s string like `\"ini\"`, if not nil or empty string."
Expand All @@ -444,6 +447,63 @@ FILETYPE should be s string like `\"ini\"`, if not nil or empty string."
mode))
nil))))

(defvar editorconfig--apply-major-mode-currently nil
"Used internally.")
(make-variable-buffer-local 'editorconfig--apply-major-mode-currently)
(put 'editorconfig--apply-major-mode-currently
'permanent-local
t)

(defun editorconig-apply-major-mode-safely (mode)
"Set `major-mode' to MODE.
Normally `editorconfig-apply' will be hooked so that it runs when changing
`major-mode', so there is a possibility that MODE is called infinitely if
MODE is called naively from inside of `editorconfig-apply'.
This funcion will avoid such cases and set `major-mode' safely.
Just checking current `major-mode' value is not enough, because it can be
different from MODE value (for example, `conf-mode' will set `major-mode' to
`conf-unix-mode' or another conf mode)."
(unless (eq mode
editorconfig--apply-major-mode-currently)
(unwind-protect
(progn
(setq editorconfig--apply-major-mode-currently
mode)
(funcall mode))
(setq editorconfig--apply-major-mode-currently
nil))))

(defun editorconfig--find-mode-from-ext (ext &optional filename)
"Get suitable `major-mode' from EXT and FILENAME.
If FILENAME is omitted filename of current buffer is used."
(cl-assert ext)
(cl-assert (not (string= ext "")))
(let* ((name (concat (or filename
buffer-file-name)
"."
ext)))
(assoc-default name
auto-mode-alist
'string-match)))

(defun editorconfig-set-major-mode-from-ext (ext)
"Set buffer `major-mode' by EXT.
EXT should be a string like `\"ini\"`, if not nil or empty string."
(cl-assert buffer-file-name)
(when (and ext
(not (string= ext ""))
(not (string= ext editorconfig-unset-value)))

(let ((mode (editorconfig--find-mode-from-ext ext
buffer-file-name)))
(if mode
(editorconig-apply-major-mode-safely mode)
(display-warning :error (format "Major-mode for `%s' not found"
ext))
nil))))

(defun editorconfig-call-editorconfig-exec ()
"Call EditorConfig core and return output."
(let* ((filename (buffer-file-name))
Expand Down Expand Up @@ -540,7 +600,8 @@ applies available properties."
(editorconfig-set-trailing-nl (gethash 'insert_final_newline props))
(editorconfig-set-trailing-ws (gethash 'trim_trailing_whitespace props))
(editorconfig-set-line-length (gethash 'max_line_length props))
(editorconfig-set-major-mode (gethash 'file_type_emacs props))
(editorconfig-set-major-mode-from-name (gethash 'file_type_emacs props))
(editorconfig-set-major-mode-from-ext (gethash 'file_type_ext props))
(condition-case err
(run-hook-with-args 'editorconfig-custom-hooks props)
(error
Expand Down
20 changes: 20 additions & 0 deletions ert-tests/editorconfig.el
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
(require 'editorconfig)

(defun display-warning (type message &optional level buffer-name)
"When testing overwrite this function to throw error when called."
(error "display-warning called: %S %S %S %S"
type
message
level
buffer-name))

(defmacro with-visit-file (path &rest body)
"Visit PATH and evaluate BODY."
(declare (indent 1) (debug t))
Expand Down Expand Up @@ -87,3 +95,15 @@
"c.txt")
(should (eq major-mode 'conf-unix-mode)))
(editorconfig-mode -1))

(ert-deftest test-file-type-ext nil
(editorconfig-mode 1)
(with-visit-file (concat editorconfig-secondary-ert-dir
"a.txt")
(should (eq major-mode 'conf-unix-mode)))

(with-visit-file (concat editorconfig-secondary-ert-dir
"bin/perlscript")
(should (eq major-mode 'perl-mode))
(should (eq perl-indent-level 5)))
(editorconfig-mode -1))
7 changes: 7 additions & 0 deletions ert-tests/test_files_secondary/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,10 @@ indent_style = tab

[c.txt]
file_type_emacs = conf

[a.txt]
file_type_ext = ini

[/bin/*]
file_type_ext = pl
indent_size = 5

0 comments on commit 1176245

Please sign in to comment.