Learn Vimscript The Hard Way - 51. Potion Section Movement part 1
Potion Section Movement - part one
해당 장도 길이가 길기 때문에 두 파트로 나누어서 작성하였다.
저번 장에 우리는 어떻게 section movement가 작동하는지 살펴보았다. 이를 potion 파일에 적용하기 전에 한번 다시 생각해보자.
우선 우리는 Potion 파일에서 "section"이 어떤 것을 의미할 것인지를 결정하여야 한다. 두 쌍의 section movement 명령어가 있으므로 우리의 사용자들을 위한 두가지 "schemes"를 마련할 수 있다.
다음 두 가지 스키마를 potion의 섹션으로 결정하자.
- 빈 줄 이후에 오는 모든 줄 이나 파일의 첫 줄(whitespace가 아닌 문자가 있는 줄)
- 첫 글자로 whitespace가 아닌 문자가 있고, 줄 안에 등호 문자(
=
)가 있고 콜론(:
)으로 끝나는 줄
조금 확장된 버전의 factorial.pn
을 예시로 사용해보자.
아래는 위 규칙이 section header에 어떻게 적용되었는지 적은 예시이다.
# factorial.pn 1
# Print some factorials, just for fun.
factorial = (n): 1 2
total = 1
n to 1 (i):
total *= i.
total.
print_line = (): 1 2
"-=-=-=-=-=-=-=-\n" print.
print_factorial = (i): 1 2
i string print
'! is: ' print
factorial (i) string print
"\n" print.
"Here are some factorials:\n\n" print 1
print_line () 1
10 times (i):
print_factorial (i).
print_line ()
우리의 첫 번째 정의는 상당히 자유롭다. 이는 대략 "top-level"의 텍스트 덩어리를 정의한다.
두 번째 정의는 조금 제한적이다. 이는 (효율적으로) 함수 정의를 의미한다.
Custom Mappings
ftplugin/potion/sections.vim
파일을 플러그인 레파지토리에 만들자. 여기에 우리의 section movement와 관련된 코드를 추가할 것이다. 이 코드는 버퍼의 filetype
이 potion
으로 설정될 떄마다 실행된다는 것을 기억하라.
우리는 모든 4가지 section movement 명령어를 다시 매핑할 것이기 때문에 뼈대를 만들어보자.
noremap <script> <buffer> <silent> [[ <nop>
noremap <script> <buffer> <silent> ]] <nop>
noremap <script> <buffer> <silent> [] <nop>
noremap <script> <buffer> <silent> ][ <nop>
nnoremap
대신에 noremap
명령어를 사용한 것을 보라. operator-pending 모드에서도 사용하기를 원하기 때문이다. 이 경우 d]]
같은 명령어를 사용할 수 있다. ("여기서부터 다음 섹션까지의 코드를 모두 지워라")
우리는 매핑을 buffer-local로 추가하여 Potion 파일에만 적용되게 하였다.
또한 silent 옵션을 추가하여 어떻게 섹션간에 이동하는지에 대한 상세한 내용은 신경쓰지 않도록 하였다.
Using a Function
section movement 명령어는 다른 명령어들과 거의 흡사하기 때문에 우리가 호출할 함수를 추상적으로 만들어보자.
다른 다양한 vim 플러그인에서 매핑을 추가할 때 이런 접근 전략을 쓰는 것을 볼 수 있을 것이다. 이는 읽기 쉽고, 유지보수가 쉽다.
sectinos.vim
파일에 다음을 추가해보자
function! s:NextSection(type, backwards)
endfunction
noremap <script> <buffer> <silent> ]]
\ :call <SID>NextSection(1, 0)<cr>
noremap <script> <buffer> <silent> [[
\ :call <SID>NextSection(1, 1)<cr>
noremap <script> <buffer> <silent> ][
\ :call <SID>NextSection(2, 0)<cr>
noremap <script> <buffer> <silent> []
\ :call <SID>NextSection(2, 1)<cr>
나(저자)는 긴 줄을 싫어하기 때문에 vimscript의 long line continuation 기능을 사용하였다. 각 매핑의 두 번 째 줄의 시작에서 역슬래쉬(\
)를 사용하고 있는 것을 볼 수 있다. 더 많은 정보를 보려면 :help line-continuation
을 참고하여라.
script-local 함수를 사용하고 전역 변수를 오염시키는 것을 방지하기 위해 <SID>
를 사용한 것에 주의하라.
각각의 매핑은 간단하게 NextSection
함수를 호출한다.
Base Movement
우리의 함수에 무엇이 필요할지 생각해보자. 우리는 커서를 다음 "section"으로 이동시켜야 한다. /
나 ?
명령어의 결과로 커서를 이동시키는 것이 쉬울것이다.
NextSection
을 다음과 같이 수정해보자.
function! s:NextSection(type, backwards)
if a:backwards
let dir = '?'
else
let dir = '/'
endif
execute 'silent normal! ' . dir . 'foo' . "\r"
endfunction
이제 위 함수는 execute normal!
을 사용하여 backwards
인자의 유무에 따라 /foo
나 ?foo
를 실행시킬 것이다.
실제로는 foo
가 아닌 다른 것을 찾아야 할 것이다. 그리고 이 패턴은 우리가 위에서 section heading으로 정의한 것에 따라 달라질 것이다.
NextSection
을 다음과 같이 바꿔보자.
function! s:NextSection(type, backwards)
if a:type == 1
let pattern = 'one'
elseif a:type == 2
let pattern = 'two'
endif
if a:backwards
let dir = '?'
else
let dir = '/'
endif
execute 'silent normal! ' . dir . pattern . "\r"
endfunction
이제 우리는 위의 패턴을 채워넣기만 하면 된다.
나머지는 다음 포스트에..