tools/vim

Learn Vimscript The Hard Way - 49. Advanced Folding - part 1

seul chan 2020. 5. 1. 23:49

Advanced Folding - 1/3

해당 장은 매우 길기 때문에 파트를 나눠서 작성할 예정이다.

저번 장에서는 vim의 indent 폴딩을 사용하여 potion 파일에 대해 빠르고 지저분한 fold를 추가하였다.

factorial.pn을 열어서 zM으로 모든 폴딩이 닫혀있는 것을 확인하라. 해당 파일은 다음과 같아 보일 것이다.

factorial = (n):
+--  5 lines: total = 1

10 times (i):
+--  4 lines: i string print

첫 번째 fold를 열면 다음과 같아진다.

factorial = (n):
    total = 1
    n to 1 (i):
+---  2 lines: # Multiply the running total.
    total.

10 times (i):
+--  4 lines: i string print

꽤 괜찮아 보이지만, 나는(저자는) block의 첫 번째 줄을 같이 fold하는 것을 선호한다. 우리는 folding code를 커스터마이즈 하여 다음과 같은 결과물을 만들 것이다.

factorial = (n):
    total = 1
+---  3 lines: n to 1 (i):
    total.

+--  5 lines: 10 times (i):

이는 더 컴팩트 하며 읽기 쉽다. 만약 당신이 indent 방식을 선호한다면 괜차낳다. 하지만 여전히 이번 장에서 나오는 내용을 연습하는 것은 vim folding 표현법에 도움이 된다.

Folding Theory

custom folding code를 작성하는 것은 어떻게 vim이 folding에 대해 "생각하는지"에 대한 아이디어를 제공해준다. 다음은 간단한 규칙이다

  • 파일의 각각의 코드 줄은 "foldlevel"을 가지고 있다. 이는 0이거나 양의 정수이다.
  • foldlevel이 0인 줄은 "절대로" fold에 포함되지 않는다.
  • foldlevel이 같은 인접한 줄은 함께 folding된다
  • level X의 fold가 닫히면, X level보다 작은 줄에 도달하기 전까지 X보다 크거나 같은 다음 줄도 fold된다.

가장 쉬운 방법은 예시를 사용하는 것이다. vim 윈도우를 열어서 다음 텍스트를 적어보자.

a
    b
    c
        d
        e
    f
g

다음 명령어로 indent folding을 켜보자.

:setlocal foldmethod=indent

몇 분 간 접혀있는 fold를 가지고 테스트를 해보자.

zo, zc, zm, zr, zM, zR, zi 등의 명령어를 사용해보자

이제 다음 명령어로 첫 번째 줄의 foldlevel을 확인해보자.

:echom foldlevel(1)
0

0이 나오는 것을 볼 수 있다. 비슷하게 2, 3번째 줄도 확인해보자.

:echom foldlevel(1)
1
:echom foldlevel(1)
1

위 결과를 토대로 확인한 각 줄의 foldlevel은 다음과 같다.

a           0
    b       1
    c       1
        d   2
        e   2
    f       1
g           0

해당 장의 앞에 있던 규칙을 다시 읽어보자. 각 fold를 여닫으면서, foldlevel을 확인하면서 이 규칙에 대해 이해했는지 확실히 해보라.

이해 대해 자신감이 생기면 다음 섹션으로 넘어가라.

First: Make a Plan

실제 코드를 작성하기에 앞서, 우리가 만들 folding의 간략한 규칙을 스케치해보자.

무선, indent 되어 있는 줄은 함께 fold되어야 한다. 뿐만 아니라 그 이전 줄도 함께 fold 되어야 한다.

hello = (name):
    'Hello, ' print
    name print.

이것은 다음처럼 fold된다.

+--  3 lines: hello = (name):

빈 줄은 다음 줄과 같은 레벨이여야 하므로 fold의 마지막 줄이 빈 줄이면 포함되지 않아야 한다. 이는 다음과 같다.

hello = (name):
    'Hello, ' print
    name print.

hello('Steve')

이는 다음과 같이 fold되어야 한다.

+--  3 lines: hello = ():

hello('Steve')

그리고 이렇게 fold되면 안 된다.

+--  4 lines: hello = ():
hello('Steve')

이런 규칙은 개인적 선호에 따라 달라질테지만, 지금은 이 방식으로 folding을 만들어 보도록 하자.

Gettings Started

custom folding code를 two split으로 코드와 함께 열어보자. 하나는 ftplugin/potion/folding.vim 파일이고, 다른 하나는 factorial.pn이다.

다들 알 테지만 :split <filename>, vsplit <filename>으로 열 수 있다.

저번 챕터에서는 folding.vim 파일이 수정되면 factorial.pn을 닫은 뒤 다시 열어야 했지만, 더 쉬운 방법이 있다.

ftplugin/potion/ 디렉토리에 있는 모든 파일은 potion 파일의 filetype이 설정될 때마다 실행되는 것을 기억해보자. 이 말은 :set ft=potion 명령어로 split 된 factorial.pn 파일의 folding을 적용할 수 있는 것을 의미한다!

이는 매번 파일을 닫고 다시 여는 것보다 훨씬 빠르다. 딱 하나 기억해야할 것은 folding.vim을 저장하는 것이다.

Expr Folding

우리는 아주 유연한 fold 방식을 제공하는 expr folding을 사용하여 우리 코드를 fold 해 볼 것이다.

foldignore 옵션은 indent folding에서만 제공되기 때문에 먼저 folding.vim파일에서 foldignore을 제거하자. 또한 vim에게 expr folding 방식을 사용할 것이라고 알려줄 것이다.

setlocal foldmethod=expr
setlocal foldexpr=GetPotionFold(v:lnum)

function! GetPotionFold(lnum)
    return '0'
endfunction

첫 줄은 간단하게 expr folding을 사용한다는 뜻이다.

두 번 째 줄은 vim이 foldlevel을 결정하기 위해 어떤 표현식을 사용할지 정의하는 라인이다. vim이 표현식을 실행할 때, v:lnum을 사용하여 각 줄의 number를 알 수 있게 해 주었다. 우리의 표현식은 이 lnum을 인자로 받는 GetPotionFold 커스텀 함수이다.

마지막으로 우리는 간단하게 모든 줄에 '0'을 반환하는 더미 함수를 정의하였다. integer가 아닌 string을 반환하는 것에 주의하라. 왜 그렇게 했는지 간단히 살펴볼 것이다.

folding.vim을 저장하고 factorial.pn에서 :set ft=potion을 실행히보자. 모든 줄에 '0'을 반환하기 때문에 아무것도 fold되지 않은 것을 확인할 수 있다.

구체적인 folding 코드 작성은 다음 포스트에서 작성할 예정이다.