VSCode가 코드를 자동완성하고 에러를 표시하는 비결은 LSP(Language Server Protocol)예요. Neovim도 LSP를 내장 지원하기 때문에, 설정만 하면 IDE 수준의 기능을 쓸 수 있어요.
동작하는 코드
LSP란?
LSP는 에디터와 언어 서버 사이의 표준 프로토콜이에요. 하나의 에디터가 여러 언어를 지원하고, 하나의 언어 서버가 여러 에디터에서 동작할 수 있어요.
에디터 (Neovim) ←→ LSP 프로토콜 ←→ 언어 서버 (ts_ls, pyright 등)
플러그인 설치
~/.config/nvim/init.lua에 다음을 추가하세요. 여기서는 vim-plug을 사용할게요.
-- vim-plug 플러그인 선언
vim.cmd([[
call plug#begin('~/.local/share/nvim/plugged')
Plug 'neovim/nvim-lspconfig'
Plug 'williamboman/mason.nvim'
Plug 'williamboman/mason-lspconfig.nvim'
Plug 'nvim-telescope/telescope.nvim'
Plug 'nvim-lua/plenary.nvim'
call plug#end()
]])
Neovim을 열고 :PlugInstall을 실행하세요.
LSP 설정
플러그인 설치 후 아래 설정을 init.lua에 추가하세요.
-- Mason: 언어 서버 자동 설치
require('mason').setup()
require('mason-lspconfig').setup({
ensure_installed = { 'ts_ls', 'pyright' },
})
-- LSP 키맵 (서버가 연결되면 활성화)
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
local opts = { buffer = args.buf }
vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, opts)
vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, opts)
end,
})
-- 언어 서버 활성화
require('lspconfig').ts_ls.setup({})
require('lspconfig').pyright.setup({})
직접 수정하기
TypeScript나 Python 프로젝트를 하나 열어서 LSP 키바인딩을 직접 써 보세요.
| 키 | 동작 |
|---|---|
gd | 정의로 이동 (Go to Definition) |
K | 호버 문서 보기 |
<leader>rn | 이름 변경 (Rename) |
gr | 참조 목록 보기 (References) |
<leader>ca | 코드 액션 (Code Action) |
[d / ]d | 이전/다음 진단 메시지 이동 |
Telescope로 검색하기
Telescope는 퍼지 검색 도구예요. 파일, 텍스트, LSP 심볼까지 검색할 수 있어요.
local telescope = require('telescope.builtin')
vim.keymap.set('n', '<leader>ff', telescope.find_files, { desc = '파일 검색' })
vim.keymap.set('n', '<leader>fg', telescope.live_grep, { desc = '텍스트 검색' })
vim.keymap.set('n', '<leader>fb', telescope.buffers, { desc = '버퍼 검색' })
vim.keymap.set('n', '<leader>fs', telescope.lsp_document_symbols, { desc = '심볼 검색' })
<leader>ff를 누르면 프로젝트의 모든 파일을 빠르게 찾을 수 있어요.
"왜?"
왜 LSP를 쓸까요? 예전에는 에디터마다, 언어마다 별도의 플러그인을 만들어야 했어요. M개 에디터 x N개 언어 = M*N개의 플러그인이 필요했죠. LSP는 이 문제를 해결해요.
- 에디터 개발자: LSP 클라이언트만 구현하면 모든 언어 지원
- 언어 개발자: 언어 서버만 만들면 모든 에디터에서 동작
- 사용자: 어떤 에디터를 쓰든 같은 수준의 언어 지원
Mason은 언어 서버의 설치와 관리를 자동화해 줘요. :Mason을 실행하면 설치 가능한 서버 목록을 볼 수 있어요.
심화 학습
자동완성 설정 (nvim-cmp)
LSP만으로도 K(호버)와 gd(정의 이동)는 되지만, 타이핑하면서 자동으로 후보가 뜨는 자동완성은 nvim-cmp 플러그인이 필요해요.
-- 플러그인 추가 (vim-plug)
-- Plug 'hrsh7th/nvim-cmp'
-- Plug 'hrsh7th/cmp-nvim-lsp'
-- 기본 설정
local cmp = require('cmp')
cmp.setup({
sources = {
{ name = 'nvim_lsp' },
},
mapping = cmp.mapping.preset.insert({
['<CR>'] = cmp.mapping.confirm({ select = true }),
['<C-Space>'] = cmp.mapping.complete(),
}),
})
LSP 직접 설정해 보기
- mason.nvim과 nvim-lspconfig를 설치하세요.
- 본인이 주로 쓰는 언어의 서버를
:Mason에서 설치하세요. - 아무 프로젝트를 열고 다음을 테스트하세요.
gd로 함수 정의 이동K로 함수 설명 확인<leader>rn으로 변수 이름 변경
- Telescope 키맵을 추가하고
<leader>ff로 파일을 검색해 보세요.
LSP의 가장 큰 장점은 무엇인가요?