C++ 공부 해보려고 윈도우에서 소켓을 구현했는데 IO Event(IOCP, epoll, kqueue 등) 라던지, 소켓 내부 구현체가 리눅스와 달라서 직접 리눅스를 설치하고 개발을 해보려고 합니다! 후회중 😭

vim

리눅스는 Arch linux 를 설치했고 데스크탑 환경은 KDE Plasma 를 선택했습니다.

vim 기본 설정

처음 vim 을 설치하고 실행하면 정말 아무것도 없습니다. 까만 화면에 커서 하나만 있습니다. 농담이 아닙니다?

기본적으로 파일 인코딩, 라인 넘버, 탭 사이즈 등 기본적인 설정을 먼저 해줄겁니다.

vim ~/.vimrc 를 입력하고 기호에 맞게 설정을 추가하세요! 😀

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
set encoding=utf-8

" 라인 넘버 출력
set number
set numberwidth=5

" 현재 줄 기준으로 상대 표시
set relativenumber

" 탭 대신 공백, 탭 사이즈
set expandtab
set tabstop=4
set softtabstop=4
set shiftwidth=4
set smarttab

" 따옴표, 괄호 짝 강조
set showmatch

" 상태 표시줄 출력
set ruler

" 검색 시 대소문자 구분 안함
set ignorecase
" 대문자 있으면 구분함
set smartcase
" 점진적 검색 및 강조
set incsearch
set hlsearch

" 백스페이스로 이전 줄도 지움
set bs=indent,eol,start

" vim 명령어 기록 및 OS 클립보드 사용
set history=1000
set clipboard=unnamedplus

기본 설정을 마쳤으면 플러그인을 설치해 보도록 하겠습니다.

👨‍💼 vim-plug

플러그인을 쉽게 설치하고 제거할 수 있게 해주는 플러그인 매니저입니다. 플러그인 매니저는 vim-plug 이외에 여러가지가 있지만 이 플러그인이 빠르고 간단해서 선택하게 되었습니다.

설치를 위해 홈디렉터리에서 아래 명령어를 입력해서 스크립트를 받습니다.

1
2
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

autoload 디렉터리에 vim 스크립트가 저장되었기 때문에 실행할 때마다 플러그인 매니저가 같이 올라올겁니다.

플러그인 추가는 ~/.vimrc 파일에 아래와 같이

이제 본격적으로 C++ 개발을 위한 플러그인을 받아보겠습니다.

🚀 coc-vim

요즘 개발환경에 빼놓을 수 없는 intellisense 를 먼저 받아보겠습니다. vim으로 개발하는 것은 함정

플러그인 설치 전 필요한 패키지가 있는데 바로 LSP 입니다.

💡 Quotation

IDE 상에서 다양한 프로그래밍 언어들에 대한 개발 편의 기능을 보편적으로 구현하기 위해 탄생한 프로토콜. 여기서의 개발 편의 기능에는 포맷팅, 자동 완성, 수정 제안, 구문 강조 등이 포함된다. - 나무위키

C++ 언어의 LSPclangdccls 가 있습니다. 여기에서는 ccls 를 사용하도록 하겠습니다. 우선 Arch linux 에서는 공식 리포지토리 외에도 AUR 이라는 유저 리포지토리도 있어서 저는 간단하게 설치했습니다.

리눅스 배포판에 맞게 clangd 또는 ccls 를 설치해주세요.

vim 에 플러그인을 추가하기 위해 .vimrc 파일에 다음과 같이 적어서 저장합니다.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
call plug#begin()
    Plug 'neoclide/coc.nvim', {'branch': 'release'}
call plug#end()

" coc-vim 단축키
" May need for Vim (not Neovim) since coc.nvim calculates byte offset by count
" utf-8 byte sequence
set encoding=utf-8
" Some servers have issues with backup files, see #649
set nobackup
set nowritebackup

" Having longer updatetime (default is 4000 ms = 4s) leads to noticeable
" delays and poor user experience
set updatetime=300

" Always show the signcolumn, otherwise it would shift the text each time
" diagnostics appear/become resolved
set signcolumn=yes

" Use tab for trigger completion with characters ahead and navigate
" NOTE: There's always complete item selected by default, you may want to enable
" no select by `"suggest.noselect": true` in your configuration file
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
" other plugin before putting this into your config
inoremap <silent><expr> <TAB>
      \ coc#pum#visible() ? coc#pum#next(1) :
      \ CheckBackspace() ? "\<Tab>" :
      \ coc#refresh()
inoremap <expr><S-TAB> coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"

" Make <CR> to accept selected completion item or notify coc.nvim to format
" <C-g>u breaks current undo, please make your own choice
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
                              \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

function! CheckBackspace() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

" Use <c-space> to trigger completion
if has('nvim')
  inoremap <silent><expr> <c-space> coc#refresh()
else
  inoremap <silent><expr> <c-@> coc#refresh()
endif

" Use `[g` and `]g` to navigate diagnostics
" Use `:CocDiagnostics` to get all diagnostics of current buffer in location list
nmap <silent><nowait> [g <Plug>(coc-diagnostic-prev)
nmap <silent><nowait> ]g <Plug>(coc-diagnostic-next)

" GoTo code navigation
nmap <silent><nowait> gd <Plug>(coc-definition)
nmap <silent><nowait> gy <Plug>(coc-type-definition)
nmap <silent><nowait> gi <Plug>(coc-implementation)
nmap <silent><nowait> gr <Plug>(coc-references)

" Use K to show documentation in preview window
nnoremap <silent> K :call ShowDocumentation()<CR>

function! ShowDocumentation()
  if CocAction('hasProvider', 'hover')
    call CocActionAsync('doHover')
  else
    call feedkeys('K', 'in')
  endif
endfunction

" Highlight the symbol and its references when holding the cursor
autocmd CursorHold * silent call CocActionAsync('highlight')

" Symbol renaming
nmap <leader>rn <Plug>(coc-rename)

" Formatting selected code
xmap <leader>f  <Plug>(coc-format-selected)
nmap <leader>f  <Plug>(coc-format-selected)

augroup mygroup
  autocmd!
  " Setup formatexpr specified filetype(s)
  autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
augroup end

" Applying code actions to the selected code block
" Example: `<leader>aap` for current paragraph
xmap <leader>a  <Plug>(coc-codeaction-selected)
nmap <leader>a  <Plug>(coc-codeaction-selected)

" Remap keys for applying code actions at the cursor position
nmap <leader>ac  <Plug>(coc-codeaction-cursor)
" Remap keys for apply code actions affect whole buffer
nmap <leader>as  <Plug>(coc-codeaction-source)
" Apply the most preferred quickfix action to fix diagnostic on the current line
nmap <leader>qf  <Plug>(coc-fix-current)

" Remap keys for applying refactor code actions
nmap <silent> <leader>re <Plug>(coc-codeaction-refactor)
xmap <silent> <leader>r  <Plug>(coc-codeaction-refactor-selected)
nmap <silent> <leader>r  <Plug>(coc-codeaction-refactor-selected)

" Run the Code Lens action on the current line
nmap <leader>cl  <Plug>(coc-codelens-action)

" Map function and class text objects
" NOTE: Requires 'textDocument.documentSymbol' support from the language server
xmap if <Plug>(coc-funcobj-i)
omap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap af <Plug>(coc-funcobj-a)
xmap ic <Plug>(coc-classobj-i)
omap ic <Plug>(coc-classobj-i)
xmap ac <Plug>(coc-classobj-a)
omap ac <Plug>(coc-classobj-a)

" Remap <C-f> and <C-b> to scroll float windows/popups
if has('nvim-0.4.0') || has('patch-8.2.0750')
  nnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
  nnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
  inoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(1)\<cr>" : "\<Right>"
  inoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(0)\<cr>" : "\<Left>"
  vnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
  vnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
endif

" Use CTRL-S for selections ranges
" Requires 'textDocument/selectionRange' support of language server
nmap <silent> <C-s> <Plug>(coc-range-select)
xmap <silent> <C-s> <Plug>(coc-range-select)

" Add `:Format` command to format current buffer
command! -nargs=0 Format :call CocActionAsync('format')

" Add `:Fold` command to fold current buffer
command! -nargs=? Fold :call     CocAction('fold', <f-args>)

" Add `:OR` command for organize imports of the current buffer
command! -nargs=0 OR   :call     CocActionAsync('runCommand', 'editor.action.organizeImport')

" Add (Neo)Vim's native statusline support
" NOTE: Please see `:h coc-status` for integrations with external plugins that
" provide custom statusline: lightline.vim, vim-airline
set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}

" Mappings for CoCList
" Show all diagnostics
nnoremap <silent><nowait> <space>a  :<C-u>CocList diagnostics<cr>
" Manage extensions
nnoremap <silent><nowait> <space>e  :<C-u>CocList extensions<cr>
" Show commands
nnoremap <silent><nowait> <space>c  :<C-u>CocList commands<cr>
" Find symbol of current document
nnoremap <silent><nowait> <space>o  :<C-u>CocList outline<cr>
" Search workspace symbols
nnoremap <silent><nowait> <space>s  :<C-u>CocList -I symbols<cr>
" Do default action for next item
nnoremap <silent><nowait> <space>j  :<C-u>CocNext<CR>
" Do default action for previous item
nnoremap <silent><nowait> <space>k  :<C-u>CocPrev<CR>
" Resume latest coc list
nnoremap <silent><nowait> <space>p  :<C-u>CocListResume<CR>

vim 을 재시작해서 :PlugInstall 명령어를 실행 시켜주세요.
다시 재시작하여 :CocConfig 를 입력해서 아래와 같이 적고 저장해 주세요.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "languageserver": {
    "ccls": {
      "command": "ccls",
      "filetypes": ["c", "cc", "cpp", "c++", "objc", "objcpp"],
      "rootPatterns": [".ccls", "compile_commands.json", ".git/", ".hg/"],
      "initializationOptions": {
        "cache": {
          "directory": "/tmp/ccls"
        }
      }
    },
    "cmake": {
      "command": "cmake-language-server",
      "filetypes": ["cmake"],
      "rootPatterns": [
        "build/"
      ],
      "initializationOptions": {
        "buildDirectory": "build"
      }
    }
  }
}

:CocList 에서 service 를 선택하면 현재 LSP 상태를 볼 수 있습니다! 👍

coc-vim

😎 Other plugs

  1. vim-fugitive: vim 내부에서 git 명령어를 사용합니다.
  2. vim-airline: 상태 표시줄과 탭을 표시합니다.
  3. vim-airline-theme: 상태 표시줄과 탭에 테마를 입힙니다.
  4. ctrlp: fzf 를 이용하여 파일을 찾습니다. (한글 파일명 ❌)
  5. auto-pairs: 따옴표나 괄호가 열리면 바로 반대쪽을 입력해줍니다.
  6. vim-devicons: 아이콘팩입니다.

vim awesome 사이트에 더 많은 플러그인들이 소개되어 있으니 한번쯤 둘러보는 것도 괜찮을 것 같습니다.

정리

  1. vim 은 진입장벽이 정말 높다. VS CodeVisual studio 만 사용하다가 vim 을 사용하려고 하면 답답해서 열불이 터진다.
  2. 사용하고 익힌 만큼 돌아온다. 코드를 작성할 때 마우스를 사용하지 않아 더 깊게 집중할 수 있다.
  3. 잘 쓰는 사람들의 생산성은 어떨지 모르겠지만, 익숙해지기 전까지 생산성에 욕심부리지 말자.