요약

  • vim에서 자동완성을 사용하는 방법은 엄청나게 많다.
  • 이 글에서는 네 가지 방법을 소개한다.
    • <C-p>, <C-n> 사용
      • vim의 기본 자동완성이며, 어떤 플러그인도 없는 기본 vim에서도 사용할 수 있다.
    • <C-x> 사용
      • 이 기능은 서버의 설정 파일을 수정하는 데에만 vim을 쓰는 사람에게 특히 유용할 것이다.
    • :abbreviate 사용
      • vim의 기본 자동완성이며, 어떤 플러그인도 없는 기본 vim에서도 사용할 수 있다.
      • 평범한 자동완성으로도 사용할 수 있을 뿐만 아니라, 셸 스크립트도 실행할 수 있다.
    • youcompleteme + UltiSnips 사용
      • 자신만의 snippet 파일을 만들어가며 점점 더 편해지는 즐거움이 있다.
      • 셸 스크립트를 실행할 수 있으며, python 코드도 돌아가기 때문에 자유도가 높다.

<C-p>, <C-n>

Vim의 기본 자동완성이라 할 수 있다.

  • <C-p>: ctrl + p 를 의미한다.
  • <C-n>: ctrl + n 을 의미한다.

insert 모드에서 <C-p> 또는 <C-n>을 입력하면, complete옵션에서 지정한 위치의 키워드를 기반으로 자동완성해준다.

  • IDE의 자동완성과는 다르게, 주석이나 문자열 안에 있는 단어들도 모두 찾아준다.
  • 보통은 아무런 설정 없이 insert 모드에서 <C-p>, <C-n> 만 눌러도 vim의 단어 완성을 사용할 수 있다.
    • 더 자세히 알고 싶지 않다면 아래의 complete 옵션은 읽지 않아도 좋다.

complete 옵션

다음 명령으로 내 complete가 어떻게 설정되어 있는지 확인할 수 있다.

:set complete?

나는 다음과 같이 설정되어 있는데, 내가 직접 한 건 아니고 ycm 등이 자동으로 설정해준 것 같다.

complete=.,w,b,u,t,i
  • .: 현재 편집중인 버퍼의 모든 단어를 자동완성 소스로 사용한다.
  • w: vim에 현재 열려 있는 window들의 모든 단어를 사용한다.
  • b: 버퍼 리스트에 있고 로드된 버퍼들의 모든 단어를 사용한다.
  • u: 버퍼 리스트에 있고 로드되지 않은 버퍼들의 모든 단어를 사용한다.
  • t: tag completion을 사용한다. ctags를 사용한다면 당연한 설정.
  • i: 현재 파일과 include된 파일의 단어를 사용한다.

자세한 내용은 :help complete로 확인.

<C-x>

  • ctrl + x 입력.

insert 모드에서만 지원하는 자동완성 기능이다.

10가지 이상의 기능이 있지만 내가 자주 쓰는 두 가지만 나열해 본다.

  • <C-x><C-l> : 라인 단위 자동 완성. 단어 완성이 아니라 줄 전체를 완성해 준다.
  • <C-x><C-f> : 파일명, 경로 자동완성. vim을 즐겨 쓰지 않는 사람이라도 이 기능은 유용할 것이다.
    • 설정파일을 수정하는 데에만 vim을 쓴다면 특히 이 기능은 유용하다.
    • 예를 들어 ~/ 를 쓰고 ctrl+x ctrl-f 를 입력하면, home 경로의 파일들 (.bashrc 등등) 이름이 자동완성된다.

:abbreviate

  • 축약어(abbreviation)를 등록할 수 있다.
  • insert, command-line 모드에서만 작동하는 일종의 자동 완성 기능.
    • abbr: insert, command-line 모드 양쪽에서 작동.
    • iabbr: insert 모드에서만 작동
    • cabbr: command-line 모드에서만 작동
  • :ab로 써도 작동한다.
    • 이러면 너무 짧아서 헷갈릴 수 있으니 나는 :abbr로 사용하고 있다.

오타 교정

가장 쉬운 사용 방법은 자신이 자주 내는 오타를 등록해 자동으로 교정되도록 하는 것이다.

:abbr consolee console

위와 같이 설정하면 consolee.log 라고 오타를 쳐도 console.log로 자동으로 교정된다.

:abbr coment comment

coment 이라 썼을 때 comment로 교정된다.

자동완성으로 활용

눈치가 빠른 사람이라면 위의 예제를 보고 다음 기능을 생각해냈을 것이다.

:abbr cns console.log()

cns라 입력하면 console.log()가 자동으로 완성된다.

:abbr cmt /* */

cmt라 입력하면 /* */가 자동으로 완성된다.

normal 모드를 활용하자

<Esc>를 사용하면 normal모드로 들어갈 수 있다.

:abbr _cmt /* */<Esc>hhi

이제 _cmt라 입력하면 /* */가 자동으로 완성되고, 커서가 가운데의 스페이스 부분으로 이동해 있다.

  • _cmt 앞에 _를 붙인 이유는 cmt를 그냥 작성할 때 멋대로 자동 완성이 되어서 골치아플 수도 있기 때문이다.

이 기능을 사용하면 import, if, for 문과 같은 괄호가 많고 줄바꿈이 있는 형태의 템플릿을 만들어 두고 사용할 수 있다.

  • 하지만 abbr을 snippet 용도로 쓰는 것은 별로 추천하지 않는다.
    • abbr은 본래 snippet 자동완성이 아니라 축약어 기능이라는 점에 주의.
    • snippet 용도로 사용하는 것은 UltiSnips쪽이 훨씬 강력하고 abbr 특유의 이런저런 짜증나는 문제가 없다.

vim 스크립트 실행 기능

<expr>을 사용하면 스크립트 실행 결과로 완성해 준다.

다음은 내 vimrc 파일에 넣어두고 사용하고 있는 abbr이다.

iabbr __email abcd@efgh.com
iabbr <expr> __time strftime("%Y-%m-%d %H:%M:%S")
iabbr <expr> __file expand('%:p')
iabbr <expr> __name expand('%')
iabbr <expr> __pwd expand('%:p:h')
iabbr <expr> __branch system("git rev-parse --abbrev-ref HEAD")

하나하나 살펴보자.

  • __time
    • vim 내장 함수인 strftime을 실행하여 나온 결과(현재 시간)로 완성해 준다.
    • 예: __time을 입력하면 2018-11-23 09:25:07와 같이 나온다.
  • __file
    • vim 내장 함수인 expand를 실행하여 나온 결과(현재 편집중인 파일의 전체 경로)로 완성해 준다.
    • 예: __file을 입력하면 /Users/jg/johngrib.github.io/_wiki/vim-auto-completion.md가 나온다.
  • __name, __pwd
    • 뻔하니 생략.
  • __branch
    • 현재 git branch를 완성해 준다.

shell 스크립트 실행 기능

마지막 예제인 __branch에서 사용한 system 함수에 주목하자.

이걸 쓰면 셸 명령어를 호출해 출력된 결과로 완성할 수 있다.

따라서 __timestrftime은 다음과 같이 대체할 수 있다.

:iabbr <expr> _time system("date '+%Y-%m-%d %H:%M:%S'")

__pwd는 다음과 같이 대체할 수 있다.

:iabbr <expr> _pwd system("pwd")

당연히 자신이 작성한 셸 스크립트를 실행할 수도 있다.

셸 스크립트 뿐만이 아니라 자신이 좋아하는 프로그래밍 언어로 작성한 도구를 호출해 사용할 수도 있다.

이를 응용하면 여러 가지 흑마법이 가능하지만, 이 글의 주제는 아니므로 다루지 않는다.

자동완성 플러그인 사용하기

이 글에서는 다음의 세 플러그인을 다룬다.

  • youcompleteme
  • coc.nvim
  • UltiSnips

나는 2019년 6월 이전까지는 youcompleteme + UltiSnips 조합으로 사용해왔으나, 그 이후로는 coc.nvim + UltiSnips 조합으로만 사용하고 있다.

youcompleteme

ycm과 UltiSnips를 활용하면 편리한 자동완성 환경을 갖출 수 있다.

ycm 설치

경험상 ycm을 문제 없이 설치하려면 다음과 같이 해야 했다.

  • vim 설치시 --with-python3 옵션을 준다.
    • 요즘은 디폴트 옵션이 되어서, 이제 저 옵션을 생략해도 된다.
  • 자동 완성 기능을 사용할 언어의 컴파일러를 각각 설치한다. (특히 새 컴퓨터에서 주의)
  • ycm 플러그인 설치 후 python3를 사용해 ycm의 install.py를 실행한다.
    • 반드시 주로 사용하는 언어를 옵션으로 지정해 준다.
      • 언어 옵션은 python3 ./install.py --help로 확인할 수 있다.
    • vim-plug를 사용하면 이 귀찮은 작업을 간편하게 자동화할 수 있다.
    • vim-plug는 vim 플러그인을 clone만 하지 않고, 지정한 셸 명령을 실행해 주기 때문이다.

경험상 ycm은 그냥 설치하지 말고, 자신이 주로 사용하는 언어의 completer를 옵션으로 줘야 문제 없이 잘 설치되는 것 같다.

  • 단, youcompleteme의 java 지원은 별로다.
    • --java-completer는 사용하지 않기를 권장한다.

다음은 내 ycm 플러그인 설치 설정이다. 플러그인 관리자는 vim-plug.

Plug 'valloric/youcompleteme', { 'do': 'python3 ./install.py --clang-completer --go-completer --rust-completer --js-completer'}

만약 vim-plug를 사용하지 않거나, 다른 문제가 있다면 youcompleteme가 설치된 경로(~/.vim 의 하위 디렉토리를 찾아볼 것)로 찾아 들어가 명령어를 입력해 수동으로 설치한다.

다음은 내가 사용하는 설치 명령어이다.

$ python3 ./install.py --clang-completer --go-completer --rust-completer --js-completer

ycm 설정

다음은 나의 ycm 설정 전체이다.

let g:ycm_key_list_select_completion = ['<C-n>']
let g:ycm_key_list_previous_completion=['<C-p>']

let g:ycm_server_python_interpreter = '/usr/local/bin/python3'
let g:ycm_collect_identifiers_from_comments_and_strings = 1
let g:ycm_complete_in_strings = 1
let g:ycm_complete_in_comments = 1
let g:ycm_min_num_of_chars_for_completion = 1
let g:ycm_filetype_blacklist = {}
키 설정

나는 첫번째와 두 번째, list completion 키를 <C-n>, <C-p>를 설정해 사용하고 있다.

let g:ycm_key_list_select_completion = ['<C-n>']
let g:ycm_key_list_previous_completion=['<C-p>']
  • 기본값인 <Tab>을 쓰면 UltiSnips의 <Tab>과 충돌하기 때문에 ycm/UltiSnips 둘 중 하나는 바꿔줘야 한다.
  • vim은 기본적으로 <C-n>, <C-p>를 사용해 단어 완성을 해주는데 ycm을 이렇게 설정해주면 vim 기본 동작이 확장된 것처럼 작동해서 사용감이 좋다.
python 경로 설정
let g:ycm_server_python_interpreter = '/usr/local/bin/python3'
  • ycm은 python을 사용하므로 경로를 지정해 줘야 돌아간다.
  • 위치를 모르겠다면(그럴리가) $ which python3로 알아낼 수 있다.
자동 완성 소스로 주석과 문자열 추가 지정
let g:ycm_collect_identifiers_from_comments_and_strings = 1
let g:ycm_complete_in_strings = 1
let g:ycm_complete_in_comments = 1
  • 이렇게 하면 주석과 문자열도 자동 완성에 사용할 소스로 수집한다.
  • 주석에 들어간 단어들이 자동완성되면 은근히 편리하다.
한 글자만 입력해도 작동할 것
let g:ycm_min_num_of_chars_for_completion = 1
  • 이렇게 하면 한 글자만 입력해도 자동완성 후보 목록을 보여준다.
블랙리스트 목록 비우기
let g:ycm_filetype_blacklist = {}
  • 이렇게 하면 ycm이 모든 파일 타입에서 자동 완성 후보를 보여준다.
  • 참고로 ycm이 기본적으로 무시하도록 되어 있는 파일 타입은 다음과 같다.
let g:ycm_filetype_blacklist = {
    \ 'tagbar' : 1,
    \ 'qf' : 1,
    \ 'notes' : 1,
    \ 'markdown' : 1,
    \ 'unite' : 1,
    \ 'text' : 1,
    \ 'vimwiki' : 1,
    \ 'pandoc' : 1,
    \ 'infolog' : 1,
    \ 'mail' : 1
    \}

ultisnips

이 항목은 별도의 문서로 분리하였다.

  • [[ultisnips]]

coc.nvim

  • coc.nvim은 VSCode와 비슷한 수준의 자동완성 기능을 제공하는 것을 목표로 하는 vim 플러그인이다.
  • 사용해보면 매우 만족스럽다. VSCode 만큼은 된다.
    • youcompleteme에서 잘 안 되는 언어들이 매우 잘 되며, php/javascript 자동완성도 훌륭하다.
    • UltiSnips와의 연동도 youcompleteme 만큼은 된다.

coc.nvim 설치

Node.js와 yarn을 먼저 설치한 다음, .vimrc에서 다음과 같이 플러그인을 정의해주면 된다.

Plug 'neoclide/coc.nvim', {'tag': '*', 'do': './install.sh'}

필요한 프로그래밍 언어의 랭귀지 서버 설치

  1. coc.nvim의 Language-servers 문서에서 내가 사용하는 언어를 찾는다.
  2. 해당 언어 섹션에서 coc.nvim이 추천하는 랭귀지 서버 플러그인을 찾는다.
  3. 해당 랭귀지 서버 플러그인 저장소에 가서 추천하는 설치 방법으로 설치한다.

보통은 :CocInstall 명령어를 사용해 필요한 언어의 랭귀지 서버를 설치하면 끝난다. 매우 간편하다.

golang 랭귀지 서버 설치

go 작성자들이 제공하는 gopls를 사용하도록 coc-settings.json에 다음과 같이 설정을 추가해주면 된다.

coc-settings.json 파일은 :CocConfig 명령어를 입력하면 vim에서 바로 열 수 있다.

{
    "suggest.detailField": "abbr",
    "suggest.enablePreview": false,
    "languageserver": {
        "golang": {
            "command": "gopls",
            "rootPatterns": ["go.mod", ".vim/", ".git/", ".hg/"],
            "filetypes": ["go"]
        }
    }
}
php 랭귀지 서버 설치
:CocInstall coc-phpls
UltiSnips와의 연동
:CocInstall coc-ultisnips

문제 해결

neovim 에서 ycm, UltiSnips가 돌아가지 않는 문제 해결하기

neovim에서 실행하면 다음과 같이 출력되며 ycm과 UltiSnips를 사용할 수 없다고 나온다.

$ nvim
YouCompleteMe unavailable: requires Vim compiled with Python (2.7.1+ or 3.4+) support.
UltiSnips requires py >= 2.7 or py3

ycm과 UltiSnips가 vim의 python support를 쓰기 때문에 생기는 문제다.

pip로 neovim을 업그레이드하면 해결되는 문제이므로 신경을 끄도록 하자.

$ sudo pip3 install --upgrade neovim