들여 쓰기로 탐색


15

들여 쓰기를 기준으로 파일 줄 사이를 탐색하고 싶습니다. 파일은 들여 쓰기로 구성됩니다. 이전 줄보다 들여 쓰기 된 줄은 이전 줄의 자식이며 이전 줄과 동일한 들여 쓰기가있는 줄은 형제입니다. 나는 주로 세 가지 명령을 찾고 있습니다.

  • 다음 형제, 즉 들여 쓰기가 동일한 다음 줄로 이동합니다. 더 들여 쓰기 된 줄은 건너 뛰지 만 덜 들여 쓰기 된 줄은 건너 뛰지 않습니다.
  • 이전 형제, 즉 다른 방향으로 같은 것으로 이동하십시오.
  • 부모, 즉 들여 쓰기가 적은 이전 줄로 이동하십시오.

점의 열 위치는 바뀌지 않아야합니다.

여기에 압입 구조화 데이터 유사체이다 forward-sexp, backward-sexp및 backward-up-listsexp 구조화 데이터. 들여 쓰기는 Haskell 및 Python과 같은 언어의 프로그램 구조에 해당합니다. 이러한 기능은이 맥락에서 특히 유용 할 수 있지만 모드별로 아무것도 찾지 않습니다 (주요 사용 사례는 다른 파일 형식의 의도 구조화 된 데이터입니다).

채색 들여 쓰기 수준 은 Up/ 를 사용하여 수동으로 탐색하는 데 도움이 될 수 Down있지만 자동으로 원합니다.

이 수퍼 유저 질문 은 비슷하지만 요구 사항이 약하며 현재 내 요구 사항에 맞는 답변이 없습니다.


set-selective-display필요한 것에 가까이 가나 요?
— Kaushal Modi

1
@KaushalModi 유용하고, 이것에 대해 몰랐으므로 감사합니다. 그러나 항상 필요한 것은 아닙니다. 바로 지금, 나는 움직이고있는 선의 아이들을보고 싶었습니다.
— Gilles 'SO- 악마 그만

이 질문을 해주셔서 감사합니다. 나는 기본적으로 같은 질문을 덜 잘합니다. 내가 원하는 유일한 추가 사항은 "최종 형제 자매로 이동"입니다. 즉, 들여 쓰기가 적은 줄은 건너 뛰지 않고 같은 들여 쓰기가있는 마지막 줄입니다. (아무것도 없을 때까지 "다음 형제로 이동"을 반복하는 것과 같습니다.)
— ShreevatsaR

방금 indent-toolsmelpa ( indent-tools ) 패키지 를 보았습니다. 이 패키지 는 아마도이 목적으로 작동합니다. 첫 번째 커밋은 2016 년 5 월 16 일에이 질문을 한 후 약 3 개월이 지났습니다.
— ShreevatsaR

답변:


4

현재 사용 가능한 4 가지 답변 ( 수퍼 유저 2 명,이 질문 2 명)을 검토하면 다음과 같은 문제가 나타납니다.

  • 스테판과 펭 바이로 슈퍼 유저에 사람은 , 현재 열 위치를 유지하고 부모까지 이동 구현하지 않는 (현재 들여보고, 줄 단위 이동)
  • Dan 의 대답 (동일한 들여 쓰기가있는 다음 줄을 찾기 위해 re-search-forward 사용)은 들여 쓰기가 적은 줄을 건너 뜁니다. 다음 형제가 없는지 알지 못하므로 형제가 아닌 것으로 이동할 수 있습니다. 그러나 다른 부모의 아이… 아마 다음 "사촌".
  • Gilles 의 답변 (개요 모드 사용)은 열 위치를 유지하지 않으며 들여 쓰기가없는 줄 ( "최상위"줄)에서는 작동하지 않습니다. 또한의 코드를 살펴보면 outline.el기본적으로 어쨌든 outline-next-visible-heading모든 행이 개요 정규 표현식과 일치하고 "제목"으로 계산되므로 기본적으로 어쨌든 한 줄씩 이동합니다 .

그래서, 각각의 아이디어를 모아서 다음과 같은 것을 가지고 있습니다. 들여 쓰기가 동일하면 다음 형제입니다. 기본 아이디어는 다음과 같습니다.

(defun indentation-get-next-sibling-line ()
  "The line number of the next sibling, or nil if there isn't any."
  (let ((wanted-indentation (current-indentation)))
    (save-excursion
      (while (and (zerop (forward-line))  ; forward-line returns 0 on success
               (or (eolp)  ; Skip past blank lines and more-indented lines
                 (> (current-indentation) wanted-indentation))))
      ;; Now we can't go further. Which case is it?
      (if (and (not (eobp)) (= (current-indentation) wanted-indentation))
        (line-number-at-pos)
        nil))))

(defun indentation-forward-to-next-sibling ()
  (interactive)
  (let ((saved-column (current-column)))
    (forward-line (- (indentation-get-next-sibling-line) (line-number-at-pos)))
    (move-to-column saved-column)))

적절하게 일반화 (앞으로 / 뒤로 / 위로 / 아래로), 내가 사용하는 것은 현재 다음과 같습니다.

(defun indentation-get-next-good-line (direction skip good)
  "Moving in direction `direction', and skipping over blank lines and lines that
satisfy relation `skip' between their indentation and the original indentation,
finds the first line whose indentation satisfies predicate `good'."
  (let ((starting-indentation (current-indentation))
         (lines-moved direction))
    (save-excursion
      (while (and (zerop (forward-line direction))
               (or (eolp)  ; Skip past blank lines and other skip lines
                 (funcall skip (current-indentation) starting-indentation)))
        (setq lines-moved (+ lines-moved direction)))
      ;; Now we can't go further. Which case is it?
      (if (and
            (not (eobp))
            (not (bobp))
            (funcall good (current-indentation) starting-indentation))
        lines-moved
        nil))))

(defun indentation-get-next-sibling-line ()
  "The line number of the next sibling, if any."
  (indentation-get-next-good-line 1 '> '=))

(defun indentation-get-previous-sibling-line ()
  "The line number of the previous sibling, if any"
  (indentation-get-next-good-line -1 '> '=))

(defun indentation-get-parent-line ()
  "The line number of the parent, if any."
  (indentation-get-next-good-line -1 '>= '<))

(defun indentation-get-child-line ()
  "The line number of the first child, if any."
  (indentation-get-next-good-line +1 'ignore '>))


(defun indentation-move-to-line (func preserve-column name)
  "Move the number of lines given by func. If not possible, use `name' to say so."
  (let ((saved-column (current-column))
          (lines-to-move-by (funcall func)))
    (if lines-to-move-by
      (progn
        (forward-line lines-to-move-by)
        (move-to-column (if preserve-column
                          saved-column
                          (current-indentation))))
      (message "No %s to move to." name))))

(defun indentation-forward-to-next-sibling ()
  "Move to the next sibling if any, retaining column position."
  (interactive "@")
  (indentation-move-to-line 'indentation-get-next-sibling-line t "next sibling"))

(defun indentation-backward-to-previous-sibling ()
  "Move to the previous sibling if any, retaining column position."
  (interactive "@")
  (indentation-move-to-line 'indentation-get-previous-sibling-line t "previous sibling"))

(defun indentation-up-to-parent ()
  "Move to the parent line if any."
  (interactive "@")
  (indentation-move-to-line 'indentation-get-parent-line nil "parent"))

(defun indentation-down-to-child ()
  "Move to the first child line if any."
  (interactive "@")
  (indentation-move-to-line 'indentation-get-child-line nil "child"))

여전히 더 많은 기능이 바람직하며, outline.el그 중 일부를 살펴보고 다시 구현 하면 도움이 될 수 있지만 지금은이 목적에 만족합니다.


@Gilles : 편집 해 주셔서 감사합니다! 같은 외모는 (current-line)뭔가이었다 misc-fns.el어떻게 든 약간의 일환으로 내 Aquamacs 설치에 가지고 oneonone.el라이브러리입니다.
— ShreevatsaR

6

이 기능은 Emacs에 있습니다. 아웃 라인 모드 는 문서에 레벨이있는 ​​표제 행을 포함하는 것으로 설명하고 레벨 사이를 이동할 수있는 기능이 있습니다. 모든 줄을 들여 쓰기를 반영하는 수준을 가진 제목 줄로 정의 할 수 있습니다 outline-regexp. 들여 쓰기로 설정 합니다. 보다 정확하게는 들여 쓰기와 공백이 아닌 첫 번째 문자를 포함합니다 (그리고 파일의 시작은 최상위 레벨입니다) \`\|\s-+\S-.

M-x load-libray outline RET
M-: (make-local-variable 'outline-regexp) RET
M-: (setq outline-regexp "\\`\\|\\s-+\\S-") RET
M-x outline-minor-mode RET

Emacs 22.1–24.3에서는 다음과 같이 단순화 할 수 있습니다.

M-x load-libray outline RET
M-1 M-x set-variable RET outline-regexp RET "\\`\\|\\s-+\\S-" RET
M-x outline-minor-mode RET

그런 다음 개요 모션 명령을 사용할 수 있습니다 .

  • C-C @ C-f( outline-forward-same-level) 다음 형제로 이동
  • C-C @ C-b( outline-backward-same-level) 이전 형제로 이동합니다.
  • C-C @ C-u( outline-up-heading) 부모로 이동합니다.

하나의 탭과 하나의 공백은 동일한 들여 쓰기 횟수에 포함됩니다. 탭과 공백이 혼합되어 있으면 적절하게 설정 tab-width하고을 호출하십시오untabify .

현재 주 모드에 개요 설정이 있으면 충돌 할 수 있습니다. 이 경우, 다수의 여러 주요 모드 솔루션 중 하나를 사용할 수 있습니다 . 가장 간단한 방법은 간접 버퍼 를 작성하고 이를 개요 주요 모드로 설정하는 것입니다. 개요 주요 모드에서 기본 키보드 단축키는 다음 C-c C-f과 같이 입력하는 것이 더 간단합니다 .


이것은 작동하는 것처럼 보이지만 실제로 어떤 이유로 든 작동하지 않습니다. M-x make-local-variable RET outline-regexp RET해당 변수를 허용하지 않으며`[No match]`만 표시합니다. 아직 더 신중하게 조사하지 마십시오.
— ShreevatsaR

@ShreevatsaR Emacs 24.4에서 호환되지 않는 변경 사항입니다. outline-regexp더 이상 커스텀이 아니며 대화식으로 쉽게 설정할 수 없습니다.
— Gilles 'SO- 악의를 멈춰라'

아주 좋아요 고맙습니다. 두 가지 사소한 문제가 있습니다 : 당신은 (I 수단 윤곽 - 정규 표현식에 대한 어떤 경기를 생각없이 들여 쓰기 라인) 최상위 수준에있는 경우 (1) 다음 어느 쪽도 앞으로 나 뒤로 작품, 그리고 어떤 이유로이 간다 까지 두 행 (2)이 다음 또는 이전 형제로 이동하면 행의 시작 (열 0)으로 이동하지만 열을 유지하는 것이 좋습니다. (질문에서 지정할 때) 두 가지 모두 개요 모드 자체의 제한 사항 일 수 있습니다.
— ShreevatsaR

5

최소한의 테스트를 거친 다음 3 가지 명령은 들여 쓰기 된 줄로 기본 탐색을 허용해야합니다. 코드 반복에 대한 사과.

(defun ind-forward-sibling ()
  "Move forward to the next sibling line with the same indentation."
  (interactive)
  (save-match-data
    (let ((col (current-column))
          (pad (progn
                 (back-to-indentation)
                 (current-column))))
      (end-of-line 1)
      (re-search-forward (concat "^\\s-\\{"
                                 (number-to-string pad)
                                 "\\}[^ ]") nil t)
      (move-to-column col))))

(defun ind-backward-sibling ()
  "Move backward to the next sibling line with the same indentation."
  (interactive)
  (save-match-data
    (let ((col (current-column))
          (pad (progn
                 (back-to-indentation)
                 (current-column))))
      (beginning-of-line 1)
      (re-search-backward (concat "^\\s-\\{"
                                 (number-to-string pad)
                                 "\\}[^ ]") nil t)
      (move-to-column col))))

(defun ind-up-parent ()
  "Move up to parent line with less indentation."
  (interactive)
  (save-match-data
    (let ((col (current-column))
          (pad (progn
                 (back-to-indentation)
                 (current-column))))
      (when (> pad 0)
        (beginning-of-line 1)
        (re-search-backward (concat "^\\s-\\{0,"
                                    (number-to-string (1- pad))
                                    "\\}[^ ]") nil t))
      (move-to-column col))))

그것은 좋았습니다 (수정 후-1을 빼는 것으로 무엇을했는지 이해하지 (current-column)못하지만 커서가 움직이지 않습니다). 내 사양을 정확하게 충족시키지 못합니다 : 들여 쓰기 수준으로 이동하면 덜지나갑니다- 들여 쓴 줄.
— Gilles 'SO- 악마 그만'

작동하지 않습니다. 예를 들어 ind-forward-sibling들여 쓰기가 동일한 다음 줄을 찾기 만하면 들여 쓰기가 적은 줄을 건너 뜁니다 (앞으로 형제가없는 경우에도 계속 진행됨).
— ShreevatsaR
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.