vim의 명령모드에서 입력하여 실행하는 명령들을 “Ex명령”이라고 한다. 주로 :
가 앞에 붙는 명령들이 여기에 해당하며, vimscript 함수와는 별개로 작동한다. (vimscript 함수들은 엄밀히 말해 :call
명령의 인자로 전달받는 값이 되는 것이다.)
:command
명령을 사용하면 사용자가 직접 원하는 동작을 수행하는 명령을 새로 정의하여 사용할 수 있다. 간단한 예로 다음 명령은 vim 파일을 편집할 때, 현재 파일을 저장하고 vim 스크립트를 로드하는 사용자 정의 Ex명령을 생성한다.
:command -bar LoadScript w! | so %
위 명령을 실행한 후에 vim 파일을 편집하고 :LoadScript
명령을 실행하면 현재 편집중인 파일을 저장한 후 :source
명령으로 다시 불러오게 된다.
보통 이런 사용자 명령은 단순한 Ex 명령의 조합을 그대로 사용하기 보다는, vimscript 함수를 정의하고 해당 함수를 실행하도록 작성하는 경우가 많다.
:command
명령은 크게 두 가지 역할을 한다.
:command
라고만 실행하면 현재 등록되어 있는 모든 사용자 정의 명령의 목록을 출력한다.:command Str
이라고 실행하면 “Str”로 시작하는 이름의 사용자 정의 명령의 목록을 출력한다.:command {cmd} {commands}
는{commands}
명령들을 실행하는{cmd}
라는 명령을 새로 등록한다.:command!
라고 쓰면 이전에 같은 이름으로 등록된 명령을 무시하고 새로 등록한다.
명령을 등록하는 방법
새로운 Ex명령을 등록하는 :command
명령은 다음과 같은 문법으로 구성된다.
:command {속성} {명령이름} {명령 표현식}
명령 속성
사용자 정의 명령은 기본적으로 내장 Ex 명령과 동일하게 취급된다. 따라서 :substitute
명령처럼 특정한 범위를 지정하여 실행될 수도 있고, :source
명령처럼 인자를 받을 수도 있다. 그리고 이러한 인자는 그 종류에 따라서 파일이름, 버퍼이름 등으로 지정되어 자동완성을 지원하게 할 수도 있다. 이러한 명령의 특징 들은 명령 속성 옵션에 의해 정의되므로, 새 명령을 등록하면서 사용할 수 있다. 명령옵션은 각각 -
로 시작하는 이름을 갖는다.
인자를 받는 명령 정의하기
기본적으로 사용자가 정의하는 명령은 인자가 없는 것으로 간주되며, 명령줄에서 인자와 함께 실행되면 에러가 발생한다. 인자를 받을 수 있는 명령을 정의하기 위해서는 -nargs=
속성을 사용하여 정의한다.
-nargs=0 : 기본, 인자를 받지 않는다.
-nargs=1 : 인자를 1개 받는다.
-nargs=* : 인자를 0, 1 ... 여러개 받을 수 있다.
-nargs=? : 인자를 0, 1개 받는다.
-nargs=+ : 인자를 1개 이상 받는다.
인자를 사용하기 위해서는 명령 표현식에 <args>
를 쓰면, 이 부분은 명령 실행시에 인자값으로 치환되어 평가된다. 인자로 넘겨진 값은 문자열 그대로 명령 표현식으로 들어간다. 그런데 이 말에는 함정이 숨어 있다. 표현식으로 전달되는 시점까지는 문자열 그대로 넘어가지만, 실제 명령 표현식이 실행될 때에는 표현식 맥락에서 평가되는 것이다.
:comm -nargs=1 Foo echo <args>
위 명령은 간단한 에코 명령을 다시 작성한 것이다. 그러면 :Foo hello
라고 실행하면 “hello” 가 화면에 표시될까? 아니다. hello 라는 변수가 정의되지 않았다는 에러가 나게 된다. 따라서 이 명령이 의도한 대로 실행되려면 <args>
대신에 <q-args>
치환자를 사용해야 한다. 이 치환자는 인자 전체를 따옴표에 넣어서 하나의 문자열로 평가하도록 만들어준다. 이렇게 치환자에 대한 변형을 처리하는 것으로는 <q-
와 <f-
가 있다. <q-
는 인자 그 자체를 하나의 문자열처럼 취급하기 위한 것이고, <f-
는 함수에 전달할 형태로 만드는 것이다. <f-args>
를 사용하면 인자들을 리스트로 만드는 것이 아니라 1) 공백 기준으로 자르고 2) 각 단어를 따옴표 처리한 후, 3) 중간에 콤마를 삽입한다.
인자의 자동완성 처리
인자를 받는 사용자 정의 명령을 작성한다면, 해당 인자의 타입을 고려하여 -complete=
속성을 지정해두면 사용성을 높일 수 있다. vim의 Ex 명령에서도 예를 들면 :set
명령은 옵션의 이름에 대해 자동완성을 지원하며, :edit
명령은 파일의 경로에 대해 자동완성을 지원해준다. 사용자 정의 명령에서도 이러한 자동완성의 도움을 받도록 할 수 있다. 아래는 설정 가능한 자동완성 결합 속성의 예시이다. 특히 -complete=custom,s:MyFunc
와 같이 커스텀 명령을 사용해서 인자에 대한 자동 완성도 구현할 수 있다. (이 부분은 뒤에서 다시 다뤄보겠다.)
-complete=augroup autocmd groups
-complete=buffer buffer names
-complete=behave :behave suboptions
-complete=color color schemes
-complete=command Ex command (and arguments)
-complete=compiler compilers
-complete=cscope |:cscope| suboptions
-complete=dir directory names
-complete=environment environment variable names
-complete=event autocommand events
-complete=expression Vim expression
-complete=file file and directory names
-complete=file_in_path file and directory names in |'path'|
-complete=filetype filetype names |'filetype'|
-complete=function function name
-complete=help help subjects
-complete=highlight highlight groups
-complete=history :history suboptions
-complete=locale locale names (as output of locale -a)
-complete=mapping mapping name
-complete=menu menus
-complete=option options
-complete=shellcmd Shell command
-complete=sign |:sign| suboptions
-complete=syntax syntax file names |'syntax'|
-complete=syntime |:syntime| suboptions
-complete=tag tags
-complete=tag_listfiles tags, file names are shown when CTRL-D is hit
-complete=user user names
-complete=var user variables
-complete=custom,{func} custom completion, defined via {func}
-complete=customlist,{func} custom completion, defined via {func}
범위 다루기
Ex 명령 중에는 특정한 범위나 수량를 지정하고, 그 범위에 대해서 작동하는 명령이 있다. 버퍼에서 문자열 찾기/바꾸기에 해당하는 :s
명령이나 창을 분할하는 :split
, 인자목록의 다음 파일로 넘어가는 :Next
같은 명령이 이런 명령에 속한다. 사용자 정의 명령에서도 -range
나 -count
속성을 명시하면 해당 명령은 앞에 숫자나 범위를 붙여서 실행할 수 있게 된다. -range
, -count
를 붙이는 것으로 명령에 범위를 적용하는 것이 가능해지는데, 이 옵션들에 대해서는 디폴트값을 지정해 줄 수 있다.
-range : 범위에 따른 명령이 된다. 생략한 경우 현재줄이 그 범위가 된다.
-range=% : 범위 속성을 활성화하고 버퍼 전체를 디폴트 범위로 한다.
-range=N : 특정 줄 번호를 디폴트 범위로 한다.
-count : 수량 속성을 활성화한다. 디폴트 값은 0개이다.
-count=N : 수량 속성을 활성화한다. 디폴트 값을 N으로 한다.
-range
와 -count
속성은 동시에 설정할 수 없다. 범위를 활성화한 경우 <line1>
, <line2>
가 범위의 시작줄 번호, 끝 줄 번호가 된다. (한 줄인 경우에는 두 값이 같다.) -count
속성이 활성화된 경우, 명령 실행 시 주어진 수량 값은 <count>
치환자를 대체하게 된다.
범위를 사용할 때에는 숫자가 아닌 특수한 기호를 사용할 수 있다. 예를 들어 구두점(.
)은 현재 라인을 의미하고 $
는 마지막 라인, %
는 버퍼 전체를 의미한다. 그런데 이 문자들은 상황이나 맥락에 따라서는 다른 의미를 갖기도 한다. %
현재 버퍼 전체의 범위를 의미할 때도 있지만, 현재 버퍼의 이름을 의미할 때도 있다. 이처럼 범위가 행번호가 아닌 탭이나 창과 같이 다른 것으로 해석될 필요가 있는 경우에 이를 구분해주기 위해서 -addr=
속성을 사용한다.
-addr=lines
: 디폴트이며, 범위는 행번호들을 의미한다.arguments
,buffers(buf)
,loaded_buffers(load)
,windows(win)
,tabs(tab)
,quickfix(qf)
,other(?)
와 같은 맥락이 있다.
기타 명령 속성
그외의 명령 속성에는 다음과 같은 것들이 있다.
-
-bang
:!
를 붙여서 사용할 수 있게 해준다.<bang>
치환자를 사용한다. -bar
: 사용자 정의명령이|
를 사용해서 다른 명령과 연결될 수 있도록 허용한다.-regiser
::del
,:put
등의 명령처럼, 레지스터를 첫 인자로 사용하게 한다.<register> / <reg>
로 치환한다.-buffer
: 현재 버퍼에서만 사용되는 명령을 만든다.