Vimscript 배우기 cho.books
제 4 장 · 원서 §11–14

버퍼-로컬 설정과 자동명령

버퍼마다 다른 매핑과 옵션을 둘 수 있습니다. 그리고 자동명령 — 특정 이벤트가 일어날 때마다 Vim이 명령을 실행하게 하는, 매핑만큼이나 중요한 기능.

<buffer> setlocal autocmd FileType 이벤트 augroup

Section 01버퍼-로컬 매핑과 옵션

매핑·약어·옵션을 한 번에 하나의 버퍼에만 설정할 수 있습니다. 이 아이디어의 진정한 힘은 자동명령과 결합할 때 드러납니다.

두 파일 foo, bar를 각각 분할로 열어 둔 채로, foo에서 다음을 실행하세요:

vimscript — 버퍼-로컬 매핑
:nnoremap <leader>d dd
:nnoremap <buffer> <localleader>x dd

foo에서는 두 매핑 모두 작동합니다. 하지만 bar로 옮겨가 <localleader>x를 누르면 — 전체 줄 대신 문자 하나만 삭제됩니다! <buffer>가 그 매핑을 "정의한 버퍼에서만" 적용되게 했기 때문입니다.

버퍼-로컬 옵션

일부 옵션은 버퍼마다 따로 설정할 수 있습니다. setlocal을 씁니다:

vimscript — 버퍼-로컬 옵션
:setlocal wrap        " 이 버퍼만 줄바꿈
:setlocal number      " 이 버퍼만 줄 번호
직관 버퍼-로컬 매핑에는 <leader>가 아니라 <localleader>를 쓰세요. 두 개의 별도 리더 키가 일종의 "네임스페이싱"을 제공해, 전역 매핑과 파일타입별 매핑을 머릿속에서 깔끔하게 구분하게 해줍니다. 더 구체적인(버퍼-로컬) 매핑이 전역 매핑보다 우선합니다.

Section 02자동명령의 구조

자동명령(autocommand)은 특정 이벤트가 발생할 때마다 Vim이 명령을 실행하게 하는 방법입니다. 예제로 바로 들어갑시다:

vimscript — 첫 자동명령
:autocmd BufNewFile * :write

이제 :edit foo로 새 파일을 열고 :quit로 닫으면 — 파일이 디스크에 생깁니다. 보통 Vim은 처음 저장할 때까지 파일을 실제로 만들지 않지만, 이 자동명령이 새 파일을 만들자마자 저장하게 했습니다.

개념 자동명령의 세 부분

:autocmd BufNewFile *.txt :write는 세 부분으로 이루어집니다:

이벤트BufNewFile — 무엇을 감시할지.

패턴*.txt — 어떤 파일에만 적용할지 거르는 필터.

명령:write — 이벤트가 발생하면 실행할 것.

이벤트는 종류가 매우 많습니다 — 존재하지 않는 파일을 편집 시작할 때, 파일을 읽을 때, 파일타입이 바뀔 때, 입력 모드에 들어가거나 나갈 때 등. 쉼표로 여러 이벤트를 묶을 수도 있습니다:

vimscript — 여러 이벤트 묶기
:autocmd BufNewFile,BufRead *.html setlocal nowrap

BufReadBufNewFile을 함께 묶는 것은 흔한 관용구입니다 — 파일이 이미 존재하든 아니든, 특정 종류의 파일을 열 때마다 명령을 실행합니다.

함정 자동명령의 명령 부분에는 <cr> 같은 특수 문자를 직접 쓸 수 없습니다. 이 제약을 우회하는 법은 8장의 execute에서 배웁니다. 지금은 이 한계를 받아들이세요.
모션 · 자동명령은 어떻게 발화하나 01 / 5
스페이스: 재생 · ← →: 단계 이동 · R: 리셋

Section 03FileType 이벤트

가장 유용한 이벤트 중 하나가 FileType입니다. Vim이 버퍼의 파일타입을 설정할 때마다 발화합니다. 버퍼-로컬 매핑과 결합하면, 편집 중인 파일의 종류에 특화된 매핑을 만들 수 있습니다:

vimscript — 파일타입별 주석 매핑
:autocmd FileType javascript nnoremap <buffer> <localleader>c I//<esc>
:autocmd FileType python     nnoremap <buffer> <localleader>c I#<esc>

JavaScript 파일에서 <localleader>c를 누르면 줄이 //로 주석 처리되고, Python 파일에서는 같은 키가 #으로 주석 처리합니다. "줄의 시작으로 가서 주석 문자를 추가한다"고 생각하는 대신, 그저 "이 줄을 주석 처리한다"고만 생각하면 됩니다. 코딩 시 머리의 부담이 줄어듭니다.

Section 04자동명령 그룹

자동명령에는 골치 아픈 문제가 있습니다. 같은 자동명령을 여러 번 실행하면 — Vim은 그것을 중복으로 만듭니다:

vimscript — 중복 문제 시연
:autocmd BufWrite * :echom "Writing buffer!"
" 위 명령을 4번 실행하면, 저장 시 메시지가 4번 출력된다
함정 ~/.vimrc를 소싱하면 파일 전체가 다시 읽힙니다 — 자동명령 정의까지 포함해서. vimrc를 소싱할 때마다 자동명령이 중복으로 쌓여 Vim이 점점 느려집니다.

해결책은 관련 자동명령을 이름 있는 그룹으로 묶고, 그룹을 비운 뒤 채우는 것입니다:

vimscript — 자동명령 그룹 (중복 방지)
augroup filetype_html
  autocmd!
  autocmd FileType html nnoremap <buffer> <localleader>f Vatzf
augroup END

augroup filetype_html로 그룹에 들어가고, autocmd!로 그룹을 즉시 비우고, 자동명령을 정의한 뒤, augroup END로 그룹을 나옵니다. vimrc를 다시 소싱해도 autocmd!의 비우기 덕분에 중복이 생기지 않습니다.

철칙 vimrc에 작성하는 모든 자동명령을 augroup + autocmd! 패턴으로 감싸세요. 예외 없이. 이것이 vimrc가 느려지지 않게 하는 유일한 방법입니다.

Section 05버퍼-로컬 약어와 스니펫

버퍼-로컬 약어를 자동명령과 결합하면 작은 스니펫 시스템을 만들 수 있습니다:

vimscript — 파일타입별 스니펫
:autocmd FileType python     :iabbrev <buffer> iff if:<left>
:autocmd FileType javascript :iabbrev <buffer> iff if ()<left>

JavaScript 파일에서 iff를 입력하면 if ()가, Python 파일에서는 if:가 펼쳐집니다. <left>는 커서를 한 칸 왼쪽으로 옮겨 괄호/콜론 안에 두게 합니다. Vim이 현재 파일 종류에 따라 적절한 약어를 수행합니다.

직관 이 세 가지 — 버퍼-로컬 설정, 자동명령, FileType 이벤트 — 를 조합하면, 모든 언어가 각자 알맞은 매핑·약어·옵션을 갖춘 환경을 갖게 됩니다. 이것이 Vim을 진정한 다언어 편집기로 만드는 토대입니다.

Section 06연습문제

  • :help local-options, :help setlocal, :help map-local을 읽으세요.
  • :help autocmd-events를 훑어보고, 자동명령을 묶을 수 있는 이벤트들의 종류를 느껴 보세요. 외울 필요는 없습니다.
  • 좋아하는 파일타입들에 대해 setlocal로 옵션을 설정하는 FileType 자동명령 몇 개를 만드세요(wrap, list, spell, number 등).
  • 자주 쓰는 파일타입들에 대해 "이 줄을 주석 처리" 자동명령을 만드세요.
  • ~/.vimrc의 모든 자동명령을 augroup + autocmd! 패턴으로 감싸세요.
  • 특정 종류의 파일에서 자주 입력하는 것들에 대한 "스니펫" 약어를 만드세요.