이 글은 Neovim 시리즈의 마지막 글이다.
- Neovim 입문: Vim을 넘어서는 첫걸음
- Neovim 중급: 생산성을 높이는 기능들
- Neovim 고급: 플러그인과 LSP로 IDE처럼 쓰기
- 나의 Neovim 설정 전체 공개 ← 현재 글
설정 철학
- Lua 기반: VimScript 대신 Lua로 모든 설정을 작성
- 모듈화: 기능별로 파일을 분리해서 관리
- 최소주의: 꼭 필요한 플러그인만, 23개로 유지
- 일관된 키매핑: 커스텀
keyMapper유틸리티로 통일
디렉토리 구조
~/.config/nvim/
├── init.lua # 진입점 (1줄)
├── lazy-lock.json # 플러그인 버전 고정
└── lua/
├── config/
│ ├── init.lua # config 모듈 진입점
│ ├── globals.lua # 전역 변수 (leader 키 등)
│ ├── options.lua # Neovim 옵션
│ └── keymaps.lua # 글로벌 키매핑
├── plugins/
│ ├── alpha.lua # 시작 화면
│ ├── comment.lua # 주석 토글
│ ├── conform.lua # 코드 포매팅
│ ├── indent-blankline.lua # 들여쓰기 가이드
│ ├── kanagawa.lua # 컬러스킴
│ ├── lsp.lua # LSP 설정
│ ├── lualine.lua # 상태줄
│ ├── neo-tree.lua # 파일 탐색기
│ ├── nvim-autopairs.lua # 자동 괄호
│ ├── nvim-cmp.lua # 자동완성
│ ├── nvim-treesitter.lua # 구문 하이라이팅
│ ├── nvim-ufo.lua # 코드 폴딩
│ ├── render-markdown.lua # 마크다운 렌더링
│ ├── telescope.lua # 퍼지 파인더
│ └── vim-floaterm.lua # 플로팅 터미널
└── utils/
└── keyMapper.lua # 키매핑 헬퍼
핵심은 init.lua가 단 1줄이라는 것이다:
require("config")
config/init.lua에서 globals, options, keymaps, lazy.nvim 순서로 로드한다.
핵심 옵션
-- lua/config/options.lua
opt = vim.opt
-- 2칸 탭
opt.tabstop = 2
opt.shiftwidth = 2
opt.softtabstop = 2
opt.expandtab = true
opt.smartindent = true
opt.wrap = false
-- 검색
opt.incsearch = true
opt.ignorecase = true
opt.smartcase = true -- 대문자가 포함되면 대소문자 구분
-- 줄 번호
opt.number = true
opt.relativenumber = true -- 상대 줄 번호 (이동에 유용)
-- 기타
opt.termguicolors = true
opt.signcolumn = "yes"
opt.scrolloff = 10 -- 커서 위아래 10줄 여유
opt.mouse:append("a")
-- 마크다운 전용 설정
vim.api.nvim_create_autocmd("FileType", {
pattern = "markdown",
callback = function()
vim.opt_local.wrap = true -- 줄 바꿈 활성화
vim.opt_local.linebreak = true -- 단어 단위로 줄 바꿈
vim.opt_local.conceallevel = 2 -- 문법 마커 숨기기
end,
})
relativenumber는 처음에는 어색하지만, 5j, 12k 같은 상대 이동을 할 때 줄 수를 바로 알 수 있어서 매우 편하다.
keyMapper 유틸리티
모든 키매핑에 일관되게 noremap과 silent를 적용하기 위해 만든 헬퍼다:
-- lua/utils/keyMapper.lua
local keyMapper = function(from, to, mode, opts)
local options = { noremap = true, silent = true }
mode = mode or "n"
if opts then
options = vim.tbl_extend("force", options, opts)
end
vim.keymap.set(mode, from, to, options)
end
return { mapKey = keyMapper }
사용법:
local mapKey = require("utils.keyMapper").mapKey
mapKey("<leader>e", ":Neotree toggle<cr>") -- Normal 모드 (기본)
mapKey("<", "<gv", "v") -- Visual 모드 지정
전체 키매핑
글로벌 키매핑
| 키 | 동작 | 모드 |
|---|---|---|
Space | Leader 키 | - |
<leader>e | Neo-tree 파일 탐색기 토글 | N |
<leader>h | 검색 하이라이트 제거 | N |
Ctrl-h/j/k/l | 분할 창 이동 | N |
< / > | 들여쓰기 유지하며 인덴트 | V |
Ctrl-; | 플로팅 터미널 토글 | N |
Telescope 키매핑
| 키 | 동작 |
|---|---|
<leader>ff | 파일 이름 검색 |
<leader>fg | 파일 내용 검색 (grep) |
<leader>fb | 버퍼 목록 |
<leader>fh | 도움말 검색 |
LSP 키매핑
| 키 | 동작 |
|---|---|
K | 호버 문서 |
gd | 정의로 이동 |
<leader>ca | 코드 액션 |
플러그인 전체 목록 (23개)
핵심
| 플러그인 | 역할 |
|---|---|
| lazy.nvim | 플러그인 매니저 |
| telescope.nvim | 퍼지 파인더 (파일/텍스트/버퍼 검색) |
| neo-tree.nvim | 사이드바 파일 탐색기 |
| nvim-cmp | 자동완성 엔진 |
| nvim-lspconfig | LSP 클라이언트 설정 |
| mason.nvim | 언어 서버/포매터 설치 관리 |
| nvim-treesitter | 구문 파싱 & 하이라이팅 |
| conform.nvim | 저장 시 자동 포매팅 |
자동완성 소스
| 플러그인 | 소스 |
|---|---|
| cmp-nvim-lsp | LSP 자동완성 |
| cmp-buffer | 버퍼 텍스트 |
| cmp-path | 파일 경로 |
| cmp_luasnip | 스니펫 |
| LuaSnip | 스니펫 엔진 |
| friendly-snippets | VS Code 스니펫 모음 |
UI & 외관
| 플러그인 | 역할 |
|---|---|
| kanagawa.nvim | 컬러스킴 (dragon 테마) |
| lualine.nvim | 하단 상태줄 |
| alpha-nvim | 시작 화면 대시보드 |
| nvim-web-devicons | 파일 아이콘 |
| indent-blankline.nvim | 들여쓰기 시각 가이드 |
편집 보조
| 플러그인 | 역할 |
|---|---|
| Comment.nvim | gcc로 주석 토글 |
| nvim-autopairs | 괄호/따옴표 자동 닫기 |
| nvim-ufo | LSP 기반 코드 폴딩 |
| vim-floaterm | 플로팅 터미널 |
| render-markdown.nvim | 마크다운 실시간 렌더링 |
테마: Kanagawa Dragon
Kanagawa의 Dragon 변형을 사용한다. 일본 전통 색상에서 영감을 받은 다크 테마로, 눈의 피로가 적다.
커스터마이징 포인트:
overrides = function(colors)
local theme = colors.theme
return {
-- 플로팅 윈도우 배경 투명화
NormalFloat = { bg = "none" },
FloatBorder = { bg = "none" },
FloatTitle = { bg = "none" },
-- Telescope UI 커스터마이징
TelescopePromptNormal = { bg = theme.ui.bg_p1 },
TelescopeResultsNormal = { fg = theme.ui.fg_dim, bg = theme.ui.bg_m1 },
TelescopePreviewNormal = { bg = theme.ui.bg_dim },
-- 자동완성 팝업
Pmenu = { fg = theme.ui.shade0, bg = theme.ui.bg_p1 },
PmenuSel = { fg = "NONE", bg = theme.ui.bg_p2 },
}
end,
theme = "dragon",
상태줄(lualine)은 Gruvbox 테마를 사용해서 본문과 미묘하게 다른 톤을 준다.
마크다운 작성 환경
블로그를 Neovim으로 작성하기 때문에 마크다운 환경을 신경 썼다:
- render-markdown.nvim: 헤딩, 코드 블록, 테이블, 체크박스를 시각적으로 렌더링
- 줄 바꿈 활성화: 마크다운 파일에서만
wrap = true - conceallevel 2:
**bold**같은 마커를 숨기고 bold 형태로 표시
LSP 구성
Mason으로 3개 언어 서버를 관리한다:
| 서버 | 언어 | 포매터 |
|---|---|---|
| lua_ls | Lua | stylua |
| ts_ls | TypeScript/JavaScript | prettierd |
| gopls | Go | gofmt (내장) |
새 언어를 추가하려면:
:Mason에서 언어 서버 설치lsp.lua의ensure_installed에 추가conform.lua에 포매터 추가 (필요 시)
정리
이 설정은 계속 발전 중이다. Neovim의 장점은 내 워크플로우에 맞게 모든 것을 조정할 수 있다는 점이다. 처음에는 남의 설정을 복사하더라도, 하나씩 이해하면서 자기 것으로 만들어가는 과정이 중요하다.
가장 좋은 Neovim 설정은 내가 이해하고 있는 설정이다.