이 글은 Neovim 시리즈의 세 번째 글이다.

  1. Neovim 입문: Vim을 넘어서는 첫걸음
  2. Neovim 중급: 생산성을 높이는 기능들
  3. Neovim 고급: 플러그인과 LSP로 IDE처럼 쓰기 ← 현재 글
  4. 나의 Neovim 설정 전체 공개

플러그인 매니저: lazy.nvim

Neovim 플러그인 매니저 중 가장 인기 있는 것이 lazy.nvim이다. 지연 로딩(lazy loading)을 기본으로 지원해서 시작 속도가 빠르다.

설치 (부트스트랩)

~/.config/nvim/init.lua에 아래를 추가하면 lazy.nvim이 없을 때 자동으로 설치된다:

local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git", "clone", "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable", lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

require("lazy").setup("plugins")

마지막 줄의 "plugins"~/.config/nvim/lua/plugins/ 디렉토리를 의미한다. 이 디렉토리에 파일을 추가하면 자동으로 플러그인이 로드된다.

플러그인 추가 방법

lua/plugins/ 안에 파일을 만들고 테이블을 반환하면 된다:

-- lua/plugins/example.lua
return {
  "작성자/플러그인이름",
  config = function()
    require("플러그인").setup({
      -- 옵션
    })
  end
}

플러그인 관리: :Lazy

LSP (Language Server Protocol)

LSP는 에디터와 언어 서버 사이의 표준 프로토콜이다. 코드 자동완성, 정의로 이동, 에러 표시, 리팩토링 등 IDE 기능의 핵심이다.

구조

Neovim ←→ nvim-lspconfig ←→ Language Server
                              (lua_ls, gopls, ts_ls, ...)

Mason으로 언어 서버 설치

Mason은 언어 서버, 포매터, 린터를 Neovim 안에서 설치/관리하는 도구다.

-- lua/plugins/lsp.lua
return {
  {
    "williamboman/mason.nvim",
    config = function()
      require("mason").setup()
    end
  },
  {
    "williamboman/mason-lspconfig.nvim",
    config = function()
      require("mason-lspconfig").setup({
        ensure_installed = { "lua_ls", "ts_ls", "gopls" }
      })
    end
  },
  {
    "neovim/nvim-lspconfig",
    config = function()
      vim.lsp.enable({ "lua_ls", "ts_ls", "gopls" })

      -- LSP 키매핑
      vim.keymap.set("n", "K", vim.lsp.buf.hover)
      vim.keymap.set("n", "gd", vim.lsp.buf.definition)
      vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action)
    end
  }
}
동작
K커서 위 심볼의 문서 표시
gd정의로 이동
<leader>ca코드 액션 (자동 수정 등)

Mason UI: :Mason (설치된 서버 확인/추가/삭제)

자동완성: nvim-cmp

nvim-cmp는 Neovim의 자동완성 엔진이다. 여러 소스(LSP, 버퍼, 파일 경로, 스니펫)에서 후보를 가져온다.

-- lua/plugins/nvim-cmp.lua
return {
  "hrsh7th/nvim-cmp",
  dependencies = {
    "hrsh7th/cmp-nvim-lsp",     -- LSP 소스
    "hrsh7th/cmp-buffer",       -- 버퍼 텍스트 소스
    "hrsh7th/cmp-path",         -- 파일 경로 소스
    "L3MON4D3/LuaSnip",        -- 스니펫 엔진
    "saadparwaiz1/cmp_luasnip", -- 스니펫 소스
    "rafamadriz/friendly-snippets", -- 스니펫 모음
  },
  config = function()
    local cmp = require("cmp")
    local luasnip = require("luasnip")

    require("luasnip.loaders.from_vscode").lazy_load()

    cmp.setup({
      snippet = {
        expand = function(args)
          luasnip.lsp_expand(args.body)
        end,
      },
      mapping = cmp.mapping.preset.insert({
        ["<C-Space>"] = cmp.mapping.complete(),
        ["<CR>"] = cmp.mapping.confirm({ select = true }),
        ["<Tab>"] = cmp.mapping.select_next_item(),
        ["<S-Tab>"] = cmp.mapping.select_prev_item(),
      }),
      sources = cmp.config.sources({
        { name = "nvim_lsp" },
        { name = "luasnip" },
        { name = "buffer" },
        { name = "path" },
      }),
    })
  end
}

자동완성 키:

동작
Ctrl-Space수동으로 완성 목록 열기
Tab다음 후보
Shift-Tab이전 후보
Enter선택 확정

Treesitter: 구문 하이라이팅

Treesitter는 코드를 파싱해서 정확한 구문 하이라이팅을 제공한다. 정규식 기반의 기존 하이라이팅보다 훨씬 정확하다.

-- lua/plugins/nvim-treesitter.lua
return {
  "nvim-treesitter/nvim-treesitter",
  build = ":TSUpdate",
  config = function()
    require("nvim-treesitter.configs").setup({
      ensure_installed = {
        "lua", "go", "javascript", "html",
        "markdown", "markdown_inline",
      },
      highlight = { enable = true },
      indent = { enable = true },
    })
  end
}

새 언어 추가: :TSInstall python

Telescope: 퍼지 파인더

Telescope는 파일, 텍스트, 버퍼, Git 등 모든 것을 검색할 수 있는 퍼지 파인더다.

-- lua/plugins/telescope.lua
return {
  "nvim-telescope/telescope.nvim",
  tag = "0.1.5",
  dependencies = { "nvim-lua/plenary.nvim" },
  config = function()
    local builtin = require("telescope.builtin")
    vim.keymap.set("n", "<leader>ff", builtin.find_files)
    vim.keymap.set("n", "<leader>fg", builtin.live_grep)
    vim.keymap.set("n", "<leader>fb", builtin.buffers)
    vim.keymap.set("n", "<leader>fh", builtin.help_tags)
  end
}
동작
<leader>ff파일 이름 검색
<leader>fg파일 내용 검색 (grep)
<leader>fb열린 버퍼 목록
<leader>fh도움말 검색

live_grep를 사용하려면 ripgrep이 설치되어 있어야 한다: brew install ripgrep

파일 탐색기: Neo-tree

-- lua/plugins/neo-tree.lua
return {
  "nvim-neo-tree/neo-tree.nvim",
  branch = "v3.x",
  dependencies = {
    "nvim-lua/plenary.nvim",
    "nvim-tree/nvim-web-devicons",
    "MunifTanjim/nui.nvim",
  },
}

<leader>e로 사이드바 파일 탐색기를 토글할 수 있다. VS Code의 Explorer와 비슷한 역할이다.

코드 포매팅: conform.nvim

-- lua/plugins/conform.lua
return {
  "stevearc/conform.nvim",
  config = function()
    require("conform").setup({
      formatters_by_ft = {
        lua = { "stylua" },
        javascript = { "prettierd", "prettier", stop_after_first = true },
        typescript = { "prettierd", "prettier", stop_after_first = true },
      },
      format_on_save = {
        timeout_ms = 500,
        lsp_format = "fallback",
      },
    })
  end
}

파일 저장 시 자동으로 포매팅된다. 포매터는 Mason으로 설치할 수 있다: :Masonstylua, prettierd 검색.

추천 플러그인 조합

최소한의 IDE 환경을 위한 추천 조합:

카테고리플러그인역할
플러그인 관리lazy.nvim플러그인 매니저
LSPmason + lspconfig언어 서버
자동완성nvim-cmp코드 완성
구문treesitter하이라이팅
검색telescope퍼지 파인더
파일 탐색neo-tree파일 트리
포매팅conform.nvim자동 포매팅
테마kanagawa / tokyonight / catppuccin컬러스킴

다음 글

이 플러그인들을 실제로 어떻게 조합하고 커스터마이징하는지, 나의 전체 Neovim 설정을 공개한다.

나의 Neovim 설정 전체 공개