들여 쓰기로 탐색


15

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

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

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

여기에 압입 구조화 데이터 유사체이다 forward-sexp, backward-sexpbackward-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.