Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

203 lines
7.4 KiB

5 years ago
  1. ;;; nginx-mode.el --- major mode for editing nginx config files
  2. ;; Copyright 2010 Andrew J Cosgriff <andrew@cosgriff.name>
  3. ;; Author: Andrew J Cosgriff <andrew@cosgriff.name>
  4. ;; Maintainer: Andrew J Cosgriff <andrew@cosgriff.name>
  5. ;; Created: 15 Oct 2010
  6. ;; Version: 1.1.9
  7. ;; Package-Version: 1.1.9
  8. ;; Package-Commit: a2bab83c2eb233d57d76b236e7c141c2ccc97005
  9. ;; Keywords: languages, nginx
  10. ;; available from http://github.com/ajc/nginx-mode
  11. ;; This program is free software; you can redistribute it and/or modify
  12. ;; it under the terms of the GNU General Public License as published by
  13. ;; the Free Software Foundation; either version 2, or (at your option)
  14. ;; any later version.
  15. ;;
  16. ;; This program is distributed in the hope that it will be useful,
  17. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. ;; GNU General Public License for more details.
  20. ;;
  21. ;; You should have received a copy of the GNU General Public License
  22. ;; along with this program; if not, see <http://www.gnu.org/licenses/>.
  23. ;;; Commentary:
  24. ;; This is a quick mode for editing Nginx config files, as I didn't find
  25. ;; anything else around that did quite this much.
  26. ;; Many thanks to the authors of puppet-mode.el, from where I found a
  27. ;; useful indentation function that I've modified to suit this situation.
  28. ;; Put this file into your load-path and the following into your ~/.emacs:
  29. ;; (require 'nginx-mode)
  30. ;;; Code:
  31. ;;;;##########################################################################
  32. ;;;; User Options, Variables
  33. ;;;;##########################################################################
  34. (defcustom nginx-indent-level 4
  35. "*Indentation of Nginx statements."
  36. :type 'integer :group 'nginx)
  37. (defcustom nginx-indent-tabs-mode nil
  38. "*Indentation can insert tabs in nginx mode if this is non-nil."
  39. :type 'boolean :group 'nginx)
  40. (defvar nginx-mode-syntax-table
  41. (let ((table (make-syntax-table)))
  42. (modify-syntax-entry ?# "< b" table)
  43. (modify-syntax-entry ?\n "> b" table)
  44. table)
  45. "Syntax table for `nginx-mode'.")
  46. (defvar nginx-font-lock-keywords
  47. (list '("^\\([ \t]+\\)?\\([A-Za-z09_]+\\)" 2 font-lock-keyword-face t)
  48. ;; uncomment the next one if you want your eyes to bleed
  49. ;; (it'll highlight parentheses and curly braces)
  50. ;;'("\\(\{\\|\}\\|\(\\|\)\\)" . font-lock-pseudo-keyword-face)
  51. '("^\\([ \t]+\\)?rewrite[ \t]+.+[ \t]+\\(permanent\\|redirect\\|break\\|last\\);$" 2 font-lock-function-name-face)
  52. '("\\(\$[0-9]+\\)[^0-9]" 1 font-lock-constant-face)
  53. '("\$[A-Za-z0-9_\-]+" . font-lock-variable-name-face)
  54. '("[ \t]+\\(on\\|off\\);$" 1 font-lock-constant-face)
  55. '("[A-Za-z0-9_\-]+\\([ \t]+[^ \t\n]+\\)?[ \t]+\\([^ \t\n]+\\)[ \t]+{" 2 font-lock-function-name-face)))
  56. ;;;;##########################################################################
  57. ;;;; Code
  58. ;;;;##########################################################################
  59. (defun nginx-block-indent ()
  60. "If point is in a block, return the indentation of the first line of that
  61. block (the line containing the opening brace). Used to set the indentation
  62. of the closing brace of a block."
  63. (save-excursion
  64. (save-match-data
  65. (let ((opoint (point))
  66. (apoint (search-backward "{" nil t)))
  67. (when apoint
  68. ;; This is a bit of a hack and doesn't allow for strings. We really
  69. ;; want to parse by sexps at some point.
  70. (let ((close-braces (count-matches "}" apoint opoint))
  71. (open-braces 0))
  72. (while (and apoint (> close-braces open-braces))
  73. (setq apoint (search-backward "{" nil t))
  74. (when apoint
  75. (setq close-braces (count-matches "}" apoint opoint))
  76. (setq open-braces (1+ open-braces)))))
  77. (if apoint
  78. (current-indentation)
  79. nil))))))
  80. (defun nginx-comment-line-p ()
  81. "Return non-nil iff this line is a comment."
  82. (save-excursion
  83. (save-match-data
  84. (beginning-of-line)
  85. (looking-at "^\\s-*#"))))
  86. (defun nginx-indent-line ()
  87. "Indent current line as nginx code."
  88. (interactive)
  89. (beginning-of-line)
  90. (if (bobp)
  91. (indent-line-to 0) ; First line is always non-indented
  92. (let ((not-indented t)
  93. (block-indent (nginx-block-indent))
  94. cur-indent)
  95. (cond
  96. ((and (looking-at "^\\s-*}\\s-*$") block-indent)
  97. ;; This line contains a closing brace and we're at the inner
  98. ;; block, so we should indent it matching the indentation of
  99. ;; the opening brace of the block.
  100. (setq cur-indent block-indent))
  101. (t
  102. ;; Otherwise, we did not start on a block-ending-only line.
  103. (save-excursion
  104. ;; Iterate backwards until we find an indentation hint
  105. (while not-indented
  106. (forward-line -1)
  107. (cond
  108. ;; Comment lines are ignored unless we're at the start of the
  109. ;; buffer.
  110. ((nginx-comment-line-p)
  111. (if (bobp)
  112. (setq not-indented nil)))
  113. ;; Brace or paren on a line by itself will already be indented to
  114. ;; the right level, so we can cheat and stop there.
  115. ((looking-at "^\\s-*}\\s-*")
  116. (setq cur-indent (current-indentation))
  117. (setq not-indented nil))
  118. ;; Indent by one level more than the start of our block. We lose
  119. ;; if there is more than one block opened and closed on the same
  120. ;; line but it's still unbalanced; hopefully people don't do that.
  121. ((looking-at "^.*{[^\n}]*$")
  122. (setq cur-indent (+ (current-indentation) nginx-indent-level))
  123. (setq not-indented nil))
  124. ;; Start of buffer.
  125. ((bobp)
  126. (setq not-indented nil)))))))
  127. ;; We've figured out the indentation, so do it.
  128. (if (and cur-indent (> cur-indent 0))
  129. (indent-line-to cur-indent)
  130. (indent-line-to 0)))))
  131. (defvar nginx-mode-map
  132. (let
  133. ((map (make-sparse-keymap)))
  134. (define-key map "\C-j" 'newline-and-indent)
  135. (define-key map "\C-m" 'newline-and-indent)
  136. map)
  137. "Keymap for editing nginx config files.")
  138. ;;;###autoload
  139. (define-derived-mode nginx-mode prog-mode "Nginx"
  140. "Major mode for highlighting nginx config files.
  141. The variable nginx-indent-level controls the amount of indentation.
  142. \\{nginx-mode-map}"
  143. :syntax-table nginx-mode-syntax-table
  144. (use-local-map nginx-mode-map)
  145. (set (make-local-variable 'comment-start) "# ")
  146. (set (make-local-variable 'comment-start-skip) "#+ *")
  147. (set (make-local-variable 'comment-end) "")
  148. (set (make-local-variable 'comment-auto-fill-only-comments) t)
  149. (set (make-local-variable 'indent-line-function) 'nginx-indent-line)
  150. (set (make-local-variable 'indent-tabs-mode) nginx-indent-tabs-mode)
  151. (set (make-local-variable 'require-final-newline) t)
  152. (set (make-local-variable 'paragraph-ignore-fill-prefix) t)
  153. (set (make-local-variable 'paragraph-start) "\f\\|[ ]*$\\|#$")
  154. (set (make-local-variable 'paragraph-separate) "\\([ \f]*\\|#\\)$")
  155. (set (make-local-variable 'font-lock-defaults)
  156. '(nginx-font-lock-keywords nil)))
  157. ;;;###autoload
  158. (add-to-list 'auto-mode-alist '("nginx\\.conf\\'" . nginx-mode))
  159. ;;;###autoload
  160. (add-to-list 'auto-mode-alist '("/nginx/.+\\.conf\\'" . nginx-mode))
  161. ;;;###autoload
  162. (add-to-list
  163. 'magic-fallback-mode-alist
  164. '("\\(?:.*\n\\)*\\(?:http\\|server\\|location .+\\|upstream .+\\)[ \n\t]+{"
  165. . nginx-mode))
  166. (provide 'nginx-mode)
  167. ;;; nginx-mode.el ends here