Section 01변수
지금까지는 단일 명령을 다뤘습니다. 이제 책의 다음 3분의 1 동안, Vimscript를 프로그래밍 언어로 바라봅니다.
가장 먼저 이야기할 것은 변수입니다. 다음 명령을 실행하세요:
:let foo = "bar" :echo foo " bar 출력 :let foo = 42 :echo foo " 42 출력
let 명령으로 변수를 만들고 값을 대입합니다. foo에 문자열 "bar"를, 그다음 정수 42를 대입했습니다. 변수의 타입이 자유롭게 바뀌는 것처럼 보이지만, Vimscript는 동적 타입 언어가 아닙니다 — 그 미묘함은 뒤에서 다룹니다.
Section 02옵션과 레지스터를 변수로
특수 구문으로 옵션을 변수처럼 읽고 쓸 수 있습니다. 이름 앞에 앰퍼샌드(&)를 붙입니다:
:set textwidth=80 :echo &textwidth " 80 :let &textwidth = &textwidth + 10 " 계산해서 설정
:set으로는 리터럴 값 하나만 줄 수 있지만, :let으로 옵션을 변수처럼 다루면 Vimscript의 전체 표현력으로 값을 계산할 수 있습니다. 불리언 옵션은 0(거짓)과 1(참)으로 나타납니다.
레지스터도 변수처럼 읽고 쓸 수 있습니다 — 이름 앞에 @를 붙입니다:
:let @a = "hello!" " 레지스터 a 에 텍스트 저장 :echo @" " 무명 레지스터 (마지막 yank/delete) :echo @/ " 현재 검색 패턴
@"는 무명 레지스터 — 목적지를 지정하지 않고 복사·삭제한 텍스트가 들어가는 곳입니다. @/는 현재 검색 패턴이라, 프로그램으로 검색 패턴을 읽고 수정할 수 있습니다. 8장의 Grep 연산자에서 이 둘을 실제로 활용합니다.
Section 03변수 스코프
Vimscript는 변수에 한 가지 비틀기를 더합니다 — 스코프(scope)입니다. 두 개의 다른 파일을 분할로 열고, 한쪽에서 다음을 실행하세요:
:let b:hello = "world" :echo b:hello " world
다른 버퍼로 옮겨가 :echo b:hello를 다시 실행하면 — Vim이 변수를 찾을 수 없다는 오류를 냅니다. b: 접두사가 변수 hello를 현재 버퍼에만 국한시켰기 때문입니다.
| 접두사 | 의미 |
|---|---|
g: | 전역 (global) |
b: | 현재 버퍼 한정 |
w: | 현재 창 한정 |
l: | 함수 로컬 |
a: | 함수 인자 |
v: | Vim이 미리 정의한 변수 |
a:(인자)와 l:(로컬) 스코프를 본격적으로 활용하게 됩니다.
Section 04조건문
모든 프로그래밍 언어에는 분기 방법이 있고, Vimscript에서 그것은 if 문입니다. 먼저 여러 줄 문법을 알아 둡시다 — 명령들을 파이프(|)로 구분하면 한 줄로 쓸 수 있습니다. 이제 if를 실행해 보세요:
:if 1 : echom "ONE" " 정수 1은 '참' — 실행됨 :endif
그런데 문자열을 조건에 넣으면 결과가 놀랍습니다:
:if "something" " 출력 없음 — '거짓'으로 취급! :if "9024" " 출력됨 — 숫자로 시작하면 그 숫자로 강제 변환
Vim은 필요할 때 변수와 리터럴을 강제로 변환합니다. "hello" + 10은 10이 됩니다 — 숫자로 시작하지 않는 문자열은 0으로 변환됩니다.
"10hello" + 10은 20입니다 — 숫자로 시작하는 문자열은 그 숫자로 변환됩니다.
if는 모든 강제 변환이 끝난 뒤 조건이 0이 아닌 정수면 본문을 실행합니다.
Python처럼 else와 elseif도 지원합니다:
:if 0 : echom "if" :elseif "nope!" : echom "elseif" :else : echom "finally!" " 앞 조건이 모두 거짓 — 실행됨 :endif
Section 05비교 — == 의 위험
if 문은 비교 없이는 쓸모가 적습니다. 숫자 비교는 예상대로 동작합니다. 문자열 비교도 그래 보입니다 — 하지만 함정이 있습니다. 다음을 실행하세요:
:set ignorecase :if "foo" == "FOO" " ignorecase가 켜지면 — 참이 된다! : echom "설마 했는데..." :endif
==의 동작은 사용자의 ignorecase 설정에 따라 달라집니다! 다른 사람이 쓸 플러그인을 만들 때, ==를 절대 신뢰하면 안 됩니다. 맨 ==는 플러그인 코드에 등장해서는 안 됩니다.
해결책 — Vim에는 두 가지 추가 비교 연산자 집합이 있습니다:
:if "foo" ==# "FOO" " ==# : 설정 무관, 항상 대소문자 구분 :if "foo" ==? "FOO" " ==? : 설정 무관, 항상 대소문자 무시
==#, 무시하려면 ==?. 평범한 ==는 잘못된 코드이며 언젠가 깨집니다. 이것은 "nmap 대 nnoremap"과 같은 교훈입니다 — 사용자 설정을 절대 신뢰하지 마세요.
Section 06연습문제
~/.vimrc의set명령 일부를let &option = ...형식으로 바꿔 보고, 다시 되돌리세요(set으로 충분하면let을 쓰지 마세요 — 읽기 어렵습니다).:help registers를 읽고, 읽고 쓸 수 있는 레지스터 목록을 살펴보세요.:help internal-variables의 스코프 목록을 훑어보세요.:set ignorecase와:set noignorecase를 오가며 다양한 비교가 어떻게 동작하는지 확인하세요.:help expr4를 읽고 사용 가능한 모든 비교 연산자를 확인하세요.:help ignorecase를 읽고 왜 누군가 그 옵션을 켜는지 알아보세요.