Vim은 최소 규격만 갖춘 인터페이스이지만, 거의 모든 UNIX® 버전에서 가장 많이 사용되는 두 편집기 중 하나이다. 다양한 소프트웨어 개발 및 시스템 관리 요구에 맞춰 Vim을 손쉽게 확장할 수 있다. Vim에는 사용자가 스크립트를 코딩한 다음 Vim으로 스크립트를 로드하는 데 사용할 수 있는 자체적인 스크립트 언어도 있다. 또는 Perl이나 Python과 같은 외부 스크립트 언어를 사용하여 편집기의 기능을 확장할 수도 있다. 이런 스크립트를 모두 합쳐 Vim 플러그인이라고 한다.
사용자 정의 플러그인이 도움이 되는 가장 흔한 상황은 프로그래밍 언어를 강조표시하는 구문이다. Vim을 설치하면 C,
C++, Perl 및 Tcl(Vim_Installation_Folder/vim72/syntax를 살펴볼 것)용으로 미리 정의된 다양한 구문 지원이
제공되지만, 때로는 사용자 정의 또는 새 프로그래밍 언어를 위한 추가 지원이 필요하거나 해당 조직의 특정 코딩 표준을 적용할 수 있게 플러그인을 확장할
필요가 있다.
유사하게, 편집기 내부에서 소스를 컴파일하는 기능도 있어 편리하다. Perl 또는 Python 코드용 사용자 정의 플러그인을 만들면 편집기 내에서 소스를 컴파일할 수 있고, 그러면 오류 위에 커서가 놓이므로 개발 시간을 대폭 단축하는 데 도움이 된다.
이 기사에서는 Vim이 사용자 정의 프로그래밍 언어에서 구문을 강조표시하기 위해 제공해야 하는 것을 보여준다. 여기서는 간단한 정규식 사용법에 따라 코딩 규칙을 적용하고 Vim을 이용한 Perl 스크립트 작성으로 이동한다. Vim 내부에서 소스를 컴파일하는 방법을 보여주는 것으로 이 기사를 마무리하겠다.
주: 본 기사에서는 독자들이 Vim, Perl, make 및 정규식에 대한 기본적인 지식이 있는 것으로 가정하고
설명한다. Vim 버전 7.2와 Perl 버전 5.8을 사용하기로 한다.
사용자가 직접 작성한 사용자 정의 언어에서 구문을 강조하기 위해 Vim의 내부 스크립팅 엔진을 사용할 것이다. 목록 1에 이 사용자 정의 언어의 몇 가지 키워드가 표시되어 있다.
목록 1. 사용자 정의 프로그래밍 언어의 키워드
foreach if then else elsif while repeat until disable integer unsigned signed byte always initial |
Vim은 syntax keyword <그룹 이름> <키워드 목록> 형식을 이용해 키워드가 되도록 어떤 단어를 연관한다.
여기서 다루는 사용자 정의 언어에 대해, 목록 2의 의사 코드를 사용한다.
목록 2. Vim에서 키워드 정의
syntax keyword group1 foreach if then else elsif while
repeat until disable integer unsigned signed byte always initial
|
그 다음, 이 파일을 $HOME에 lang.vim이라는 이름으로 저장한다. 사용자 정의 언어로 작은 코드 스니펫을 편집한다(목록 3 참조).
목록 3. 사용자 정의 프로그래밍 언어로 작성된 코드
integer k=0;
repeat (k < 3) begin
print “hello world” + k + “\n”;
k = k + 1;
end
|
Vim 편집기에서 lang.vim을 :source $HOME/lang.vim으로 로드하면 끝이다. 하지만, 좀 기다리면서 문제가 있는지 살펴보고, 아무런 일도 생기지 않는지 확인한다. 구문을 지정했지만, 구문을 어떻게 강조해야 할지에 관한 정보를 입력하지 않았다. 목록 4는 lang.vim 파일의 개선된 버전을 나타낸 것이다.
목록 4. 구문 강조표시를 지원하는 개선된 버전의 lang.vim
syntax keyword type1 integer unsigned signed byte
syntax keyword statement1 foreach if then else elsif
while repeat until disable always initial
highlight link type1 Type
highlight link statement1 Statement
|
lang.vim을 다시 로드한다. 그러면 목록 3과 같이 코드에서 구문이 강조표시된다(그림 1 참조). 아래의 그림 1에서는 키워드 integer 및 repeat가 강조표시되어 있다.
그림 1. 사용자 정의 코드에서 강조표시된 구문
목록 4에서는 정확히 무슨 일을 한 것일까? 다음 두 가지 사항을 이해해야 한다.
- 사용자는 일반적으로 프로그램에 있는 명령문들(
if-then-else,repeat등)이 데이터 유형(integer,byte등)과는 다르게 강조표시되어 더 쉽게 읽을 수 있을 것으로 여긴다. 그래서 구문을 적당한 내용을 포함한 여러 그룹으로 분할한다. 예컨대,type1그룹에는integer,unsigned,signed및byte키워드가 들어 있다. - Vim에는 특정 색상 구성표와 함께 제공되는
Type,Statement,Comment및Identifier와 같이 미리 정의된 구문 그룹이 있다.highlight명령은byte와 같은 키워드에 대해 동일한 색상 구성표가 적용되도록type1을 Vim의Type그룹과 연관한다.
십중팔구의 사용자는 integer와 INTEGER가 모두 강조표시되도록 언어에서 대/소문자를
구분하지 않기를 바랄 것이다. 또한, // C++ 스타일의 주석에 대한 지원도 추가하고 싶을 것이다. 목록 5는 수정된
lang.vim 파일을 나타낸 것이다.
목록 5. 구문 강조표시를 지원하는 개선된 버전의 lang.vim
syntax case ignore
syntax keyword type1 integer unsigned signed byte
syntax keyword statement1 foreach if then else elsif
while repeat until disable always initial
syntax match comment1 /\/\/.*/
highlight link type1 Type
highlight link statement1 Statement
highlight link comment1 Comment
|
syntax case ignore 문이 대/소문자 구분을 하지 않도록 해준다. 키워드를 사용하여 주석을 처리할 수 없으므로,
Vim Comment 그룹과 연관할 수 있는 정규식이 필요하다. syntax match <ID> /<패턴>/을
사용하여 정규식을 정의한다.
시작 및 종료 슬래시(/) 사이에서 //로 시작된 것은 무엇이든 그 행의 끝까지
계속되었음을 나타내는 \/\/.* 패턴을 정의했다. 그래서 사용자 정의 언어에서 그림 2에 표시된 코드는 적절히
강조표시된다.
그림 2. 주석 및 대/소문자 구분 무시 기능 지원
조직별로 특정한 코딩 표준을 처리하기 위해 사용자 정의 플러그인을 손쉽게 확장할 수 있다. 몇 가지 일반적인 지침은 다음과 같다.
- 코드에는 탭이 없다.
- 변수 이름은 14자를 초과하면 안 된다.
- 단일 행의 길이가 80자를 초과하지 않도록 한다.
- 함수는 100행을 초과할 수 없다.
코드에는 탭이 없다는 가장 간단한 지침부터 시작해보자. 간단히 tab에 대한 ID를 정의한 다음, 그 ID를 Vim의
미리 정의된 Error 태그와 연관한다.
syntax match identifier1 “\t” highlight link identifier1 Error |
그러면 코드에 탭이 있는 경우 어떤 일이 생길까? 그림 3은 탭이 있는 그림 2의 코드를 수정한 코드를 나타낸 것이다.
그림 3. 빨간색으로 탭이 있음을 강조표시한 Vim의 모습
그림 3에서는 repeat 바로 뒤의 탭이 빨간색으로 강조표시되어 있는데, 이는 무엇인가 잘못되었음을 사용자에게 분명히 알려주는 역할을 한다.
변수 이름의 길이에 대한 지원에는 구문 일치에서 정규식 사용에 대해 더욱 깊은 이해가 요구된다.
syntax match longword1 “\w\{14,}”
highlight link longword1 Error
|
여기서, \w는 문자 클래스 [0-9A-Za-z_]를 정의한다. 즉, 모든 숫자, 영문자(대문자 또는
소문자) 또는 밑줄(_)이 허용된다. 다음 시퀀스는 \{14,}인데, 이는 최소 14개의 연속 항목이 일치해야
한다는 뜻이다. 따라서 this_is_a_REAL_long_word1은 ID 길이가 14자를 초과하므로 강조표시되는 반면, this_is_ok_2는
정상적으로 표시된다. 그림 4는 오류가 발생할 때 어떤 모습인지를 나타낸 것이다.
그림 4. 14자를 초과하는 변수 이름이 빨간색으로 표시됨
그림 4에서는 this_is_a_REAL_long_word1 변수가 (역시 Vim의 기본 색상 프로파일에 따라) 빨간색으로 강조표시되어 사용자에게 무엇인가 잘못되었음을 경고한다.
단일 행의 길이가 80자를 초과하면 너무 길고 복잡하게 느껴져 읽기 어렵다. syntax match를 다시 사용하여 이
정규식에 대한 ID와 Error에 대한 링크를 정의하게 될 것이다. 정규식을 이해하기 어려워서는 안 된다. 캐럿(^)은
한 행의 시작을 표시하고, 달러 기호($)는 한 행의 끝을 표시한다. 그리고 그 사이에 있는 어떤 내용도 80자를 초과하면 오류가
발생한다. 마침표(.)는 행의 끝이 아닌 어떤 문자와 일치함을 표시한다.
syntax match longline1 “^.\{80,}$”
highlight link longline1 Error
|
그림 5는 길이가 80자를 초과하여 강조표시된 코드 행을 나타낸 것이다.
그림 5. 행의 길이가 80자를 초과하지 않도록 하기 위한 규칙
그림 5에서는 공식이 워낙 복잡하여 80자를 초과하는 바람에 Vim에서 전체 행이 빨간색으로 강조표시된 것을 알 수 있다. 백스페이스를 입력하여 행 길이가 80자에서 79자로 줄어드는 순간 강조표시는 사라진다.
사용자 정의 코딩 규칙 중 마지막 항목은 함수의 길이는 항상 100행 미만으로 유지해야 한다는 것이다. 목록 6은 사용자 정의 프로그래밍 언어에서 정의한 함수를 나타낸 것이다.
목록 6. 사용자 정의 프로그래밍 언어에서 정의한 함수
function f (int k, int l) returns float
begin
f = k * l;
for (int i=0; i<10; i++)
begin
f += sqrt(k) * sqrt(l);
end
return f + 2;
endfunction
|
복잡한 정규식을 고안하거나 Vim에서 미리 정의된 내부 함수를 호출하기보다는 행 수를 검사하기 위해 Perl로 전체 함수를 전달하는 것이 아마 더 쉽고 분명히 더 빠를 것이다. 다음 섹션에서 세부사항을 설명한다.
Vim은 Perl, Python, Tcl 및 Ruby 스크립트와 연결하기 쉽다. 하지만, 논의의 범위는 Perl로만 한정하기로 한다. Python, Tcl 및 Ruby와의 인터페이스도 사실은 유사하다. 목록 7에서는 어떤 함수의 길이가 100행을 초과하는 경우 오류 메시지를 표시하는 Vim 플러그인을 설명한다.
목록 7. Perl을 사용하여 Vim용 사용자 정의 플러그인 작성
perl << EOF
sub checksize
{
my $count = 0;
my $startfunc = 0;
my $filelen = scalar @_;
while ($count < $filelen)
{
if ($_[$count] =~ /^function/)
{
$startfunc = $count;
}
elsif ($_[$count] =~ /endfunction/)
{
if ($count - $startfunc > 100)
{
Vim::Msg($_[$startfunc], "Error");
}
}
++$count;
}
}
EOF
function! L1( )
perl checksize($curbuf->Get(1..$curbuf->Count()))
endfunction
|
이 모든 코딩 작업은 앞서 사용한 것과 같은 lang.vim 파일에서 수행한다. 이 플러그인의 뉘앙스는 다음과 같다.
- 마커를 사용하여 Vim 스크립트 내부에 Perl 코드를 임베드한다. 이런 마커들은 임의의 이름을 가질 수 있지만 모두 대문자로 된 이름은
안 된다. 목록 7의
perl << EOF … EOF에서 사용된 마커는EOF였다. 두 번째EOF가 행의 첫 번째 열에서 시작하는지 확인한다. 마커를EOF로 명명할 필요는 없고 어떤 이름으로든 명명할 수 있지만, 첫 번째 열에 대한 규칙은 반드시 지켜야 한다. - 파일의 전체 내용이 Perl 코드로 전달된다. Perl 서브루틴
checksize는 (Perl에서@_ implicit배열의 일부로서) 전체 파일을 순회하면서 함수 길이를 계속 검사한다. 이 서브루틴에서는function이라는 키워드가 나타나면 카운터를 0으로 설정하고,endfunction이라는 키워드가 나타나면 카운터가 100을 초과하는지 검사한다. 함수 길이가 100행을 초과하면 오류 메시지가 표시된다. - Vim 내부에 메시지를 표시해야 하므로, 일반적인 Perl 인쇄 루틴을 사용하여 오류 메시지를 표시할 수 없다. Vim에서는 Perl에 유용한
인터페이스를 제공하는데, 그 세부사항은 참고자료에서 확인할 수 있다.
Vim::Msg는 편집기 창 내부의 메시지를 표시한다. 목록 7에서는 잘못된 함수의 첫 번째 행을 표시한다.Vim::Msg에 대한 두 번째 인수는 표시되는 정보의 유형이다.error는 이 정보가 빨간색으로 강조표시됨을 암시한다. - Vim에서 파일 원본을 Perl 코드로 전달하는 함수를 정의한다.
$curbuf->Count( )는 현재 버퍼의 행 수를 알려주고,$curbuf->Get(<line1>..<line2>)은line1및line2에 의해 지정되는 행 사이의 텍스트를 리턴한다. 이 스크립트에서는 현재 버퍼의 첫 행에서 마지막 행으로 내용을 전달한다. 이제 ESC 모드에서:call L1()을 입력한다. 그러면 바로 잘못된 함수가 나열되는 것을 볼 수 있다.
Vim에서는 편집기 내부에서 소스를 컴파일할 수 있다. 구문 강조표시 및 사용자 정의 코드 검사와 함께, 이 기능을 통해 Vim을 사용자 정의 통합
개발 환경(IDE)과 가깝게 만들 수 있다. 목록 8에는 몇몇 오류가 있는 C++ 파일이 있다.
목록 8. 정말 난잡한 C++ 코드
#include <iostream>
using namespace stdl
class mytags {
public:
int getid(int id=0);
void setid(int)
protectd:
list<int> tags;
const list<int>::iterator tag_i;
}
|
목록 9에는 편집기 내부에서 컴파일하기 위해 Vim에 추가할 수 있는 간결한 다섯 개의 행이 표시되어 있다.
목록 9. F3 키 맵핑으로 편집기 내부의 오류 컴파일 및 표시
function! build() make cl “list the errors endfunction map <F3> :call build()<CR> |
ESC 모드에서 F3 키를 눌러 소스를 컴파일한다. build() 함수는 Vim 내부에서 make를 호출한
다음, 오류를 표시하는 cl을 호출한다. 첫 번째 오류로 이동하려면 ESC 모드에서 :cfirst를 입력하고,
이후의 모든 오류로 하나씩 이동하려면 :cn을 사용하고, 마지막 오류로 이동하려면 :clast를
입력한다. 기본적으로, Makefile은 소스와 같은 폴더에 있는 것으로 간주된다. 다시 말해, 목록 9에서
build() 함수를 수정하여 Makefile이 있는 폴더로 이동할 수 있기 때문에, 이 중 어떤 것도 필요하지
않다. 또한, 그것만으로도 충분히 쉽게 make로 인수를 전달할 수 있다. 목록 10에서 그 점을 분명히 보여주고
있다.
목록 10. make를 사용하여 소스를 빌드하기 위해 수정한 Vim 스크립트
function! build() cd /home/arpan/ibm/scripts “go to the folder where Makefile is make CC=g++ cd /home/sources “back to sources cl “list the errors endfunction map <F3> :call build()<CR> |
목록 11은 이제 Vim 내부에서 나타나는 오류를 보여준다.
목록 11. Vim 환경 내에서 오류 생성
#include <iostream>
using namespace stdl
class mytags {
public:
int getid(int id=0);
void setid(int)
protectd:
list<int> tags;
const list<int>::iterator tag_i;
}
t.cpp:4: error: expected namespace-name before "class"
t.cpp:4: error: `<type error>' is not a namespace
t.cpp:4: error: expected `;' before "class"
t.cpp:8: error: expected `;' before "protectd"
t.cpp:10: error: ISO C++ forbids declaration of `list' with no type
t.cpp:10: error: expected `;' before '<' token
t.cpp:6: error: expected unqualified-id at end of input
t.cpp:6: error: expected `,' or `;' at end of input
Press ENTER or type command to continue
|
$HOME/.vim에서 syntax라는 이름의 폴더를 작성하고 사용자 정의 플러그인을 그 폴더로 복사한다. 예컨대, 사용자 정의 언어가
ml2라는 언어라고 한다면, 이 파일의 이름을 ml2.vim으로 지정한다. 그 다음, $HOME/.vimrc를 편집하고 syntax on
행을 추가한다. 그걸로 끝이다. 이제는 Vim에서 확장자가 ml2인 파일을 열 때마다 해당 구문이 자동으로 강조표시된다. 이 작동에는 명시적인 함수 호출이
포함되지 않으므로, 서브루틴 길이와 같은 빠른 사용자 정의 코드 검사를 위한 키 맵핑을 가지는 것이 좋다.
고공 행진을 하고 있는 통합 IDE가 빠른 개발의 필수 요건은 아니며, Vim은 이런 철학을 충분히 입증하고 있다. Ruby 및 Python과 같은 언어에 대한 인터페이스를 사용하면 Vim으로 웹에 연결하는 것도 가능하다. 본 주제에 관한 추가 자료는 참고자료 섹션을 참조한다.
교육
-
Vim 문서: Vim 편집기에 대한 자세한 정보를 살펴보자.
-
Vim 정규식: Vim에 유용한 여러 가지 정규식을 찾을 수 있다.
-
Vim
목차: Swaroop C H의 Vim 목차를 읽어보자.
-
Scripting the Vim editor, Part 1: Variables, values, and
expressions(Damian Conway, developerWorks, 2009년 5월): Vimscript 프로그래밍 언어의 기본 컴포넌트에 대해 알아보자.
-
AIX와 UNIX: AIX 시스템 관리 및 UNIX 스킬 확장의 모든 측면과 관련된 풍부한
정보를 접할 수 있다.
-
AIX 및 UNIX 입문(한글): AIX와 UNIX 입문 페이지에서 자세한 정보를 볼 수 있다.
-
기술
서점: 다양한 기술 주제와 관련된 서적을 살펴볼 수 있다.
제품 및 기술 얻기
-
Per interface for Vim: Vim용 Perl 인터페이스에 대한 자세한 내용을 확인하고 이 인터페이스를 다운로드할 수 있다.
토론
-
developerWorks 블로그:
블로그를 읽어 보고 developerWorks
community에 참여하자.
- Twitter의 developerWorks 페이지를 살펴보자.
- My developerWorks 커뮤니티에 참여하자.
- AIX 및 UNIX® 포럼에 참여하자.
- AIX Forum
- AIX Forum for developers
- Cluster Systems Management
- IBM Support Assistant Forum
- Performance Tools Forum
- Virtualization Forum
- 기타 AIX and UNIX Forums