Language Server Protocol 이라고 이미 프로토콜 이름에 Server가 들어가 있어서 살짝 혼란스러울 수 있습니다. 헛갈리지 않게 줄여서 LSP라 부르겠습니다. 네오빔은 LSP 서버와 내장 LSP 클라이언트가 소통할 수도 있고, CoC 플러그인을 이용해 소통할 수도 있습니다. ※ 네오빔을 쓰시는 주변 분들을 보니, 이제(2024.11) CoC보다는 빌트인된 클라이언트를 많이 쓰시는 것 같긴 한데, CoC 플러그인 개발이 끊긴 건 아닙니다.
여기서는, 설치 방법이 아니라, 내장 클라이언트를 쓸 때 관련 플러그인들이 무슨 역할을 하는 지만 봅니다.
LSP 서버는 소스 코드의 의미semantics를 분석해서
등의 작업을 지원합니다.
네오빔은 LSP클라이언트를 내장하고 있고, 언어에 맞는 각 서버들은 써드 파티를 이용합니다.
(아래는 네오빔 도움말과, 각 플러그인들의 설명을 참고해서 정리했습니다.)
:lua vim.lsp.start({config}, {opts})
name
, root_dir
이 같은 클라이언트가 실행 중에 있으면 재사용합니다.-- 파일 타입에 따라 자동으로 실행될 이벤트 핸들러 FileType autocommand
vim.api.nvim_create_autocmd('FileType', {
pattern = 'python', -- 여기 예시는 파일 타입이 "python"일 때 실행한다는 뜻
callback = function(args)
vim.lsp.start({
name = 'my-server-name',
cmd = {'언어 서버 실행명', '--option', 'arg1', 'arg2'},
-- 전체 코드의 의미를 파싱해야 하니, 어디가 프로젝트 루트인가 알아야 합니다.
root_dir = vim.fs.root(args.buf, {'setup.py', 'pyproject.toml'}),
-- on_attach = ...
-- LSP 클라이언트가 현재 버퍼와 붙을 때 실행할 작업을, 이 핸들러에 지정합니다.
-- 키 바인딩을 한다거나 다른 플러그인들과 연동 작업 같은 것들 넣기에 적당합니다.
})
end,
})
vim.fs.root({source},{marker})
함수로 상대 경로를 따라 올라가며 루트 디렉토리를 찾습니다. 프로젝트의 루트임을 알 수있게 해주는 파일들을 지정합니다. 위에선 setup.py
파일이나 pyproject.toml
이 있는 폴더를 찾는다는 뜻입니다. 실행한 언어 서버와 소통을 담당할 클라이언트를 시작하고 현재 버퍼와 연결합니다.
버퍼에 클라이언트가 연결되면, 네오빔이 자동으로 다음 작업을 합니다.
tagfunc
: 정의로 점프 기능을 <C-]>
같은 tag command
로 할 수 있게 합니다.omnifunc
: 삽입 모드에서 옴니 모드 완성을 설정하고 활성화합니다. <C-x><C-o>
키로 부를 수 있습니다. 1formatexpr
: gq
로 LSP 포맷팅(들여쓰기, 줄바끔, 띄어쓰기…)을 활성화합니다. 디폴트로는 빈 값인데, 여기에 LSP 함수를 설정하면, gq
로 이 함수가 실행되어 텍스트를 포맷팅합니다.k
키를 vim.lsp.buf.hover()
동작과 바인딩합니다.[d
, ]d
키를 vim.diagnostic.goto_prev()
와 vim.diagnostic.goto_next()
에 바인딩합니다.<C-W>d
를 vim.diagnostic.opel_float()
에 바인딩합니다.위 설정들을 자동으로 하는데, 사용자화 하려면, LspAttach
, LspDetach
자동실행명령어autocommand를 이용할 수 있습니다.
위처럼 단지 vim.lsp.start(...)
해 주는 것만으로 단일 언어를 위한 LSP 설정을 마칠 수 있습니다만, 언어에 따라, 확장자 별로 위 작업을 모두 반복해서 하려면 꽤 성가신 반복 작업입니다. 보통 아래와 같이 플러그인들을 활용합니다.
mason.nvim:
LSP 서버, DAP서버, 린터, 포맷터를 설치, 관리합니다. 패키지들은 네오빔 데이터 디렉토리(:h standard-path
)에 설치됩니다. 실행 파일들은 bin/
한 곳에 심볼릭 링크를 만들어 두고, 이 경로를 네오빔의 PATH
에 추가합니다. LSP 클라이언트와 소통할 외부 서버들 관리를 위한 패키지 매니저라 볼 수 있습니다.
lspconfig:
다양한 LSP서버들의 기본적인 설정을 제공합니다.
예시) 하스켈의 LSP서버 hls를 위한 설정으로, 플러그인 설치 후 nvim-lspconfig/lua/lspconfig/configs/hls.lua를 보면, 다음과 같이 되어 있습니다. 위에서 본 vim.lsp.start
에 넣어 줄 옵션 값들입니다. 특별한 동작을 한다기보다 언어별 설정값을 저장해 둔 데이터 셋트입니다.
local util = require 'lspconfig.util'
return {
default_config = {
cmd = { 'haskell-language-server-wrapper', '--lsp' },
filetypes = { 'haskell', 'lhaskell' },
root_dir = util.root_pattern('hie.yaml', 'stack.yaml', 'cabal.project', '*.cabal', 'package.yaml'),
single_file_support = true,
settings = {
haskell = {
formattingProvider = 'ormolu',
cabalFormattingProvider = 'cabalfmt',
},
},
},
nvim-lspconfig/lua/lspconfig/manager.lua 에서
131 local client_id = lsp.start(new_config, {
...
LSP서버에 따라 적당한 옵션을 골라 lsp.start
(vim.lsp.start
)를 실행합니다.
반드시 mason과 짝지어 돌리지 않아도 됩니다. 직접 외부 LSP서버를 설치하고, require('lspconfig').pyright.setup({})
와 비슷한 코드로 개별 설정을 할 수도 있습니다.
mason-lspconfig:
mason.nvim
과 lspconfig
, 이 둘을 연결해 줄 브릿지입니다. mason.nvim
으로 원하는 외부 서버를 설치하면, 해당 서버에 맞는 설정을 lspconfig
가 넣어줘야 자동 LSP 환경 설정이 마무리 됩니다. mason.nvim
이 설치한 서버를 보고, lspconfig
의 언어별 setup {}
을 부르는 역할을 합니다.
※ fidget.nvim: 가끔 LSP 동작이 잘되는 것인가 의심스러울 때가 있습니다. 필수는 아니지만 이 플러그인을 설치하면 LSP 동작 상태를 실시간으로 볼 수 있습니다.
※ lspsaga.nvim: - 지금 어느 파일의 어느 함수에 있나 보여주는 Breadcrumbs가 생기고, - 함수 호출 계보를 보여주고, - 빌트인 코드 액션은 줄 단위 진단diagnostic을 하고, Lspsaga는 커서 단위 진단을 합니다.
빌트인 클라이언트와 일부 기능이 겹치지만, 쓸만합니다.
※ 얼마 전(2024.10) lua
LSP 서버의 이름이 바뀌면서 lua_ls
란 이름과 lua-language-server
이름을 매핑해주는 작업을 여기서 해줬었습니다.
보통, 위 플러그인들 중 하나를 쓰는 게 아니라, mason.nvim
, lspconfig
, mason-lspconfig
를 같이 설치해서 연동해서 씁니다. 한 두 개의 언어만 고정해서 쓴다면, 수작업으로 설졍해도 되지만, 여러 언어들 관련 설정을 하기에는 수작업은 많이 성가십니다. 위 플러그인들을 이용해서 설정하다가 문제가 생기면, Vim.kr(한국 빔 사용자 모임) 디스코드 로 오셔서 도움을 받으실 수 있습니다.
:set omnifunc?
로 설정값을 확인 할 수 있습니다. v:lua.vim.lsp.omnifunc
값이 나오면 LSP 옴니 모드 완성Omni mode completion이 활성화된 상태입니다.
단순한 텍스트 매칭으로 완성될 단어를 제안하는 일반 텍스트 완성과 다르게, 컨텍스트(어떤 형식의 파일인지, 현재 코드의 상태는 어떤지, 함수 호출 위치가 어디인지…)에 따라서 완성될 단어를 제안합니다.
(다양한 언어, 문맥을 지원한다고 해서 Omni
가 붙었다고 하는데, 모두
를 뜻하는 Omni
가 맞나 싶습니다.)
nvim-cmp 플러그인을 이용해서 여러 소스를 참고해서 제안하도록 할 수 있습니다.↩︎