summaryrefslogtreecommitdiff
path: root/.emacs.d/lisp/yaml-mode.el
diff options
context:
space:
mode:
authorSimeon Simeonov2015-08-28 11:10:13 +0200
committerSimeon Simeonov2015-08-28 11:10:13 +0200
commit3ec6ac6a8d888043cc12dfe6f77adcd0cfc1b086 (patch)
treec2382110856abc0cae77f8360ea2b0d8962d07f9 /.emacs.d/lisp/yaml-mode.el
parenteeeaae3a34ca050c9ea30aa3950dc91db70b9b1a (diff)
Upgrade all, add yaml, few snippet fixes
Diffstat (limited to '.emacs.d/lisp/yaml-mode.el')
-rw-r--r--.emacs.d/lisp/yaml-mode.el456
1 files changed, 456 insertions, 0 deletions
diff --git a/.emacs.d/lisp/yaml-mode.el b/.emacs.d/lisp/yaml-mode.el
new file mode 100644
index 0000000..15f3872
--- /dev/null
+++ b/.emacs.d/lisp/yaml-mode.el
@@ -0,0 +1,456 @@
1;;; yaml-mode.el --- Major mode for editing YAML files
2
3;; Copyright (C) 2010-2014 Yoshiki Kurihara
4
5;; Author: Yoshiki Kurihara <clouder@gmail.com>
6;; Marshall T. Vandegrift <llasram@gmail.com>
7;; Keywords: data yaml
8;; Version: 0.0.12
9
10;; This file is not part of Emacs
11
12;; This file is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
17;; This file is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to
24;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
26
27;;; Commentary:
28
29;; This is a major mode for editing files in the YAML data
30;; serialization format. It was initially developed by Yoshiki
31;; Kurihara and many features were added by Marshall Vandegrift. As
32;; YAML and Python share the fact that indentation determines
33;; structure, this mode provides indentation and indentation command
34;; behavior very similar to that of python-mode.
35
36;;; Installation:
37
38;; To install, just drop this file into a directory in your
39;; `load-path' and (optionally) byte-compile it. To automatically
40;; handle files ending in '.yml', add something like:
41;;
42;; (require 'yaml-mode)
43;; (add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode))
44;;
45;; to your .emacs file.
46;;
47;; Unlike python-mode, this mode follows the Emacs convention of not
48;; binding the ENTER key to `newline-and-indent'. To get this
49;; behavior, add the key definition to `yaml-mode-hook':
50;;
51;; (add-hook 'yaml-mode-hook
52;; '(lambda ()
53;; (define-key yaml-mode-map "\C-m" 'newline-and-indent)))
54
55;;; Known Bugs:
56
57;; YAML is easy to write but complex to parse, and this mode doesn't
58;; even really try. Indentation and highlighting will break on
59;; abnormally complicated structures.
60
61;;; Code:
62
63
64;; User definable variables
65
66;;;###autoload
67(defgroup yaml nil
68 "Support for the YAML serialization format"
69 :group 'languages
70 :prefix "yaml-")
71
72(defcustom yaml-mode-hook nil
73 "*Hook run by `yaml-mode'."
74 :type 'hook
75 :group 'yaml)
76
77(defcustom yaml-indent-offset 2
78 "*Amount of offset per level of indentation."
79 :type 'integer
80 :group 'yaml)
81
82(defcustom yaml-backspace-function 'backward-delete-char-untabify
83 "*Function called by `yaml-electric-backspace' when deleting backwards.
84It will receive one argument, the numeric prefix value."
85 :type 'function
86 :group 'yaml)
87
88(defcustom yaml-block-literal-search-lines 100
89 "*Maximum number of lines to search for start of block literals."
90 :type 'integer
91 :group 'yaml)
92
93(defcustom yaml-block-literal-electric-alist
94 '((?| . "") (?> . "-"))
95 "*Characters for which to provide electric behavior.
96The association list key should be a key code and the associated value
97should be a string containing additional characters to insert when
98that key is pressed to begin a block literal."
99 :type 'alist
100 :group 'yaml)
101
102(defface yaml-tab-face
103 '((((class color)) (:background "red" :foreground "red" :bold t))
104 (t (:reverse-video t)))
105 "Face to use for highlighting tabs in YAML files."
106 :group 'faces
107 :group 'yaml)
108
109(defcustom yaml-imenu-generic-expression
110 '((nil "^\\(:?[a-zA-Z_-]+\\):" 1))
111 "The imenu regex to parse an outline of the yaml file."
112 :type 'string
113 :group 'yaml)
114
115
116;; Constants
117
118(defconst yaml-mode-version "0.0.12" "Version of `yaml-mode'.")
119
120(defconst yaml-blank-line-re "^ *$"
121 "Regexp matching a line containing only (valid) whitespace.")
122
123(defconst yaml-directive-re "^\\(?:--- \\)? *%\\(\\w+\\)"
124 "Regexp matching a line contatining a YAML directive.")
125
126(defconst yaml-document-delimiter-re "^ *\\(?:---\\|[.][.][.]\\)"
127 "Rexexp matching a YAML document delimiter line.")
128
129(defconst yaml-node-anchor-alias-re "[&*][a-zA-Z0-9_-]+"
130 "Regexp matching a YAML node anchor or alias.")
131
132(defconst yaml-tag-re "!!?[^ \n]+"
133 "Rexexp matching a YAML tag.")
134
135(defconst yaml-bare-scalar-re
136 "\\(?:[^-:,#!\n{\\[ ]\\|[^#!\n{\\[ ]\\S-\\)[^#\n]*?"
137 "Rexexp matching a YAML bare scalar.")
138
139(defconst yaml-hash-key-re
140 (concat "\\(?:^\\(?:--- \\)?\\|{\\|\\(?:[-,] +\\)+\\) *"
141 "\\(?:" yaml-tag-re " +\\)?"
142 "\\(" yaml-bare-scalar-re "\\) *:"
143 "\\(?: +\\|$\\)")
144 "Regexp matching a single YAML hash key.")
145
146(defconst yaml-scalar-context-re
147 (concat "\\(?:^\\(?:--- \\)?\\|{\\|\\(?:[-,] +\\)+\\) *"
148 "\\(?:" yaml-bare-scalar-re " *: \\)?")
149 "Regexp indicating the begininng of a scalar context.")
150
151(defconst yaml-nested-map-re
152 (concat ".*: *\\(?:&.*\\|{ *\\|" yaml-tag-re " *\\)?$")
153 "Regexp matching a line beginning a YAML nested structure.")
154
155(defconst yaml-block-literal-base-re " *[>|][-+0-9]* *\\(?:\n\\|\\'\\)"
156 "Regexp matching the substring start of a block literal.")
157
158(defconst yaml-block-literal-re
159 (concat yaml-scalar-context-re
160 "\\(?:" yaml-tag-re "\\)?"
161 yaml-block-literal-base-re)
162 "Regexp matching a line beginning a YAML block literal.")
163
164(defconst yaml-nested-sequence-re
165 (concat "^\\(?: *- +\\)+"
166 "\\(?:" yaml-bare-scalar-re " *:\\(?: +.*\\)?\\)?$")
167 "Regexp matching a line containing one or more nested YAML sequences.")
168
169(defconst yaml-constant-scalars-re
170 (concat "\\(?:^\\|\\(?::\\|-\\|,\\|{\\|\\[\\) +\\) *"
171 (regexp-opt
172 '("~" "null" "Null" "NULL"
173 ".nan" ".NaN" ".NAN"
174 ".inf" ".Inf" ".INF"
175 "-.inf" "-.Inf" "-.INF"
176 "y" "Y" "yes" "Yes" "YES" "n" "N" "no" "No" "NO"
177 "true" "True" "TRUE" "false" "False" "FALSE"
178 "on" "On" "ON" "off" "Off" "OFF") t)
179 " *$")
180 "Regexp matching certain scalar constants in scalar context.")
181
182
183;; Mode setup
184
185(defvar yaml-mode-map ()
186 "Keymap used in `yaml-mode' buffers.")
187(if yaml-mode-map
188 nil
189 (setq yaml-mode-map (make-sparse-keymap))
190 (define-key yaml-mode-map "|" 'yaml-electric-bar-and-angle)
191 (define-key yaml-mode-map ">" 'yaml-electric-bar-and-angle)
192 (define-key yaml-mode-map "-" 'yaml-electric-dash-and-dot)
193 (define-key yaml-mode-map "." 'yaml-electric-dash-and-dot)
194 (define-key yaml-mode-map [backspace] 'yaml-electric-backspace))
195
196(defvar yaml-mode-syntax-table nil
197 "Syntax table in use in `yaml-mode' buffers.")
198(if yaml-mode-syntax-table
199 nil
200 (setq yaml-mode-syntax-table (make-syntax-table))
201 (modify-syntax-entry ?\' "\"" yaml-mode-syntax-table)
202 (modify-syntax-entry ?\" "\"" yaml-mode-syntax-table)
203 (modify-syntax-entry ?# "<" yaml-mode-syntax-table)
204 (modify-syntax-entry ?\n ">" yaml-mode-syntax-table)
205 (modify-syntax-entry ?\\ "\\" yaml-mode-syntax-table)
206 (modify-syntax-entry ?- "w" yaml-mode-syntax-table)
207 (modify-syntax-entry ?_ "_" yaml-mode-syntax-table)
208 (modify-syntax-entry ?\( "." yaml-mode-syntax-table)
209 (modify-syntax-entry ?\) "." yaml-mode-syntax-table)
210 (modify-syntax-entry ?\{ "(}" yaml-mode-syntax-table)
211 (modify-syntax-entry ?\} "){" yaml-mode-syntax-table)
212 (modify-syntax-entry ?\[ "(]" yaml-mode-syntax-table)
213 (modify-syntax-entry ?\] ")[" yaml-mode-syntax-table))
214
215;;;###autoload
216(define-derived-mode yaml-mode fundamental-mode "YAML"
217 "Simple mode to edit YAML.
218
219\\{yaml-mode-map}"
220 :syntax-table yaml-mode-syntax-table
221 (set (make-local-variable 'comment-start) "# ")
222 (set (make-local-variable 'comment-start-skip) "#+ *")
223 (set (make-local-variable 'indent-line-function) 'yaml-indent-line)
224 (set (make-local-variable 'indent-tabs-mode) nil)
225 (set (make-local-variable 'fill-paragraph-function) 'yaml-fill-paragraph)
226 (set (make-local-variable 'font-lock-defaults)
227 '(yaml-font-lock-keywords
228 nil nil nil nil
229 (font-lock-syntactic-keywords . yaml-font-lock-syntactic-keywords)))
230 (if (fboundp 'font-lock-flush)
231 (font-lock-flush)
232 (with-no-warnings
233 (font-lock-fontify-buffer))))
234
235
236;; Font-lock support
237
238(defvar yaml-font-lock-keywords
239 (list
240 (cons yaml-constant-scalars-re '(1 font-lock-constant-face))
241 (cons yaml-tag-re '(0 font-lock-type-face))
242 (cons yaml-node-anchor-alias-re '(0 font-lock-function-name-face))
243 (cons yaml-hash-key-re '(1 font-lock-variable-name-face))
244 (cons yaml-document-delimiter-re '(0 font-lock-comment-face))
245 (cons yaml-directive-re '(1 font-lock-builtin-face))
246 '(yaml-font-lock-block-literals 0 font-lock-string-face)
247 '("^[\t]+" 0 'yaml-tab-face t))
248 "Additional expressions to highlight in YAML mode.")
249
250(defvar yaml-font-lock-syntactic-keywords
251 (list '(yaml-syntactic-block-literals 0 "."))
252 "Additional syntax features to highlight in YAML mode.")
253
254
255(defun yaml-font-lock-block-literals (bound)
256 "Find lines within block literals.
257Find the next line of the first (if any) block literal after point and
258prior to BOUND. Returns the beginning and end of the block literal
259line in the match data, as consumed by `font-lock-keywords' matcher
260functions. The function begins by searching backwards to determine
261whether or not the current line is within a block literal. This could
262be time-consuming in large buffers, so the number of lines searched is
263artificially limitted to the value of
264`yaml-block-literal-search-lines'."
265 (if (eolp) (goto-char (1+ (point))))
266 (unless (or (eobp) (>= (point) bound))
267 (let ((begin (point))
268 (end (min (1+ (point-at-eol)) bound)))
269 (goto-char (point-at-bol))
270 (while (and (looking-at yaml-blank-line-re) (not (bobp)))
271 (forward-line -1))
272 (let ((nlines yaml-block-literal-search-lines)
273 (min-level (current-indentation)))
274 (forward-line -1)
275 (while (and (/= nlines 0)
276 (/= min-level 0)
277 (not (looking-at yaml-block-literal-re))
278 (not (bobp)))
279 (set 'nlines (1- nlines))
280 (unless (looking-at yaml-blank-line-re)
281 (set 'min-level (min min-level (current-indentation))))
282 (forward-line -1))
283 (cond
284 ((and (< (current-indentation) min-level)
285 (looking-at yaml-block-literal-re))
286 (goto-char end) (set-match-data (list begin end)) t)
287 ((progn
288 (goto-char begin)
289 (re-search-forward (concat yaml-block-literal-re
290 " *\\(.*\\)\n")
291 bound t))
292 (set-match-data (nthcdr 2 (match-data))) t))))))
293
294(defun yaml-syntactic-block-literals (bound)
295 "Find quote characters within block literals.
296Finds the first quote character within a block literal (if any) after
297point and prior to BOUND. Returns the position of the quote character
298in the match data, as consumed by matcher functions in
299`font-lock-syntactic-keywords'. This allows the mode to treat ['\"]
300characters in block literals as punctuation syntax instead of string
301syntax, preventing unmatched quotes in block literals from painting
302the entire buffer in `font-lock-string-face'."
303 (let ((found nil))
304 (while (and (not found)
305 (/= (point) bound)
306 (yaml-font-lock-block-literals bound))
307 (let ((begin (match-beginning 0)) (end (match-end 0)))
308 (goto-char begin)
309 (cond
310 ((re-search-forward "['\"]" end t) (setq found t))
311 ((goto-char end)))))
312 found))
313
314
315;; Indentation and electric keys
316
317(defun yaml-compute-indentation ()
318 "Calculate the maximum sensible indentation for the current line."
319 (save-excursion
320 (beginning-of-line)
321 (if (looking-at yaml-document-delimiter-re) 0
322 (forward-line -1)
323 (while (and (looking-at yaml-blank-line-re)
324 (> (point) (point-min)))
325 (forward-line -1))
326 (+ (current-indentation)
327 (if (looking-at yaml-nested-map-re) yaml-indent-offset 0)
328 (if (looking-at yaml-nested-sequence-re) yaml-indent-offset 0)
329 (if (looking-at yaml-block-literal-re) yaml-indent-offset 0)))))
330
331(defun yaml-indent-line ()
332 "Indent the current line.
333The first time this command is used, the line will be indented to the
334maximum sensible indentation. Each immediately subsequent usage will
335back-dent the line by `yaml-indent-offset' spaces. On reaching column
3360, it will cycle back to the maximum sensible indentation."
337 (interactive "*")
338 (let ((ci (current-indentation))
339 (cc (current-column))
340 (need (yaml-compute-indentation)))
341 (save-excursion
342 (beginning-of-line)
343 (delete-horizontal-space)
344 (if (and (equal last-command this-command) (/= ci 0))
345 (indent-to (* (/ (- ci 1) yaml-indent-offset) yaml-indent-offset))
346 (indent-to need)))
347 (if (< (current-column) (current-indentation))
348 (forward-to-indentation 0))))
349
350(defun yaml-electric-backspace (arg)
351 "Delete characters or back-dent the current line.
352If invoked following only whitespace on a line, will back-dent to the
353immediately previous multiple of `yaml-indent-offset' spaces."
354 (interactive "*p")
355 (if (or (/= (current-indentation) (current-column)) (bolp))
356 (funcall yaml-backspace-function arg)
357 (let ((ci (current-column)))
358 (beginning-of-line)
359 (delete-horizontal-space)
360 (indent-to (* (/ (- ci (* arg yaml-indent-offset))
361 yaml-indent-offset)
362 yaml-indent-offset)))))
363
364(defun yaml-electric-bar-and-angle (arg)
365 "Insert the bound key and possibly begin a block literal.
366Inserts the bound key. If inserting the bound key causes the current
367line to match the initial line of a block literal, then inserts the
368matching string from `yaml-block-literal-electric-alist', a newline,
369and indents appropriately."
370 (interactive "*P")
371 (self-insert-command (prefix-numeric-value arg))
372 (let ((extra-chars
373 (assoc last-command-event
374 yaml-block-literal-electric-alist)))
375 (cond
376 ((and extra-chars (not arg) (eolp)
377 (save-excursion
378 (beginning-of-line)
379 (looking-at yaml-block-literal-re)))
380 (insert (cdr extra-chars))
381 (newline-and-indent)))))
382
383(defun yaml-electric-dash-and-dot (arg)
384 "Insert the bound key and possibly de-dent line.
385Inserts the bound key. If inserting the bound key causes the current
386line to match a document delimiter, de-dent the line to the left
387margin."
388 (interactive "*P")
389 (self-insert-command (prefix-numeric-value arg))
390 (save-excursion
391 (beginning-of-line)
392 (if (and (not arg) (looking-at yaml-document-delimiter-re))
393 (delete-horizontal-space))))
394
395(defun yaml-narrow-to-block-literal ()
396 "Narrow the buffer to block literal if the point is in it,
397otherwise do nothing."
398 (interactive)
399 (save-excursion
400 (goto-char (point-at-bol))
401 (while (and (looking-at-p yaml-blank-line-re) (not (bobp)))
402 (forward-line -1))
403 (let ((nlines yaml-block-literal-search-lines)
404 (min-level (current-indentation))
405 beg)
406 (forward-line -1)
407 (while (and (/= nlines 0)
408 (/= min-level 0)
409 (not (looking-at-p yaml-block-literal-re))
410 (not (bobp)))
411 (set 'nlines (1- nlines))
412 (unless (looking-at-p yaml-blank-line-re)
413 (set 'min-level (min min-level (current-indentation))))
414 (forward-line -1))
415 (when (and (< (current-indentation) min-level)
416 (looking-at-p yaml-block-literal-re))
417 (set 'min-level (current-indentation))
418 (forward-line)
419 (setq beg (point))
420 (while (and (not (eobp))
421 (or (looking-at-p yaml-blank-line-re)
422 (> (current-indentation) min-level)))
423 (forward-line))
424 (narrow-to-region beg (point))))))
425
426(defun yaml-fill-paragraph (&optional justify region)
427 "Fill paragraph.
428This behaves as `fill-paragraph' except that filling does not
429cross boundaries of block literals."
430 (interactive "*P")
431 (save-restriction
432 (yaml-narrow-to-block-literal)
433 (let ((fill-paragraph-function nil))
434 (fill-paragraph justify region))))
435
436(defun yaml-set-imenu-generic-expression ()
437 (make-local-variable 'imenu-generic-expression)
438 (make-local-variable 'imenu-create-index-function)
439 (setq imenu-create-index-function 'imenu-default-create-index-function)
440 (setq imenu-generic-expression yaml-imenu-generic-expression))
441
442(add-hook 'yaml-mode-hook 'yaml-set-imenu-generic-expression)
443
444
445(defun yaml-mode-version ()
446 "Diplay version of `yaml-mode'."
447 (interactive)
448 (message "yaml-mode %s" yaml-mode-version)
449 yaml-mode-version)
450
451;;;###autoload
452(add-to-list 'auto-mode-alist '("\\.e?ya?ml$" . yaml-mode))
453
454(provide 'yaml-mode)
455
456;;; yaml-mode.el ends here