Last active
October 30, 2019 22:11
-
-
Save preetpalS/54acec3f166393f1d9e55380e1df7364 to your computer and use it in GitHub Desktop.
An Emacs major mode for .env files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; dotenv-mode.el --- Major mode for .env files -*- lexical-binding: t; -*- | |
;; Author: Preetpal S. Sohal | |
;; URL: https://github.com/preetpalS/emacs-dotenv-mode | |
;; Version: 0.2.5 | |
;; Package-Requires: ((emacs "24.3")) | |
;; License: GNU General Public License Version 3 | |
;; 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. | |
;;; Commentary: | |
;; | |
;; Major mode for editing .env files (which are used for storing | |
;; environment variables). | |
;; | |
;; Usage: | |
;; | |
;; (require 'dotenv-mode) ; unless installed from a package | |
;; (add-to-list 'auto-mode-alist '("\\.env\\..*\\'" . dotenv-mode)) ;; for optionally supporting additional file extensions such as `.env.test' with this major mode | |
;;; Code: | |
(defgroup dotenv () | |
"Major mode for editing .env files." | |
:group 'languages | |
:prefix "dotenv-") | |
;; Adapted from code in ruby-mode provided with Emacs | |
(defcustom dotenv-comment-column (default-value 'comment-column) | |
"Indentation column of comments." | |
:type 'integer | |
:safe 'integerp) | |
(defvar dotenv-mode-syntax-table | |
(let ((table (make-syntax-table))) | |
(modify-syntax-entry ?' "\"'" table) ; ?' is a string delimiter | |
(modify-syntax-entry ?\" "\"" table) ; ?\" is a string delimiter | |
(modify-syntax-entry ?# "<" table) ; ?# starts comments | |
(modify-syntax-entry ?\n ">" table) ; ?\n ends comments | |
(modify-syntax-entry ?_ "_" table) ; ?_ can be used in variable and command names | |
(modify-syntax-entry ?\\ "\\" table) ; ?\\ is an escape sequence character | |
(modify-syntax-entry ?$ "'" table) ; ?$ is an expression prefix; Used in highlighting $VARIABLES, ${SUBSTITUTED_VARIABLES}, and $(substituted commands) embedded in double-quoted strings | |
table)) | |
;; Adapted from code generously donated by Fuco1 (https://github.com/Fuco1; see: https://fuco1.github.io/2017-06-11-Font-locking-with-custom-matchers.html) | |
(defun dotenv-mode--match-variables-in-double-quotes (limit) | |
"Match variables in double-quotes in `dotenv-mode'." | |
(with-syntax-table dotenv-mode-syntax-table | |
(catch 'done | |
(while (re-search-forward | |
;; `rx' is cool, mkay. | |
(rx (or line-start | |
(not (any "\\"))) | |
(group "$") | |
(group | |
(or (and "{" (+? nonl) "}") | |
(and "(" (+? nonl) ")") ;; Added to support for interpolated command substitution syntax (like: "$(shell command)") | |
(and (+ (any alnum "_"))) | |
(and (any "*" "@" "#" "?" "-" "$" "!" "0" "_"))))) | |
limit t) | |
(let ((string-syntax (nth 3 (syntax-ppss)))) | |
(when (and string-syntax (= string-syntax 34)) | |
(throw 'done (point)))))))) | |
(defvar dotenv-mode-keywords | |
'(("\\(export\\)[[:space:]]+" . 1) | |
;; Adapted from code generously donated by Fuco1 (https://github.com/Fuco1; see: https://fuco1.github.io/2017-06-11-Font-locking-with-custom-matchers.html) | |
(dotenv-mode--match-variables-in-double-quotes (1 'default t) | |
(2 font-lock-variable-name-face t)) | |
("\\([[:alpha:]_]+[[:alnum:]_]*\\)[=]" 1 font-lock-variable-name-face) | |
("^\\([[:alpha:]_]+[[:alnum:]_]*\\)[:=]" 1 font-lock-variable-name-face) | |
("\$[[:alpha:]]+[[:alnum:]_]*" . font-lock-variable-name-face) | |
("\${[[:alpha:]]+[[:alnum:]_]*}" . font-lock-variable-name-face) | |
("\$([[:alpha:]]+[[:alnum:]_]*)" . font-lock-variable-name-face))) | |
(defun dotenv-mode-variables () | |
"Initialize buffer-local variables for `dotenv-mode'" | |
(setq-local comment-start "# ") ;; Added due to suggestion by jscheid (https://github.com/jscheid) | |
(setq-local comment-end "") | |
(setq-local comment-column dotenv-comment-column) | |
(setq-local comment-start-skip "#+ *") | |
(setq-local font-lock-defaults '((dotenv-mode-keywords)))) | |
;;;###autoload | |
(define-derived-mode dotenv-mode prog-mode ".env" | |
"Major mode for `.env' files." | |
:abbrev-table nil | |
:syntax-table dotenv-mode-syntax-table | |
(dotenv-mode-variables)) | |
;;;###autoload | |
(mapc (lambda (s) (add-to-list 'auto-mode-alist `(,s . dotenv-mode))) | |
'( | |
"\\.env\\'" | |
"\\.env\\.example\\'" | |
)) | |
(provide 'dotenv-mode) | |
;;; dotenv-mode.el ends here |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Moving development to https://github.com/preetpalS/emacs-dotenv-mode. I may merge changes back into this gist once in a while when I make further changes to the GitHub repo (note that this is done with
git push REMOTE_ADDRESS_OF_THIS_GIST gist:master
(see gist branch on GitHub repo)).