~sirn/poly-yaml-mode

58aa54287cfe53a35d6d125961cae8e04b3ecce3 — Kridsada Thanabulpong 4 years ago
Initial commit
2 files changed, 173 insertions(+), 0 deletions(-)

A README.md
A poly-yaml-mode.el
A  => README.md +38 -0
@@ 1,38 @@
# poly-yaml-mode

YAML multiple major modes for [polymode](https://polymode.github.io/)

### Caveats

- Pretty much WIP, here be dragons
- Only works with YAML quoted string or literal YAML block
- Can get confused by YAML block that first line ended with a quote

## Polymodes

### poly-yaml+sh-mode

Polymode for shell script within YAML string, e.g.

```yaml
foo:
  baz: 'echo "Hello, world!"'
  bar: |
    #!/bin/sh
    echo "Hello, world!"
```

### poly-yaml+jinja2-mode

Polymode for Jinja2 within YAML string, e.g.

```yaml
foo:
  baz: "Hello, {{name}}"
  bar: |
    Hello, {{name}}
```

### poly-yaml+ansible-mode

Special mode that activates `ansible` minor mode alongside `poly-yaml+jinja2-mode`.

A  => poly-yaml-mode.el +135 -0
@@ 1,135 @@
;;; poly-yaml-mode.el --- Various polymodes for YAML -*- lexical-binding: t -*-
;;
;; Author: Kridsada Thanabulpong
;; Maintainer: Kridsada Thanabulpong
;; Copyright (C) 2019 Kridsada Thanabulpong
;; Version: 0.2
;; Package-Requires: ((emacs "25") (polymode "0.2"))
;; URL: https://git.sr.ht/~sirn/poly-yaml
;; Keywords: languages, multi-modes
;;
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; This file is *NOT* part of GNU Emacs.
;;
;; 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, 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; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;;
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
;;
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Code:

(require 'polymode)
(require 'yaml-mode)

(defgroup poly-yaml nil
  "Settings for poly-yaml polymodes"
  :group 'polymode)

(defconst poly-yaml-string-head-re
  (rx (* nonl) (any ":" "-") (+ blank)
      (submatch (or "\"" "'" (and "|" (*? blank) (? "\r") "\n"))))
  "Regex matching the start of a string context into the first group.")

(defconst poly-yaml-string-tail-re
  (rx (* nonl) (submatch (any "\"" "'")) (* blank)
      eol)
  "Regex matching the end of a string context into the first group.")

(defconst poly-yaml-string-head-matcher
  (cons poly-yaml-string-head-re 1)
  "Matcher matching the start of a string context.")

(defun poly-yaml-string-tail-fn (_arg)
  "Get the end position of a string depending the beginning fo the the string
context. Indentation levels are used to determine the end of YAML literal
block. Used as a tail matcher for `poly-innermode'."
  ;; Roughly a copy of `pm-same-indent-tail-matcher' with few difference:
  ;; 1. handling of a single-line string
  ;; 2. assumes point is always at the code block rather than head end
  (let* ((cur-pos (point))
         (cur-indent (1- (current-indentation)))
         (end (point-at-eol)))
    (if (looking-at-p poly-yaml-string-tail-re)
        (progn
          (re-search-forward poly-yaml-string-tail-re nil t)
          (cons (match-beginning 1)
                (match-end 1)))
      (progn
        (forward-line 1)
        (while (and (not (eobp))
                    (or (looking-at-p (rx (*? blank "\t") eol))
                        (and (> (current-indentation) cur-indent)
                             (setq end (point-at-eol)))))
          (forward-line 1))
        (setq end (min (point-max) (1+ end)))
        (cons end end)))))

(defconst poly-yaml-string-tail-matcher
  #'poly-yaml-string-tail-fn
  "Matcher matching the end of a string context.")


;;; ROOT POLYMODE

(defcustom poly-yaml-root-polymode
  (pm-polymode :name "yaml"
               :hostmode 'poly-yaml-hostmode
               :innermodes '(pm-inner/fundamental))
  "Root polymode with YAML host intended to be inherited from."
  :group 'polymode)


;;; POLYMODES
;;
;; poly-yaml+jinja2

(define-innermode poly-yaml-jinja2-innermode
  :mode 'jinja2-mode
  :head-matcher poly-yaml-string-head-matcher
  :tail-matcher poly-yaml-string-tail-matcher
  :head-mode 'host
  :tail-mode 'host)

(define-polymode poly-yaml+jinja2-mode poly-yaml-root-polymode
  :innermodes '(poly-yaml-jinja2-innermode))

;; poly-yaml+sh

(define-innermode poly-yaml-sh-innermode
  :mode 'sh-mode
  :head-matcher poly-yaml-string-head-matcher
  :tail-matcher poly-yaml-string-tail-matcher
  :head-mode 'host
  :tail-mode 'host)

(define-polymode poly-yaml+sh-mode poly-yaml-root-polymode
  :innermodes '(poly-yaml-sh-innermode))

;; poly-yaml+ansible

(define-polymode poly-yaml+ansible-mode poly-yaml+jinja2-mode
  (require 'ansible)
  (require 'ansible-doc)
  (ansible 1)
  (ansible-doc-mode 1))


(provide 'poly-yaml-mode)
;;; poly-yaml-mode.el ends here