yaml-mode-expansions.el (7393B)
1 ;;; yaml-mode-expansions.el --- expansions for yaml mode -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2021-2023 Free Software Foundation, Inc. 4 5 ;; Author: Aaron Gonzales 6 ;; Keywords: marking region yaml YAML expand 7 8 ;; This program is free software; you can redistribute it and/or modify 9 ;; it under the terms of the GNU General Public License as published by 10 ;; the Free Software Foundation, either version 3 of the License, or 11 ;; (at your option) any later version. 12 13 ;; This program is distributed in the hope that it will be useful, 14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 ;; GNU General Public License for more details. 17 18 ;; You should have received a copy of the GNU General Public License 19 ;; along with this program. If not, see <http://www.gnu.org/licenses/>. 20 21 ;;; Commentary: 22 ;; 23 ;; - Additions implemented here: 24 ;; - er/mark-yaml-key-value 25 ;; - er/mark-yaml-list-item 26 ;; - er/mark-yaml-block 27 ;; - er/mark-yaml-outer-block 28 ;; - er/mark-yaml-inner-block 29 30 31 ;;; Code: 32 33 (require 'expand-region-core) 34 35 (defconst yaml-indent 2) 36 37 (unless (fboundp 'yaml-indent-offset) 38 (defalias 'yaml-indent-offset #'yaml-indent)) 39 40 (defvar er--yaml-key-value-regex 41 (rx (one-or-more 42 (any "0-9A-Za-z")) 43 ":" 44 (zero-or-more " ") 45 (one-or-more 46 (any "0-9A-Za-z" " '_-")))) 47 48 (defvar er--yaml-list-item-regex 49 (rx (seq "- " 50 (one-or-more 51 (any "0-9A-Za-z" "\"':=_-"))))) 52 53 (defvar er--yaml-block-regex 54 (rx (seq (zero-or-more 55 (any " -")) 56 (one-or-more 57 (any "0-9A-Za-z" " '_-")) 58 ":\n"))) 59 60 (defun er--get-regex-indentation-level (regex) 61 "Return the indentation level of the code with respect to the REGEX passed." 62 (when (looking-at regex) 63 ;; Block start means that the next level is deeper. 64 (+ (current-indentation) yaml-indent-offset) ;FIXME: Unused? 65 ;; Assuming we're inside the block that we want to mark 66 (current-indentation))) 67 68 (defun er/mark-yaml-line-base (regex) 69 "Mark line of yaml file based on simple REGEX." 70 (back-to-indentation) 71 (when (looking-at regex) 72 (set-mark (line-end-position)))) 73 74 (defun er/mark-yaml-block-static-base (regex) 75 "Mark yaml block based on REGEX passed." 76 ;; go bac to indentation so always can get regexp 77 (back-to-indentation) 78 ;; make sure the cursor is set inside the block 79 ;; mark point at this higher code block 80 (set-mark (point)) 81 ;; save level of this blocks indentation 82 (let ((block-indentation (current-indentation))) 83 (forward-line 1) 84 (while (and 85 ;; No need to go beyond the end of the buffer. Can't use 86 ;; eobp as the loop places the point at the beginning of 87 ;; line, but eob might be at the end of the line. 88 (not (= (point-max) (line-end-position))) 89 ;; Proceed if: indentation is too deep 90 (or (> (current-indentation) block-indentation) 91 ;; Looking at an empty line 92 (looking-at (rx line-start (* whitespace) line-end)) 93 ;; We're not looking at the start of a YAML block 94 ;; and the indent is deeper than the block's indent 95 (and (not (looking-at regex)) 96 (> (current-indentation) block-indentation)))) 97 (forward-line 1) 98 (back-to-indentation)) 99 ;; Find the end of the block by skipping comments backwards 100 (python-util-forward-comment -1) 101 (exchange-point-and-mark)) 102 (back-to-indentation)) 103 104 (defun er/mark-yaml-block-base (regex &optional next-indent-level) 105 "Mark yaml block based on REGEX passed. 106 NEXT-INDENT-LEVEL can be used to search outer blocks when necessary." 107 ;; go bac to indentation so always can get regexp 108 (back-to-indentation) 109 ;; make sure the cursor is set inside the block 110 (let ((next-indent-level 111 (or 112 ;; Use the given level 113 next-indent-level 114 ;; used to mark current block 115 (er--get-regex-indentation-level regex)))) 116 ;; if true then at start of block and wanna mark itself 117 ;; else were are inside the block already and will mark it))) 118 ;; move up the code unti a parent code block is reached 119 (while (and (>= (current-indentation) next-indent-level) 120 (not (eq (current-indentation) 0))) 121 (re-search-backward regex (point-min) t) 122 (back-to-indentation)) 123 ;; mark point at this higher code block 124 (set-mark (point)) 125 ;; save level of this blocks indentation 126 (let ((block-indentation (current-indentation))) 127 (forward-line 1) 128 (while (and 129 ;; No need to go beyond the end of the buffer. Can't use 130 ;; eobp as the loop places the point at the beginning of 131 ;; line, but eob might be at the end of the line. 132 (not (= (point-max) (line-end-position))) 133 ;; Proceed if: indentation is too deep 134 (or (> (current-indentation) block-indentation) 135 ;; Looking at an empty line 136 (looking-at (rx line-start (* whitespace) line-end)) 137 ;; We're not looking at the start of a YAML block 138 ;; and the indent is deeper than the block's indent 139 (and (not (looking-at regex)) 140 (> (current-indentation) block-indentation)))) 141 (forward-line 1) 142 (back-to-indentation)) 143 ;; Find the end of the block by skipping comments backwards 144 (python-util-forward-comment -1) 145 (exchange-point-and-mark))) 146 (back-to-indentation)) 147 148 (defun er/mark-yaml-key-value () 149 "Mark a yaml key-value pair." 150 (interactive) 151 (er/mark-yaml-line-base er--yaml-key-value-regex)) 152 153 (defun er/mark-yaml-list-item () 154 "Mark a yaml list item." 155 (interactive) 156 (er/mark-yaml-line-base er--yaml-list-item-regex)) 157 158 (defun er/mark-yaml-inner-block () 159 "Mark the yaml contents of the block at point. 160 Command that wraps `er/mark-yaml-block-base'." 161 (interactive) 162 (er/mark-yaml-block-base er--yaml-block-regex (current-indentation)) 163 (forward-line) 164 (back-to-indentation)) 165 166 (defun er/mark-yaml-block () 167 "Mark the yaml block that point is currently at the top of. 168 Command that wraps `er/mark-yaml-block-base'." 169 (interactive) 170 (er/mark-yaml-block-static-base er--yaml-block-regex)) 171 172 (defun er/mark-yaml-outer-block () 173 "Mark the outer yaml block that surrounds the block around point. 174 Command that wraps `er/mark-yaml-block-base'." 175 (interactive) 176 (er/mark-yaml-block-base er--yaml-block-regex (current-indentation))) 177 178 (defun er/add-yaml-mode-expansions () 179 "Add yaml-mode-specific expansions for buffers in yaml-mode." 180 (let ((try-expand-list-additions '(er/mark-symbol 181 er/mark-outside-quotes 182 er/mark-yaml-list-item 183 er/mark-yaml-key-value 184 er/mark-yaml-block 185 er/mark-yaml-outer-block 186 er/mark-yaml-inner-block))) 187 (set (make-local-variable 'expand-region-skip-whitespace) nil) 188 (set (make-local-variable 'er/try-expand-list) try-expand-list-additions))) 189 190 (er/enable-mode-expansions 'yaml-mode #'er/add-yaml-mode-expansions) 191 192 (provide 'yaml-mode-expansions) 193 194 ;;; yaml-mode-expansions.el ends here