본문 바로가기

Software

Vim 에디터 사용법 설명 및 C++/Python 개발환경설정

1. Introduction

본 포스트에서는 리눅스에서 vim 에디터를 통해 c++ 또는 python 개발환경을 구축하는 방법에 대하여 설명한다. 본 포스트에서 vim의 코드 네비게이션 플러그인은 youcompleteme 과 vim-lsp 를 사용하였는데 youcompleteme 의 경우 2016년에 등장한 vim-lsp 이전까지는 vim에서 독보적으로 강력한 코드 네비게이션 플러그인이었으나 다양한 프로그래밍 언어를 지원하는 vim-lsp 가 등장하면서 현재는 둘 다 많이 사용하고 있는 상황이 되었다.

포스트를 작성하는 시점(2020.09)을 기준으로 youcompleteme 플러그인은 설치하는 과정은 간단하지만 실제로 사용할 때 약간의 세팅이 복잡한 반면, vim-lsp 플러그인은 vim, clang 버전 문제로 설치 과정이 약간 복잡하지만 설치하고 난 후 실제로 사용할 때는 매우 간단하게 사용할 수 있다. 실제로 테스트해 본 결과 두 플러그인 모두 속도와 기능면에서는 차이가 없었고 둘 중 하나만 사용해도 독립적으로 충분한 기능을 제공하기 때문에 원하는 환경설정을 사용하면 된다. vimrc1(ycm), vimrc2(vim-lsp)

vim 에디터의 폰트는 Hack 를 사용하였으며 테마는 codedark 를 사용하였다. 대부분의 내용을 c++ 코드를 통해 설명하였는데 python 코딩을 할 때도 동일한 기능들이 적용된다. 포스트에서 설명하는 모든 내용들은 우분투 18.04 LTS 환경에서 테스트하였다.

 

Tip
INSERT MODE에서 NORMAL MODE로 넘어가려면 일반적으로 <ESC> 키를 눌러야 한다. 하지만 vim에서는 기본적으로 <C-[> 키를 사용하여 <ESC>를 누르는 것과 동일하게 NORMAL MODE로 넘어갈 수 있다. 코딩을 하다보면 두 모드를 왔다갔다 할 일이 매우 빈번한데 그럴 때마다 <ESC>를 누르려면 손가락의 위치를 많이 움직여야 하므로 은근히 귀찮을 수 있다. 그럴 때는 <C-[>키를 활용해보자.

 

2. How to set up 

포스팅 시점(2020.09) 기준으로 vim-lsp 를 사용하기 위해서는 vim 8.2 버전을 설치해야 하기 때문에 이를 설치하기 위해서는 vim-lsp 섹션의 C++ 섹션으로 가서 해당 버전을 설치하면 된다. ycm 을 사용하는 경우 모든 버전에서 정상적으로 작동하는 것을 확인하였다. ycm 의 경우 터미널을 연 다음 아래 명령어로 vim을 설치한다.

$ sudo apt install vim

다음으로 Vundle 플러그인을 설치한다. Vundle 플러그인은 다른 플러그인들을 쉽게 다운로드해줄 수 있는 플러그인이다. 다음 명령어를 통해 Vundle 플러그인을 설치한다.

# Make ~/.vim/bundle directory.
$ mkdir ~/.vim/bundle -p
$ cd ~/.vim/bundle
$ git clone https://github.com/VundleVim/Vundle.vim

Vundle 플러그인이 정상적으로 다운로드되었다면 다른 플러그인들을 설치할 준비가 되었다. vimrc1(ycm), vimrc2(vim-lsp) 둘 중 하나를 다운로드 받은 후 홈폴더로 이동시킨다. 이 때, vimrc 파일 이름 앞에 점(.)을 추가해야 정상적으로 vim에서 인식한다. 그리고 codedark 테마 파일을 다운로드 받은 후 ~/.vim/colors 폴더로 이동시킨다.

# Move .vimrc to home folder.
$ mv  ~/Downloads/vimrc1_ycm  ~/.vimrc
# or
$ mv  ~/Downloads/vimrc2_lsp  ~/.vimrc

# Move codedark.vim to ~/.vim/colors folder.
$ mkdir ~/.vim/colors -p
$ mv  ~/Downloads/codedark.vim  ~/.vim/colors

다음으로 플러그인들을 설치한다. 우선 .vimrc 파일을 연다.

$ vim  ~/.vimrc

.vimrc 파일이 열렸다면 :BundleInstall 명령을 실행한다. 명령이 정상적으로 실행되면 .vimrc 파일에 등록되어 있는 여러 플러그인들이 Vundle 플러그인에 따라 순차적으로 설치된다. 여기까지 정상적으로 완료되었다면 youcompleteme 과 vim-lsp 의 자동완성 기능을 제외하고 모든 기능들이 정상적으로 설치되었다.

2.1. youcompleteme setting

(youcompleteme 또는 vim-lsp 플러그인 세팅 중 하나만 사용하면 된다.)

youcompleteme (ycm) 플러그인은 vim에서 사용할 수 있는 코드 자동완성 및 코드 네비게이션 플러그인이다. ycm 플러그인은 다운로드 받는 후 바로 작동하지 않고 별도의 설치를 통해 사용할 수 있다.

우선 Vundle을 통해 다운로드 받은 후 bundle/youcompleteme 폴더로 이동한다.

$ cd  ~/.vim/bundle/youcompleteme

다음으로 ycm 을 설치한다. ycm 은 다양한 언어의 자동완성을 지원하는데 해당 포스트에서는 c++/python 개발환경에 맞게 해당 모듈들만 설치한다. 필자가 알고 있는 한 python은 별도로 모듈을 설치해주지 않아도 자동완성이 되는 것으로 알고 있다. 따라서 c++ 자동완성 모듈만 설치해준다.

# Current folder: ~/.vim/bundle/youcompleteme/
# Install ycm (for c++)
$ python3  ./install.py  --clang-completer 

정상적으로 설치가 완료되었다면 .ycm_extra_conf.py 파일을 ~/.vim 디렉토리로 복사한다. .ycm_extra_conf.py 파일의 역할은 다음 섹션에서 설명한다.

# Copy .ycm_extra_conf.py to ~/.vim
$ cp  ~/.vim/bundle/youcompleteme/third_party/ycmd/.ycm_extra_conf.py  ~/.vim/

2.1.1. C++

앞서 복사한 ~/.vim/.ycm_extra_conf.py 파일은 /usr/include, /usr/local/include 폴더에서 표준헤더 파일을 읽은 후 시스템에 설치된 표준헤더들에 대해 자동완성을 수행한다. 따라서 c++의 경우 vector, map, algorithm 같은 표준헤더들의 자동완성이 가능해진다. 하지만 개발자가 임의로 선언한 클래스, 멤버함수, 멤버변수에 대한 자동완성 기능은 지원하지 않는다. 임의로 선언한 함수 및 변수들의 자동완성을 수행하기 위해서는 다음과 같은 순서로 진행해야 한다. 단, 해당 기능은 cmake로 개발중인 프로젝트에 한하여 적용된다.

cmake 프로젝트에서 빌드를 수행할 때 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 옵션을 추가하여 build 폴더에 compile_commands.json 파일이 생성되도록 한다. 코드를 반드시 빌드하지(make) 않아도 해당 json 파일만 생성되면 네비게이션이 된다.

# In cmake project, make build folder and go to the folder.
$ mkdir build
$ cd build

# This option creates 'compile_commands.json' file.
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..

~/.vim/.ycm_extra_conf.py 파일을 cmake 프로젝트의 가장 최상단에 복사하고 앞서 생성한 compile_commands.json 파일을 프로젝트 최상단에 링크 파일로 세팅한다.

# Copy .ycm_extra_conf.py file to the root of the cmake project.
$ cp  ~/.vim/.ycm_extra_conf.py  /path/to/cmake/project/

# Create a soft link of compile_commands.json file to the cmake project root path.
$ cd /path/to/cmake/project/
$ ln -s ./build/compile_commands.json ./

.ycm_extra_conf.py 의 107번 정도 라인의 compilation_database_folder 변수에 compile_commands.json 링크 파일이 존재하는 경로를 입력한다.

# Open .ycm_extra_conf.py
$ vim /path/to/cmake/project/.ycm_extra_conf.py

# At line 107, there is compilation_database_folder variable.
compilation_database_folder='./'

cmake 프로젝트의 최상단 디렉토리에서 vim을 실행한 후 프로그래밍한다.

위와 같이 새로운 cmake 프로젝트를 생성할 때마다 최상위 폴더에 .ycm_extra_conf.py 를 복사한 후 위 방법과 같이 진행하면 임의로 작성한 코드에 대한 자동완성과 코드 네비게이션 기능을 사용할 수 있다.

모든 세팅이 정상적으로 완료된 경우 위와 같이 임의로 작성한 코드 및 기본 헤더 코드에 대한 자동완성 기능을 사용할 수 있다.

그리고 위와 같이 함수 및 변수로 이동(코드 네비게이션) 또한 가능하다.

2.1.2. Python

파이썬 코드를 ycm 플러그인으로 네비게이션하려는 경우 C++과 달리 별도의 과정없이 파일을 열면 자동으로 코드 인식이 된다. 따라서 앞서 설명한 것처럼 .ycm_extra_conf.py 파일이 ~/.vim/.ycm_extra_conf.py 경로에만 있다면 어느 경로에서도 코드 네비게이션이 가능하다.

위와 같이 코드 자동완성 및 함수 및 변수로 이동이 가능해진다.

2.2. vim-lsp setting

(youcompleteme 또는 vim-lsp 플러그인 세팅 중 하나만 사용하면 된다.)

2.2.1.C++

현재(2020.09) 기준으로 테스트해 본 결과 vim-lsp 는 vim 7.x, 8.0, 8.1 버전에서 에러 구문 체크 기능이 정상적으로 작동하지 않고 vim 8.2 버전에서만 정상적으로 작동했다. 또한 clangd-9 버전 이상을 사용해야 정상적으로 코드 네비게이션이 가능했다. 따라서 해당 섹션에서는 Ubuntu 18.04 LTS, vim 8.2, clangd-9 버전을 사용하여 진행하였다. vim 8.2 버전은 vim ftp 사이트 에서 소스코드를 다운로드 받은 후 설치 스크립트를 통해 빌드 후 사용하면 된다. clangd-9은 다음 명령을 통해 설치하면 된다.

$ sudo apt install clangd-9 

vim-lsp 는 ycm 과 달리 .ycm_extra_conf.py를 사용하지 않고도 compile_commands.json 파일이 cmake 프로젝트 최상단에 링크 파일로 존재하면 자동으로 인식된다. 따라서 다음과 같이 진행한다.

cmake 프로젝트에서 빌드를 수행할 때 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 옵션을 추가하여 build 폴더에 compile_commands.json 파일이 생성되도록 한다. 코드를 반드시 빌드하지(make) 않아도 해당 json 파일만 생성되면 네비게이션이 된다.

# In cmake project, make build folder and go to the folder.
$ mkdir build
$ cd build

# This option creates 'compile_commands.json' file.
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..

앞서 생성한 compile_commands.json 파일을 프로젝트 최상단에 링크 파일로 세팅한다.

# Create a soft link of compile_commands.json file to the cmake project root path.
$ cd /path/to/cmake/project/
$ ln -s ./build/compile_commands.json ./

cmake 프로젝트의 최상단 디렉토리에서 vim을 실행한 후 프로그래밍한다.

모든 세팅이 정상적으로 완료된 경우 ycm 과 동일하게 임의로 작성한 코드 및 기본 헤더 코드에 대한 자동완성 기능을 사용할 수 있다.

그리고 ycm 과 동일하게 함수 및 변수로 이동(코드 네비게이션) 또한 가능하다.

2.2.2. Python

파이썬의 경우 C++과 달리 compile_commands.json 파일 없이도 자동완성이 지원된다. 단, vim-lsp 에서 해당 기능을 사용하기 위해서는 pyls 라는 프로그램을 설치해야 한다.

pyls 는 다음 명령어를 통해 쉽게 설치할 수 있다.

# Install pyls
$ pip install python-language-server --user

# Check pyls is installed successfully
$ pyls --help

위와 같이 ycm 과 동일하게 코드 자동완성 및 함수 및 변수로 이동이 가능해진다.

3. My vim configuration

해당 섹션에서는 필자가 사용하는 vim의 다양한 기본 기능 및 플러그인 기능들에 대해 설명한다. 사용하는 .vimrc 파일은 vimrc1(ycm), vimrc2(lsp) 에서 다운로드 받을 수 있다. 해당 키바인딩은 필자가 임의로 설정한 키바인딩이므로 원한다면 얼마든지 바꿔서 사용할 수 있다.

3.1. General features

Orignal keybindings 섹션의 경우 vim 자체의 기본 키바인딩을 설명하였다. 키바인딩을 임의로 바꾼 경우 Custom keybindings 섹션에 설명하였다. vim에는 수많은 기능 및 키바인딩들이 존재하지만 이를 다 설명하지 않고 실제로 자주 사용하는 키바인딩 위주로 설명하였다.

Control 키바인딩은 <C-{...}> 과 같이 표현하고 Alt 키바인딩은 <A-{...}> 으로 표현하였다. (NORMAL), (INSERT), (VISUAL)은 각 모드를 의미한다.

3.1.1. Original keybindings

3.1.1.1 h, j, k, l

(NORMAL) 커서를 상하좌우 방향으로 움직인다. 일반적으로 방향키 대신 사용한다.

3.1.1.2 <ESC>

(INSERT)=>(NORMAL) 모드로 변경한다.

3.1.1.3 a, A, i, I

(NORMAL)=>(INSERT) 모드로 변경한다. a,i는 현재 커서에서 한 칸 앞뒤에서 모드를 변경하며 A,I는 현재 라인의 맨 앞과 뒤로 이동한 후 모드를 변경한다.

3.1.1.4 s, S

(NORMAL)=>(INSERT) 모드로 변경할 때 s는 현재 커서의 칸을 지우면서 변경하고 S는 현재 라인 전체를 지우면서 변경한다.

3.1.1.5 o, O

(NORMAL)=>(INSERT) 모드로 변경한다. o는 현재 라인의 한 칸 아래에서 모드를 변경하며 O는 한 칸 위에서 모드를 변경한다.

3.1.1.6 dd, D

(NORMAL) 현재 라인의 코드를 지운다. dd는 한 줄 전체를 지우며 D는 현재 커서로부터 뒷칸을 전부 지운다.

3.1.1.7 yy, Y, p, P

(NORMAL) 현재 라인의 코드를 복사/붙여넣기한다. y,p로 인한 복사/붙여넣기는 클립보드에 저장되지 않고 vim에서만 사용한다. 즉, Ctrl + c, Ctrl + v처럼 다른 프로그램에 복붙이 불가능하다. p는 현재 커서 기준 한 칸 아래에 붙여넣기하며 P는 한 칸 위에 붙여넣기한다.

3.1.1.8 v, V

(NORMAL)=>(VISUAL) 모드로 변경한다. (VISUAL) 모드는 마우스 드래그를 통해 선택을 하는것과 동일한 효과를 가지는 모드이며 d,y,s 등 각종 키바인딩들을 응용할 수 있다. v는 한 칸 단위로 VISUAL 모드를 선택할 수 있으며 V는 현재 라인 전체를 VISUAL 모드로 변경한다.

3.1.1.9 <C-v>

(VISUAL) 커스텀 영역(Visual Block)을 선택할 수 있다. a,i,s,y,p 키와 응용해서 주로 사용한다.

3.1.1.10 r

(NORMAL) 현재 커서의 한 단어를 변경한다. (INSERT) 모드로 넘어가지 않고 변경할 수 있다.

3.1.1.11 gg, G

(NORMAL) 현재 파일의 가장 위로 가거나 가장 아래로 이동한다. gg는 가장 위로 이동하며 G는 가장 아래로 이동한다.

3.1.1.12 u

(NORMAL) 변경사항을 취소한다(undo).

3.1.1.13 z.

(NORMAL) 커서를 화면의 중앙으로 이동한다.

3.1.1.14 <C-u>, <C-d>

(NORMAL) 커서를 한 페이지 단위로 빠르게 이동한다. C-u 키를 사용하면 위로 이동하며 C-d 키를 사용하면 아래로 이동한다.

3.1.1.15 <C-a>

(NORMAL) 현재 커서의 뒷쪽에 있는 숫자를 1씩 증가시킨다.

3.1.1.16 /{search word}, n, N

(NORMAL) 특정 단어를 검색한다. n은 아래 방향으로 검색하며 N은 윗 방향으로 검색한다.

3.1.1.17 "+y, "+gP

(NORMAL) 선택 영역을 클립보드에 복사/붙여넣기한다. 일반 Ctrl + c, Ctrl + v와 동일한 복사/붙여넣기이다.

3.1.1.18 :e {file name}

(NORMAL) 특정 파일을 연다. :e! 는 현재 변경된 코드를 저장하지 않고 다른 파일을 연다는 의미이다.

3.1.1.19 :w

(NORMAL) 현재 파일을 저장한다.

3.1.1.20 :q

(NORMAL) 현재 파일을 닫는다. :q! 는 현재 변경된 코드를 저장하지 않고 닫는다는 의미이다.

3.1.1.21 :%s

(NORMAL) 특정 단어를 일괄적으로 변경한다.

3.1.1.22 :vsplit (:vs)

(NORMAL) 세로로 창을 분할한다.

3.1.1.23 :split (:sp)

(NORMAL) 가로로 창을 분할한다.

3.1.1.24 <C-w><C-w>, <C-w>ArrowKey

(NORMAL) 여러 창들을 이동한다.

3.1.1.25 <C-o>, <C-i>

(NORMAL) 이전에 열어놨던 여러 버퍼들로 이동한다. 예를 들어, A->B->C->D 파일 순서로 코딩을 진행하는 경우 키로 D->C->B->A 파일 순서로 네비게이션 할 수 있다. 다시 반대로 가고 싶은 경우 키를 사용하면 된다.

3.1.2. Custom keybindings

3.1.2.1 t

(NORMAL) 변수나 함수를 검색하는 경우 해당 단어가 하이라이팅되는데 이 때 t를 누르면 하이라이팅이 해제된다.

3.1.2.2 <C-d>

(INSERT) 현재 커서의 한 단어를 지운다. (NORMAL) 모드로 변경하지 않고 단어를 바로 지울 수 있다.

3.1.2.3 <C-f> 

(NORMAL) 현재 커서에서 한 칸 아래에 빈 칸을 생성한다. (INSERT) 모드로 변경하지 않고 빈 칸을 생성할 수 있다.

3.1.2.4 <C-h,j,k,l>

(NORMAL) 여러 창들을 이동한다.

3.1.2.5 U

(NORMAL) 실행취소했던 작업을 다시 원상복구한다(redo).

3.1.2.6 Q

(NORMAL) 현재 파일을 저장하지 않고 바로 종료한다. :q! 와 동일한 명령어이다.

3.1.2.7 , .

(NORMAL) 빈 칸 단위로 빠르게 코드를 네비게이션한다. 원래 키바인딩은 {, } 이지만 이를 , .로 변경하였다

3.1.2.8 <C-p>

(NORMAL) 현재 파일의 전체 경로를 상태창에 출력한다.

3.1.2.9 <C-z>

(INSERT) 모드에서 실행취소(undo)를 수행한다. (NORMAL) 모드로 넘어가지 않고 바로 실행취소할 수 있다.

3.1.2.10 <leader>s

(NORMAL) 현재 커서에 있는 단어들과 동일한 단어를 일괄적으로 변경한다. %s 는 단어를 직접 입력해야 하지만 해당 명령어는 커서에 있는 단어를 자동으로 선택해준다.

3.1.2.11 <C-e> , <A-e>

(NORMAL) 현재 라인의 맨 앞과 뒤로 이동한다. 이동한 후에도 (INSERT) 모드로 변경하지 않고 (NORMAL) 모드를 유지한다.

3.1.2.12 <C-c><C-c>, <C-c><C-v>

(NORMAL) 현재 창의 크기를 증가시킨다.

3.2. Plugin Features

3.2.1 The-NERD-tree

현재 폴더의 파일 목록을 볼 수 있는 플러그인

3.2.1.1 <C-n>

(NORMAL) NERD tree를 실행한다.

3.2.2 snipMate

(NORMAL) 특정 키워드를 입력 후 Tab을 누르면 미리 저장된 Snippet들이 나오는 플러그인

3.2.3 tComment

단축키를 통해 간편하게 코멘트를 적용할 수 있는 플러그인

3.2.3.1 <C-_><C-_>

(NORMAL) 현재 라인이나 선택영역을 코멘트화한다.

3.2.4 EasyMotion

코드 사이를 빠르게 네비게이션할 수 있는 플러그인

3.2.4.1 <leader><leader>w, b

(NORMAL) 현재 커서 기준으로 앞과 뒤를 빠르게 이동한다.

3.2.5 Mark

단어를 하이라이팅해주는 플러그인

3.2.5.1 <F4>, <F5>

(NORMAL) 현재 커서에 있는 단어를 마킹한다. F5를 통해 마킹하고 F4로 전체 취소할 수 있다.

3.2.6 tagbar

함수 및 변수 정보를 출력해주는 플러그인

3.2.6.1 <C-t>

(NORMAL) 현재 파일의 함수 및 변수 정보를 출력한다. ctags가 설치되어 있어야 한다. 아래 명령을 통해 설치한다.

$ sudo apt install ctags

3.2.7 youcompleteme, vim-lsp

코드 자동완성 및 네비게이션, 구문 체크 등을 해주는 플러그인. 위 그림은 틀린 구문을 체크해주는 모습이다. youcompleteme, vim-lsp 모두 c++/python 개발환경에서는 동일한 기능을 제공하므로 한 번에 설명하였다.

3.2.7.1 <A-.>, <A-,>

(NORMAL) 현재 커서의 함수 또는 변수의 정의로 이동한다. <A-.>을 통해 이동하고 <A-,>를 통해 원래 위치로 돌아온다.

3.2.7.2 <leader>f

(NORMAL) 현재 커서의 함수 또는 변수가 사용된 레퍼런스들을 표시한다.

3.2.8 vim-airline

vim 화면 위, 아래 상태바에 여러 정보들을 보여주는 플러그인

3.2.8.1 <leader>q, w, c

(NORMAL) q,w 키를 통해 다음 버퍼, 이전 버퍼로 이동한다. c를 통해 현재 버퍼를 닫을 수 있다.

3.2.9 vim-gitgutter

git 버전 관리에 의한 코드 변경내역을 표시해주는 플러그인

git을 통한 코드 변경내역이 감지되는 경우 표시해주는 플러그인이다. 위와 같이 코드 변경내역이 왼쪽 라인에 표시된다.

3.2.9.1 <leader>gn, gp

(NORMAL) gn, gp 키를 통해 코드 변경내역을 빠르게 네비게이션한다.

3.2.9.2 <leader>gr

(NORMAL) 현재 커서에 코드 변경내역이 있다면 이를 실행취소한다.

3.2.10 vim-diminactive

여러 창이 띄워져있을 때 현재 창을 하이라이팅해주는 플러그인

3.2.11 AutoClose

괄호 (), {}, [] 등을 자동으로 완성시켜주는 플러그인

3.2.12 vim-indent-guides

자동으로 코드의 들여쓰기를 해주는 플러그인. .vimrc 파일에서 let g:indent_guides_enable_on_vim_startup 변수를 1로 하면 vim이 시작할 때 같이 적용되며 0으로 하면 vim이 시작할 때 해당 플러그인은 적용되지 않는다.

3.2.13 vim-fugitive

:Gdiff, :Gblame과 같이 git 명령어를 사용할 수 있는 플러그인

3.2.14 vim-cpp-enhanced-highlight

c++ 코드를 하이라이팅해주는 플러그인. vim에서는 기본적으로 c++ 코드를 제대로 하이라이팅해주지 못하므로 가독성을 위해 사용한다.

4. References

  1. Naver blog 포스트
  2. vim을 강력하게 만들어줄 8가지 플러그인 - 개발자맛 Youtube
  3. 코딩할 때 vim이 최고인 이유. 개발환경 추천 영상 - 개발자맛 Youtube
  4. YouCompleteMe (YCM) 본격 vim을 IDE로 만들기 - nophotoplease 블로그