DaleSchool

LSP로 IDE처럼 쓰기

입문20분

학습 목표

  • LSP가 무엇인지 설명할 수 있다
  • nvim-lspconfig로 언어 서버를 연결할 수 있다
  • 자동완성, 정의 이동, 에러 표시를 사용할 수 있다
  • Telescope로 파일과 심볼을 검색할 수 있다

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 직접 설정해 보기

  1. mason.nvim과 nvim-lspconfig를 설치하세요.
  2. 본인이 주로 쓰는 언어의 서버를 :Mason에서 설치하세요.
  3. 아무 프로젝트를 열고 다음을 테스트하세요.
    • gd로 함수 정의 이동
    • K로 함수 설명 확인
    • <leader>rn으로 변수 이름 변경
  4. Telescope 키맵을 추가하고 <leader>ff로 파일을 검색해 보세요.

LSP의 가장 큰 장점은 무엇인가요?