
vim 명령어를 어느 정도 익히고 나면 자연스럽게 설정 파일에 손이 가게 됩니다. 예전에 일반 vim을 쓸 때는 ~/.vimrc 하나에 set number 같은 걸 몇 줄 넣는 게 전부였는데, Neovim으로 넘어오면 init.lua라는 게 등장하고, Lua 스크립트로 설정을 한다는 얘기가 나옵니다.
처음엔 "vim 쓰려고 언어를 또 배워야 해?" 싶었는데, 막상 보면 설정 파일 맥락에서 쓰는 Lua는 그렇게 방대하지 않습니다. 그리고 Vimscript로 비슷한 걸 짜는 것보다 확실히 읽기 편합니다.
1편에서는 init.lua가 어디에 있고 어떻게 구성되는지, Lua 문법 중 설정 파일에서 실제로 쓰이는 것들, 키매핑, autocmd를 정리합니다.
init.lua는 어디에 있나
Neovim의 설정 파일 위치는 운영체제마다 다릅니다.
Linux / macOS ~/.config/nvim/init.lua
Windows ~\AppData\Local\nvim\init.lua
nvim 디렉토리가 없으면 만들면 됩니다. 기존에 init.vim을 쓰고 있었다면 같은 위치에 init.lua로 대체하면 됩니다. 둘을 같이 두면 충돌이 생기니 하나만 씁니다.
파일 하나에 전부 써도 되고, 여러 파일로 나눠서 require()로 불러오는 구조로 가도 됩니다. 처음엔 init.lua 하나에 다 쓰다가 길어지면 나누는 게 자연스러운 흐름입니다.
Vimscript와 Lua, 뭐가 다른가
Neovim은 Lua를 1급 스크립트 언어로 내장하고 있습니다. Vimscript로 쓰던 설정을 Lua로 쓸 수 있고, 두 가지를 섞어 써도 됩니다. 같은 설정을 두 가지 방식으로 쓰면 이렇게 됩니다.
" Vimscript (.vimrc 또는 init.vim)
set number
set tabstop=4
nnoremap <leader>w :w<CR>
-- Lua (init.lua)
vim.opt.number = true
vim.opt.tabstop = 4
vim.keymap.set('n', '<leader>w', ':w<CR>')
Vimscript가 짧아 보이지만, 설정이 복잡해질수록 Lua가 훨씬 읽기 편합니다. 조건문, 함수, 모듈화 같은 걸 쓸 때 차이가 큽니다.
init.lua 안에서 Vimscript 명령어를 그대로 실행하고 싶으면 vim.cmd()를 씁니다.
vim.cmd('colorscheme habamax')
vim.cmd([[
augroup MyGroup
autocmd!
augroup END
]])
설정값 쓰기 (vim.opt)
set에 해당하는 게 vim.opt입니다.
vim.opt.number = true -- set number
vim.opt.relativenumber = true -- set relativenumber
vim.opt.tabstop = 4 -- set tabstop=4
vim.opt.shiftwidth = 4 -- set shiftwidth=4
vim.opt.expandtab = true -- set expandtab
vim.opt.hlsearch = true -- set hlsearch
vim.opt.incsearch = true -- set incsearch
vim.opt.ignorecase = true -- set ignorecase
vim.opt.smartcase = true -- set smartcase
vim.opt.wrap = false -- set nowrap
vim.opt.termguicolors = true -- set termguicolors
vim.opt.signcolumn = 'yes' -- 좌측 기호 열 항상 표시 (LSP 진단 표시용)
vim.opt.updatetime = 250 -- 자동저장, CursorHold 반응 속도 (ms)
vim.opt.clipboard = 'unnamedplus' -- 시스템 클립보드 연동
vim.opt 외에 vim.o(전역), vim.wo(창 단위), vim.bo(버퍼 단위)도 있습니다. 대부분의 경우 vim.opt를 쓰면 Neovim이 알아서 적절한 범위에 적용합니다.
리더 키 설정
플러그인 키맵에서 <leader>를 많이 씁니다. 기본값은 \인데 보통 스페이스로 바꿔 씁니다. vim.opt보다 먼저 선언해야 플러그인 설정에 반영됩니다.
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
Lua 문법 — 설정 파일에서 쓰는 것들
Lua 언어 전체를 배울 필요는 없고, init.lua에서 실제로 나오는 패턴들만 알면 됩니다.
주석
-- 한 줄 주석
--[[
여러 줄 주석
]]
변수
local x = 10 -- 지역 변수 (local 권장)
y = 20 -- 전역 변수 (가능하면 안 씀)
local s = "hello"
local flag = true
local nothing = nil -- 값 없음
local을 붙이는 게 기본입니다. 안 붙이면 전역 변수가 되어서 다른 파일 설정과 충돌할 수 있습니다.
테이블
Lua에서 테이블은 배열이자 딕셔너리입니다. 플러그인 설정에서 가장 자주 보이는 자료구조입니다.
-- 배열처럼
local colors = { 'red', 'green', 'blue' }
print(colors[1]) -- Lua 인덱스는 1부터 시작
-- 딕셔너리처럼
local opts = {
noremap = true,
silent = true,
}
print(opts.noremap) -- true
조건문
if vim.fn.has('mac') == 1 then
vim.opt.shell = 'zsh'
elseif vim.fn.has('win32') == 1 then
vim.opt.shell = 'pwsh'
else
vim.opt.shell = 'bash'
end
함수
local function my_func(a, b)
return a + b
end
-- 익명 함수를 변수에 담는 방식도 자주 씁니다
local greet = function(name)
print('Hello, ' .. name)
end
require로 모듈 불러오기
init.lua가 길어지면 파일을 나눠서 require로 불러옵니다.
-- init.lua
require('config.options') -- ~/.config/nvim/lua/config/options.lua
require('config.keymaps') -- ~/.config/nvim/lua/config/keymaps.lua
require('config.plugins') -- ~/.config/nvim/lua/config/plugins.lua
lua/ 디렉토리 아래에 파일을 만들면 require()로 불러올 수 있습니다. .은 디렉토리 구분자로 씁니다.
~/.config/nvim/
├── init.lua
└── lua/
└── config/
├── options.lua
├── keymaps.lua
└── plugins.lua
키매핑 (vim.keymap.set)
Vimscript의 nnoremap, inoremap 등을 대체합니다.
vim.keymap.set(모드, 키, 동작, 옵션)
모드는 문자열로 씁니다: 'n'(Normal), 'i'(Insert), 'v'(Visual), 'x'(Visual+Select), 't'(Terminal), 'c'(Command), ''(전체).
local map = vim.keymap.set
-- 기본 예시
map('n', '<leader>w', ':w<CR>', { desc = '저장' })
map('n', '<leader>q', ':q<CR>', { desc = '종료' })
-- noremap + silent 기본으로 붙이는 패턴
local opts = { noremap = true, silent = true }
map('n', '<C-h>', '<C-w>h', opts) -- 왼쪽 창으로
map('n', '<C-j>', '<C-w>j', opts) -- 아래 창으로
map('n', '<C-k>', '<C-w>k', opts) -- 위 창으로
map('n', '<C-l>', '<C-w>l', opts) -- 오른쪽 창으로
-- 검색 하이라이트 끄기
map('n', '<Esc>', ':nohlsearch<CR>', opts)
-- 줄 이동 (선택 후 J/K로 이동)
map('v', 'J', ":m '>+1<CR>gv=gv", opts)
map('v', 'K', ":m '<-2<CR>gv=gv", opts)
-- Lua 함수를 직접 연결할 수도 있습니다
map('n', '<leader>e', function()
vim.diagnostic.open_float()
end, { desc = '진단 메시지 열기' })
noremap = true는 키맵 재귀 방지, silent = true는 명령어를 하단 커맨드라인에 출력하지 않는 옵션입니다. desc는 which-key 같은 플러그인이 설명을 보여줄 때 쓰입니다.
autocmd
특정 이벤트가 발생할 때 자동으로 실행할 동작을 등록합니다.
vim.api.nvim_create_autocmd(이벤트, 옵션)
자주 쓰는 패턴
-- 파일 저장 시 trailing whitespace 제거
vim.api.nvim_create_autocmd('BufWritePre', {
pattern = '*',
callback = function()
vim.cmd('%s/\\s\\+$//e')
end,
})
-- 파일 타입별 들여쓰기 설정
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'lua', 'javascript', 'typescript' },
callback = function()
vim.opt_local.tabstop = 2
vim.opt_local.shiftwidth = 2
end,
})
-- 터미널 열면 Insert 모드로 진입
vim.api.nvim_create_autocmd('TermOpen', {
pattern = '*',
callback = function()
vim.cmd('startinsert')
end,
})
-- yank 시 잠깐 하이라이트 (복사된 영역 시각적 피드백)
vim.api.nvim_create_autocmd('TextYankPost', {
callback = function()
vim.highlight.on_yank()
end,
})
여러 autocmd를 하나의 그룹으로 묶으면 관리가 편합니다. reload 시 중복 등록도 막을 수 있습니다.
local group = vim.api.nvim_create_augroup('MyConfig', { clear = true })
vim.api.nvim_create_autocmd('BufWritePre', {
group = group,
pattern = '*',
callback = function()
vim.cmd('%s/\\s\\+$//e')
end,
})
vim.fn — Vimscript 함수 호출
Lua에서 Vimscript 내장 함수를 그대로 쓸 수 있습니다.
vim.fn.has('nvim-0.9') -- 버전 확인
vim.fn.expand('%:p') -- 현재 파일 전체 경로
vim.fn.expand('~') -- 홈 디렉토리 경로
vim.fn.executable('rg') -- 실행 파일 존재 여부 (1 or 0)
vim.fn.stdpath('config') -- Neovim 설정 경로
vim.fn.stdpath('data') -- 데이터 경로 (플러그인 저장 위치)
정리 표
| 분류 | Vimscript | Lua |
|---|---|---|
| 옵션 설정 | set number |
vim.opt.number = true |
| 전역 변수 | let g:foo = 1 |
vim.g.foo = 1 |
| 키매핑 | nnoremap <key> <cmd> |
vim.keymap.set('n', ...) |
| autocmd | autocmd Event * cmd |
vim.api.nvim_create_autocmd(...) |
| 함수 실행 | call Func() |
vim.fn.Func() |
| 명령어 실행 | 직접 | vim.cmd('...') |
| 모듈화 | source file.vim |
require('module') |
| 주석 | " |
-- |
2편에서는 lazy.nvim으로 플러그인을 관리하는 방법과, LSP(mason + nvim-lspconfig)를 실제로 세팅하는 방법을 다룹니다.
'블로그, 컴퓨터 > Cheatsheets' 카테고리의 다른 글
| Git 명령어 정리 (1편) — 기본 개념, 설정, 커밋, 로그 (0) | 2026.05.26 |
|---|---|
| Neovim 설정 정리 (2편) — lazy.nvim, LSP, 주요 플러그인 (0) | 2026.05.25 |
| Vim 명령어 정리 (2편) — 검색/치환, Visual 모드, 분할 화면, 설정 (0) | 2026.05.24 |
| Vim 명령어 정리 (1편) — 모드, 이동, 편집, 저장 (0) | 2026.05.24 |
| 리눅스 터미널 명령어 정리 (2편) — 권한, 프로세스, 네트워크, 검색 & 파이프 (0) | 2026.05.23 |