From 44b6eb141d7b635f75444b28480acbbf735aa5f6 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Thu, 21 Nov 2013 08:30:01 +0100 Subject: [PATCH] added yaml-mode. Signed-off-by: Andreas Gerler --- init.el | 4 + yaml-mode.el | 415 ++++++++++++++++++++++++++++++++++++++++++++++++++ yaml-mode.elc | Bin 0 -> 13043 bytes 3 files changed, 419 insertions(+) create mode 100644 yaml-mode.el create mode 100644 yaml-mode.elc diff --git a/init.el b/init.el index 097d059f..d1267198 100644 --- a/init.el +++ b/init.el @@ -19,6 +19,10 @@ load-path)) (require 'template) (template-initialize) +;; load yaml-mode +(require 'yaml-mode) +(add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode)) + ;; load org mode ;; See http://orgmode.org/worg/org-tutorials/orgtutorial_dto.html for details diff --git a/yaml-mode.el b/yaml-mode.el new file mode 100644 index 00000000..66ea331e --- /dev/null +++ b/yaml-mode.el @@ -0,0 +1,415 @@ +;;; yaml-mode.el --- Major mode for editing YAML files + +;; Copyright (C) 2010-2013 Yoshiki Kurihara + +;; Author: Yoshiki Kurihara +;; Marshall T. Vandegrift +;; Keywords: data yaml +;; Version: 0.0.9 + +;; This file is not part of Emacs + +;; This file 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 2, or (at your option) +;; any later version. + +;; This file 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This is a major mode for editing files in the YAML data +;; serialization format. It was initially developed by Yoshiki +;; Kurihara and many features were added by Marshall Vandegrift. As +;; YAML and Python share the fact that indentation determines +;; structure, this mode provides indentation and indentation command +;; behavior very similar to that of python-mode. + +;;; Installation: + +;; To install, just drop this file into a directory in your +;; `load-path' and (optionally) byte-compile it. To automatically +;; handle files ending in '.yml', add something like: +;; +;; (require 'yaml-mode) +;; (add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode)) +;; +;; to your .emacs file. +;; +;; Unlike python-mode, this mode follows the Emacs convention of not +;; binding the ENTER key to `newline-and-indent'. To get this +;; behavior, add the key definition to `yaml-mode-hook': +;; +;; (add-hook 'yaml-mode-hook +;; '(lambda () +;; (define-key yaml-mode-map "\C-m" 'newline-and-indent))) + +;;; Known Bugs: + +;; YAML is easy to write but complex to parse, and this mode doesn't +;; even really try. Indentation and highlighting will break on +;; abnormally complicated structures. + +;;; Code: + + +;; User definable variables + +;;;###autoload +(defgroup yaml nil + "Support for the YAML serialization format" + :group 'languages + :prefix "yaml-") + +(defcustom yaml-mode-hook nil + "*Hook run by `yaml-mode'." + :type 'hook + :group 'yaml) + +(defcustom yaml-indent-offset 2 + "*Amount of offset per level of indentation." + :type 'integer + :group 'yaml) + +(defcustom yaml-backspace-function 'backward-delete-char-untabify + "*Function called by `yaml-electric-backspace' when deleting backwards. +It will receive one argument, the numeric prefix value." + :type 'function + :group 'yaml) + +(defcustom yaml-block-literal-search-lines 100 + "*Maximum number of lines to search for start of block literals." + :type 'integer + :group 'yaml) + +(defcustom yaml-block-literal-electric-alist + '((?| . "") (?> . "-")) + "*Characters for which to provide electric behavior. +The association list key should be a key code and the associated value +should be a string containing additional characters to insert when +that key is pressed to begin a block literal." + :type 'alist + :group 'yaml) + +(defface yaml-tab-face + '((((class color)) (:background "red" :foreground "red" :bold t)) + (t (:reverse-video t))) + "Face to use for highlighting tabs in YAML files." + :group 'faces + :group 'yaml) + +(defcustom yaml-imenu-generic-expression + '((nil "^\\(:?[a-zA-Z_-]+\\):" 1)) + "The imenu regex to parse an outline of the yaml file." + :type 'string + :group 'yaml) + + +;; Constants + +(defconst yaml-mode-version "0.0.9" "Version of `yaml-mode'.") + +(defconst yaml-blank-line-re "^ *$" + "Regexp matching a line containing only (valid) whitespace.") + +(defconst yaml-comment-re "\\(?:^\\|\\s-+\\)\\(#.*\\)" + "Regexp matching a line containing a YAML comment or delimiter.") + +(defconst yaml-directive-re "^\\(?:--- \\)? *%\\(\\w+\\)" + "Regexp matching a line contatining a YAML directive.") + +(defconst yaml-document-delimiter-re "^ *\\(?:---\\|[.][.][.]\\)" + "Rexexp matching a YAML document delimiter line.") + +(defconst yaml-node-anchor-alias-re "[&*][a-zA-Z0-9_-]+" + "Regexp matching a YAML node anchor or alias.") + +(defconst yaml-tag-re "!!?[^ \n]+" + "Rexexp matching a YAML tag.") + +(defconst yaml-bare-scalar-re + "\\(?:[^-:,#!\n{\\[ ]\\|[^#!\n{\\[ ]\\S-\\)[^#\n]*?" + "Rexexp matching a YAML bare scalar.") + +(defconst yaml-hash-key-re + (concat "\\(?:^\\(?:--- \\)?\\|{\\|\\(?:[-,] +\\)+\\) *" + "\\(?:" yaml-tag-re " +\\)?" + "\\(" yaml-bare-scalar-re "\\) *:" + "\\(?: +\\|$\\)") + "Regexp matching a single YAML hash key.") + +(defconst yaml-scalar-context-re + (concat "\\(?:^\\(?:--- \\)?\\|{\\|\\(?:[-,] +\\)+\\) *" + "\\(?:" yaml-bare-scalar-re " *: \\)?") + "Regexp indicating the begininng of a scalar context.") + +(defconst yaml-nested-map-re + (concat ".*: *\\(?:&.*\\|{ *\\|" yaml-tag-re " *\\)?$") + "Regexp matching a line beginning a YAML nested structure.") + +(defconst yaml-block-literal-base-re " *[>|][-+0-9]* *\\(?:\n\\|\\'\\)" + "Regexp matching the substring start of a block literal.") + +(defconst yaml-block-literal-re + (concat yaml-scalar-context-re + "\\(?:" yaml-tag-re "\\)?" + yaml-block-literal-base-re) + "Regexp matching a line beginning a YAML block literal.") + +(defconst yaml-nested-sequence-re + (concat "^\\(?: *- +\\)+" + "\\(?:" yaml-bare-scalar-re " *:\\(?: +.*\\)?\\)?$") + "Regexp matching a line containing one or more nested YAML sequences.") + +(defconst yaml-constant-scalars-re + (concat "\\(?:^\\|\\(?::\\|-\\|,\\|{\\|\\[\\) +\\) *" + (regexp-opt + '("~" "null" "Null" "NULL" + ".nan" ".NaN" ".NAN" + ".inf" ".Inf" ".INF" + "-.inf" "-.Inf" "-.INF" + "y" "Y" "yes" "Yes" "YES" "n" "N" "no" "No" "NO" + "true" "True" "TRUE" "false" "False" "FALSE" + "on" "On" "ON" "off" "Off" "OFF") t) + " *$") + "Regexp matching certain scalar constants in scalar context.") + + +;; Mode setup + +(defvar yaml-mode-map () + "Keymap used in `yaml-mode' buffers.") +(if yaml-mode-map + nil + (setq yaml-mode-map (make-sparse-keymap)) + (define-key yaml-mode-map "|" 'yaml-electric-bar-and-angle) + (define-key yaml-mode-map ">" 'yaml-electric-bar-and-angle) + (define-key yaml-mode-map "-" 'yaml-electric-dash-and-dot) + (define-key yaml-mode-map "." 'yaml-electric-dash-and-dot) + (define-key yaml-mode-map [backspace] 'yaml-electric-backspace) + (define-key yaml-mode-map "\C-j" 'newline-and-indent)) + +(defvar yaml-mode-syntax-table nil + "Syntax table in use in `yaml-mode' buffers.") +(if yaml-mode-syntax-table + nil + (setq yaml-mode-syntax-table (make-syntax-table)) + (modify-syntax-entry ?\' "\"" yaml-mode-syntax-table) + (modify-syntax-entry ?\" "\"" yaml-mode-syntax-table) + (modify-syntax-entry ?# "<" yaml-mode-syntax-table) + (modify-syntax-entry ?\n ">" yaml-mode-syntax-table) + (modify-syntax-entry ?\\ "\\" yaml-mode-syntax-table) + (modify-syntax-entry ?- "w" yaml-mode-syntax-table) + (modify-syntax-entry ?_ "_" yaml-mode-syntax-table) + (modify-syntax-entry ?\( "." yaml-mode-syntax-table) + (modify-syntax-entry ?\) "." yaml-mode-syntax-table) + (modify-syntax-entry ?\{ "(}" yaml-mode-syntax-table) + (modify-syntax-entry ?\} "){" yaml-mode-syntax-table) + (modify-syntax-entry ?\[ "(]" yaml-mode-syntax-table) + (modify-syntax-entry ?\] ")[" yaml-mode-syntax-table)) + +;;;###autoload +(define-derived-mode yaml-mode fundamental-mode "YAML" + "Simple mode to edit YAML. + +\\{yaml-mode-map}" + (set (make-local-variable 'comment-start) "# ") + (set (make-local-variable 'comment-start-skip) "#+ *") + (set (make-local-variable 'indent-line-function) 'yaml-indent-line) + (set (make-local-variable 'indent-tabs-mode) nil) + (set (make-local-variable 'font-lock-defaults) + '(yaml-font-lock-keywords + nil nil nil nil + (font-lock-syntactic-keywords . yaml-font-lock-syntactic-keywords)))) + + +;; Font-lock support + +(defvar yaml-font-lock-keywords + (list + (cons yaml-comment-re '(1 font-lock-comment-face)) + (cons yaml-constant-scalars-re '(1 font-lock-constant-face)) + (cons yaml-tag-re '(0 font-lock-type-face)) + (cons yaml-node-anchor-alias-re '(0 font-lock-function-name-face t)) + (cons yaml-hash-key-re '(1 font-lock-variable-name-face t)) + (cons yaml-document-delimiter-re '(0 font-lock-comment-face)) + (cons yaml-directive-re '(1 font-lock-builtin-face)) + '(yaml-font-lock-block-literals 0 font-lock-string-face t) + '("^[\t]+" 0 'yaml-tab-face t)) + "Additional expressions to highlight in YAML mode.") + +(defvar yaml-font-lock-syntactic-keywords + (list '(yaml-syntactic-block-literals 0 "." t)) + "Additional syntax features to highlight in YAML mode.") + + +(defun yaml-font-lock-block-literals (bound) + "Find lines within block literals. +Find the next line of the first (if any) block literal after point and +prior to BOUND. Returns the beginning and end of the block literal +line in the match data, as consumed by `font-lock-keywords' matcher +functions. The function begins by searching backwards to determine +whether or not the current line is within a block literal. This could +be time-consuming in large buffers, so the number of lines searched is +artificially limitted to the value of +`yaml-block-literal-search-lines'." + (if (eolp) (goto-char (1+ (point)))) + (unless (or (eobp) (>= (point) bound)) + (let ((begin (point)) + (end (min (1+ (point-at-eol)) bound))) + (goto-char (point-at-bol)) + (while (and (looking-at yaml-blank-line-re) (not (bobp))) + (forward-line -1)) + (let ((nlines yaml-block-literal-search-lines) + (min-level (current-indentation))) + (forward-line -1) + (while (and (/= nlines 0) + (/= min-level 0) + (not (looking-at yaml-block-literal-re)) + (not (bobp))) + (set 'nlines (1- nlines)) + (unless (looking-at yaml-blank-line-re) + (set 'min-level (min min-level (current-indentation)))) + (forward-line -1)) + (cond + ((and (< (current-indentation) min-level) + (looking-at yaml-block-literal-re)) + (goto-char end) (set-match-data (list begin end)) t) + ((progn + (goto-char begin) + (re-search-forward (concat yaml-block-literal-re + " *\\(.*\\)\n") + bound t)) + (set-match-data (nthcdr 2 (match-data))) t)))))) + +(defun yaml-syntactic-block-literals (bound) + "Find quote characters within block literals. +Finds the first quote character within a block literal (if any) after +point and prior to BOUND. Returns the position of the quote character +in the match data, as consumed by matcher functions in +`font-lock-syntactic-keywords'. This allows the mode to treat ['\"] +characters in block literals as punctuation syntax instead of string +syntax, preventing unmatched quotes in block literals from painting +the entire buffer in `font-lock-string-face'." + (let ((found nil)) + (while (and (not found) + (/= (point) bound) + (yaml-font-lock-block-literals bound)) + (let ((begin (match-beginning 0)) (end (match-end 0))) + (goto-char begin) + (cond + ((re-search-forward "['\"]" end t) (setq found t)) + ((goto-char end))))) + found)) + + +;; Indentation and electric keys + +(defun yaml-compute-indentation () + "Calculate the maximum sensible indentation for the current line." + (save-excursion + (beginning-of-line) + (if (looking-at yaml-document-delimiter-re) 0 + (forward-line -1) + (while (and (looking-at yaml-blank-line-re) + (> (point) (point-min))) + (forward-line -1)) + (+ (current-indentation) + (if (looking-at yaml-nested-map-re) yaml-indent-offset 0) + (if (looking-at yaml-nested-sequence-re) yaml-indent-offset 0) + (if (looking-at yaml-block-literal-re) yaml-indent-offset 0))))) + +(defun yaml-indent-line () + "Indent the current line. +The first time this command is used, the line will be indented to the +maximum sensible indentation. Each immediately subsequent usage will +back-dent the line by `yaml-indent-offset' spaces. On reaching column +0, it will cycle back to the maximum sensible indentation." + (interactive "*") + (let ((ci (current-indentation)) + (cc (current-column)) + (need (yaml-compute-indentation))) + (save-excursion + (beginning-of-line) + (delete-horizontal-space) + (if (and (equal last-command this-command) (/= ci 0)) + (indent-to (* (/ (- ci 1) yaml-indent-offset) yaml-indent-offset)) + (indent-to need))) + (if (< (current-column) (current-indentation)) + (forward-to-indentation 0)))) + +(defun yaml-electric-backspace (arg) + "Delete characters or back-dent the current line. +If invoked following only whitespace on a line, will back-dent to the +immediately previous multiple of `yaml-indent-offset' spaces." + (interactive "*p") + (if (or (/= (current-indentation) (current-column)) (bolp)) + (funcall yaml-backspace-function arg) + (let ((ci (current-column))) + (beginning-of-line) + (delete-horizontal-space) + (indent-to (* (/ (- ci (* arg yaml-indent-offset)) + yaml-indent-offset) + yaml-indent-offset))))) + +(defun yaml-electric-bar-and-angle (arg) + "Insert the bound key and possibly begin a block literal. +Inserts the bound key. If inserting the bound key causes the current +line to match the initial line of a block literal, then inserts the +matching string from `yaml-block-literal-electric-alist', a newline, +and indents appropriately." + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (let ((extra-chars + (assoc last-command-event + yaml-block-literal-electric-alist))) + (cond + ((and extra-chars (not arg) (eolp) + (save-excursion + (beginning-of-line) + (looking-at yaml-block-literal-re))) + (insert (cdr extra-chars)) + (newline-and-indent))))) + +(defun yaml-electric-dash-and-dot (arg) + "Insert the bound key and possibly de-dent line. +Inserts the bound key. If inserting the bound key causes the current +line to match a document delimiter, de-dent the line to the left +margin." + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + (save-excursion + (beginning-of-line) + (if (and (not arg) (looking-at yaml-document-delimiter-re)) + (delete-horizontal-space)))) + + +(defun yaml-set-imenu-generic-expression () + (make-local-variable 'imenu-generic-expression) + (make-local-variable 'imenu-create-index-function) + (setq imenu-create-index-function 'imenu-default-create-index-function) + (setq imenu-generic-expression yaml-imenu-generic-expression)) + +(add-hook 'yaml-mode-hook 'yaml-set-imenu-generic-expression) + + +(defun yaml-mode-version () + "Diplay version of `yaml-mode'." + (interactive) + (message "yaml-mode %s" yaml-mode-version) + yaml-mode-version) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.ya?ml$" . yaml-mode)) + +(provide 'yaml-mode) + +;;; yaml-mode.el ends here diff --git a/yaml-mode.elc b/yaml-mode.elc new file mode 100644 index 0000000000000000000000000000000000000000..013f0c498c9e06b79ff5f316e110bf0472f02f6f GIT binary patch literal 13043 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 literal 0 HcmV?d00001 -- 2.47.3