branch: scratch/expand-region commit 51e0740e1f61f29bd64acd1afd83343a7168ba14 Author: Magnar Sveen <magn...@gmail.com> Commit: Magnar Sveen <magn...@gmail.com>
Revert "Revert "feat: add `yaml-mode` expansions"" This reverts commit 09ebc2df5ce3aac05e82367b2e42e7d0f3ff1656. --- expand-region.el | 1 + yaml-mode-expansions.el | 156 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/expand-region.el b/expand-region.el index 1c6d4b44b6..de8630eafb 100644 --- a/expand-region.el +++ b/expand-region.el @@ -190,6 +190,7 @@ before calling `er/expand-region' for the first time." (eval-after-load 'sml-mode '(require 'sml-mode-expansions)) (eval-after-load 'enh-ruby-mode '(require 'enh-ruby-mode-expansions)) (eval-after-load 'subword '(require 'subword-mode-expansions)) +(eval-after-load 'yaml-mode '(require 'yaml-mode-expansions)) (provide 'expand-region) diff --git a/yaml-mode-expansions.el b/yaml-mode-expansions.el new file mode 100644 index 0000000000..a9c90d3b4d --- /dev/null +++ b/yaml-mode-expansions.el @@ -0,0 +1,156 @@ +;;; yaml-mode-expansions.el --- expansions for yaml mode + +;; Copyright (C) 2021 Aaron Gonzales + +;; Author: Aaron Gonzales +;; Keywords: marking region yaml YAML expand + +;; 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 of the License, 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. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; - Additions implemented here: +;; - er/mark-yaml-key-value +;; - er/mark-yaml-list-item +;; - er/mark-yaml-block + +;;; Code: + +(require 'expand-region-core) + +(defconst yaml-indent 2) + +(if (not (fboundp 'yaml-indent-offset)) + (defalias 'yaml-indent-offset 'yaml-indent)) + +(defvar er--yaml-key-value-regex + (rx (one-or-more + (any "0-9A-Za-z")) + ":" + (zero-or-more " ") + (one-or-more + (any "0-9A-Za-z" " '_-")))) + +(defvar er--yaml-list-item-regex + (rx (seq "- " + (one-or-more + (any "0-9A-Za-z" " '_-")) + "\n"))) + +(defvar er--yaml-block-regex + (rx (seq (zero-or-more + (any " -")) + (one-or-more + (any "0-9A-Za-z" " '_-")) + ":\n"))) + +(defun er--get-regex-indentation-level (regex) + "Return the indentation level of the code with respect to the REGEX passed." + (if (looking-at regex) + ;; Block start means that the next level is deeper. + (+ (current-indentation) yaml-indent-offset) + ;; Assuming we're inside the block that we want to mark + (current-indentation))) + +(defun er/mark-yaml-line-base (regex) + "Mark line of yaml file based on simple REGEX." + (back-to-indentation) + (if (looking-at regex) + (set-mark (line-end-position)))) + +(defun er/mark-yaml-block-base (regex &optional next-indent-level) + "Mark yaml block based on REGEX passed. NEXT-INDENT-LEVEL can be used to search outer blocks when necessary." + (back-to-indentation) + ;; make sure the cursor is set inside the block + (let ((next-indent-level + (or + ;; Use the given level + next-indent-level + ;; used to mark current block + ;; if true then at start of block and wanna mark itself + ;; else were are inside the block already and will mark it))) + ;; move up the code unti a parent code block is reached + (er--get-regex-indentation-level regex)))) + (while (and (>= (current-indentation) next-indent-level) + (not (eq (current-indentation) 0))) + (re-search-backward regex (point-min) t) + (back-to-indentation)) + ;; mark point at this higher code block + (set-mark (point)) + ;; save level of this blocks indentation + (let ((block-indentation (current-indentation))) + (forward-line 1) + (while (and + ;; No need to go beyond the end of the buffer. Can't use + ;; eobp as the loop places the point at the beginning of + ;; line, but eob might be at the end of the line. + (not (= (point-max) (point-at-eol))) + ;; Proceed if: indentation is too deep + (or (> (current-indentation) block-indentation) + ;; Looking at an empty line + (looking-at (rx line-start (* whitespace) line-end)) + ;; We're not looking at the start of a Python block + ;; and the indent is deeper than the block's indent + (and (not (looking-at regex)) + (> (current-indentation) block-indentation)))) + (forward-line 1) + (back-to-indentation)) + ;; Find the end of the block by skipping comments backwards + (python-util-forward-comment -1) + (exchange-point-and-mark))) + (back-to-indentation)) + +(defun er/mark-yaml-key-value () + "Mark a yaml key-value pair." + (interactive) + (er/mark-yaml-line-base er--yaml-key-value-regex)) + +(defun er/mark-yaml-list-item () + "Mark a yaml list item." + (interactive) + (er/mark-yaml-line-base er--yaml-list-item-regex)) + +(defun er/mark-yaml-block () + "Mark the yaml block that surrounds the block around point. + +Command that wraps `er/mark-yaml-block-base'." + (interactive) + (er/mark-yaml-block-base er--yaml-block-regex)) + +(defun er/mark-outer-yaml-block () + "Mark the outer yaml block that surrounds the block around point. + +Command that wraps `er/mark-yaml-block-base'." + (interactive) + (er/mark-yaml-block-base er--yaml-block-regex (current-indentation))) + +(defun er/add-yaml-mode-expansions () + "Add yaml-mode-specific expansions for buffers in yaml-mode." + (let ((try-expand-list-additions '( + er/mark-symbol + er/mark-outside-quotes + er/mark-yaml-list-item + er/mark-yaml-key-value + er/mark-yaml-block + er/mark-outer-yaml-block + mark-page))) + (set (make-local-variable 'expand-region-skip-whitespace) nil) + (set (make-local-variable 'er/try-expand-list) + (append try-expand-list-additions er/try-expand-list)))) + +(er/enable-mode-expansions 'yaml-mode 'er/add-yaml-mode-expansions) + +(provide 'yaml-mode-expansions) + +;;; yaml-mode-expansions.el ends here