通过缩进选择 Emacs

Emacs selection by indentation

在 Sublime Text 中,可以 select 基于缩进的代码块: (Selection -> Expand Selection to Indentation)

例如在下面的代码块中,光标所在的位置是 此处标记:

<header>
    <nav>
        <ul>
            <li id='link-main'><a href='#'>Main site</a></li>
            <li class='stupid'><a href='#'>About Us</a></li>
            <li class='stupid'><a href="#">History</a></li>
            <a href="random link"></a><CURSOR_HERE>
            <div>
                <div>
                </div>
            </div>
            <li><a href="#">Contact</a></li>
        </ul>
    </nav>  
</header>

这将导致此 select离子(由 <SELECTION></SELECTION> 标记)

<header>
    <nav>
        <ul>
 <SELECTION><li id='link-main'><a href='#'>Main site</a></li>
            <li class='stupid'><a href='#'>About Us</a></li>
            <li class='stupid'><a href="#">History</a></li>
            <a href="random link"></a>
            <div>
                <div>
                </div>
            </div>
            <li><a href="#">Contact</a></li></SELECTION>
        </ul>
    </nav>  
</header>

如何使用 emacs 实现相同的目的?

我不知道基于缩进的选择,但是expand region 进行语义扩展:

Expand region increases the selected region by semantic units. Just keep pressing the key until it selects what you want.

扩展区域为 available on MELPA

如果您使用 Evil, here's an evil plugin evil-indent-textobject 可以 select(或 yank/delete)基于缩进的块。

(defun ar-backward-indent ()
  "Go backward same or deeper levels of indentation. "
  (interactive)
  (let ((orig (point))
    (indent (progn (back-to-indentation) (current-column)))
    (last (point)))
    (while (and (not (bobp))(forward-line -1) (progn (back-to-indentation) (<= indent (current-indentation))))
      (setq last (point)))
    (goto-char last)))

(defun ar-forward-indent ()
  "Go backward same or deeper levels of indentation. "
  (interactive)
  (let ((indent (progn (back-to-indentation) (current-column)))
    last)
    (while
    (and (not (eobp)) (forward-line 1) (progn (back-to-indentation) (<= indent (current-indentation))))
      (setq last (line-end-position)))
    (goto-char last)))

(defun ar-mark-indent-level ()
  "Mark lines around point where indentation is equal or deeper. "
  (interactive)
  (let ((orig (point)))
    (ar-backward-indent)
    (push-mark (point) t)
    (goto-char orig)
    (ar-forward-indent)))

来源:https://github.com/andreas-roehler/subroutines

首先我们必须检查点是否在缩进为 0 的行上,是否是 select 整个缓冲区。

如果点在有一些缩进的行上,select所有具有相同或更少缩进的行。

(defun expand-to-indentation ()
  "Select surrounding lines with current indentation."
  (interactive)
  (let ((indentation (current-indentation)))
    (if (= indentation 0)
        (mark-whole-buffer)
      (while (<= indentation (current-indentation))
        (forward-line -1))
      (forward-line 1)
      (push-mark (point) nil t)
      (while (<= indentation (current-indentation))
        (forward-line 1))   
      (backward-char))))

您可以交互调用此函数,也可以将其绑定到任何键。

根据@ChillarAnand 的回答,我自己使用以下内容:

(defun mark-current-indentation (&optional ARG)
  "Select surrounding lines with current indentation.
if ARG is 'C-u', mark forward; if ARG is 'C-u C-u', mark backward."
  (interactive "P")
  (let ((is-forward (not (equal ARG '(16))))
        (is-backward (not (equal ARG '(4))))
        (indentation (if (not (current-line-empty-p))
                         (current-indentation)
                       (skip-chars-forward "\s\t\n")
                       (current-indentation))))
    (if (= indentation 0)
        (mark-whole-buffer)
      (if (not is-forward) (push-mark (point) nil t))
      (while (and (not (bobp)) is-backward
                  (or (current-line-empty-p) (<= indentation (current-indentation))))
        (forward-line -1))
      (if is-backward (forward-line 1) (move-beginning-of-line nil))
      (if (not (use-region-p)) (push-mark (point) nil t))
      (while (and (not (eobp)) is-forward
                  (or (current-line-empty-p) (<= indentation (current-indentation))))
        (forward-line 1))
      (if is-forward (backward-char)))))