NeoVIM
설치
appimage로 설치
https://github.com/neovim/neovim/releases/ 에서 appimage 다운로드
sudo mv nvim.appimage /usr/local/bin/nvim-0.12.1alias vi='/usr/local/bin/nvim-0.12.1'설정 ~/.config/nvim/init.lua
vim.pack.add {
'https://github.com/nvim-treesitter/nvim-treesitter',
'https://github.com/neovim/nvim-lspconfig',
'https://github.com/stevearc/oil.nvim', -- file manager
'https://github.com/y9san9/y9nika.nvim',
'https://github.com/brenoprata10/nvim-highlight-colors',
'https://www.github.com/nvim-tree/nvim-tree.lua', -- file explorer
'https://github.com/nvim-tree/nvim-web-devicons', -- icon for oil,lualine
'https://github.com/nvim-lualine/lualine.nvim', -- status bar
'https://github.com/romgrk/barbar.nvim', -- buffer by tab
'https://github.com/folke/which-key.nvim', -- show shortcut
'https://github.com/nvim-orgmode/orgmode', -- orgmode
}
vim.cmd.packadd('cfilter')
vim.cmd.packadd('nvim.undotree')
vim.cmd.packadd('nvim.difftool')
vim.o.updatetime = 300 -- 0.3s (basically 4s=4000)
vim.g.mapleader = " " -- space for leader
vim.g.maplocalleader = " " -- space for localleader
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.cursorline = true -- highlight current line
vim.opt.wrap = true -- wrap lines by default
vim.opt.tabstop = 2 -- tabwidth
vim.opt.shiftwidth = 2 -- indent width
vim.opt.softtabstop = 2 -- soft tab stop not tabs on tab/backspace
vim.opt.expandtab = true -- use spaces instead of tabs
vim.opt.smartindent = true -- smart auto-indent
vim.opt.autoindent = true -- copy indent from current line
vim.opt.autocomplete = true -- autocomplete ctrl+n/p
vim.opt.ignorecase = true -- case insensitive search
vim.opt.smartcase = true -- case sensitive if uppercase in string
vim.opt.hlsearch = true -- highlight search matches
vim.opt.incsearch = true -- show matches as you type
vim.opt.colorcolumn = '80'
vim.opt.textwidth = 80
vim.opt.completeopt = 'menu,menuone,fuzzy,noinsert'
vim.opt.swapfile = false
vim.opt.confirm = true
vim.opt.linebreak = true
vim.opt.termguicolors = true
vim.opt.wildoptions:append { 'fuzzy' }
vim.opt.path:append { '**' }
vim.opt.smoothscroll = true
vim.opt.grepprg = 'rg --vimgrep --no-messages --smart-case'
vim.opt.statusline = '[%n] %<%f %h%w%m%r%=%-14.(%l,%c%V%) %P'
vim.opt.laststatus = 3
vim.opt.clipboard = 'unnamedplus' -- copy,paste with clipboard
-- color scheme
-- vim.cmd.colorscheme('y9nika')
vim.pack.add { { src = "https://github.com/catppuccin/nvim", name = "catppuccin" } }
vim.cmd.colorscheme "catppuccin-nvim"
-- disable mouse popup yet keep mouse enabled
vim.cmd [[
aunmenu PopUp
autocmd! nvim.popupmenu
]]
--
-- Buffer
-- barbar
require'barbar'.setup {
-- Set the filetypes which barbar will offset itself for
sidebar_filetypes = {
-- Use the default values: {event = 'BufWinLeave', text = '', align = 'left'}
NvimTree = true,
-- Or, specify the text used for the offset:
undotree = {
text = 'undotree',
align = 'center', -- *optionally* specify an alignment (either 'left', 'center', or 'right')
},
-- Or, specify the event which the sidebar executes when leaving:
['neo-tree'] = {event = 'BufWipeout'},
-- Or, specify all three
Outline = {event = 'BufWinLeave', text = 'symbols-outline', align = 'right'},
},
-- Sets the name of unnamed buffers. By default format is "[Buffer X]"
-- where X is the buffer number. But only a static string is accepted here.
no_name_title = nil,
-- Enable/disable current/total tabpages indicator (top right corner)
tabpages = true,
-- Enables/disable clickable tabs
-- - left-click: go to buffer
-- - middle-click: delete buffer
clickable = true,
}
-- local opts = { noremap = true, silent = true }
-- 1. 이전/다음 버퍼로 이동 (Move to previous/next)
vim.keymap.set('n', '<A-,>', '<Cmd>BufferPrevious<CR>', opts)
vim.keymap.set('n', '<A-.>', '<Cmd>BufferNext<CR>', opts)
-- 2. 버퍼 순서 변경 (Re-order to previous/next)
vim.keymap.set('n', '<A-<>', '<Cmd>BufferMovePrevious<CR>', opts)
vim.keymap.set('n', '<A->>', '<Cmd>BufferMoveNext<CR>', opts)
-- 3. 특정 위치의 버퍼로 바로 이동 (Goto buffer in position)
vim.keymap.set('n', '<leader>1', '<Cmd>BufferGoto 1<CR>', opts)
vim.keymap.set('n', '<leader>2', '<Cmd>BufferGoto 2<CR>', opts)
vim.keymap.set('n', '<leader>3', '<Cmd>BufferGoto 3<CR>', opts)
vim.keymap.set('n', '<leader>4', '<Cmd>BufferGoto 4<CR>', opts)
vim.keymap.set('n', '<leader>5', '<Cmd>BufferGoto 5<CR>', opts)
vim.keymap.set('n', '<leader>6', '<Cmd>BufferGoto 6<CR>', opts)
vim.keymap.set('n', '<leader>7', '<Cmd>BufferGoto 7<CR>', opts)
vim.keymap.set('n', '<leader>8', '<Cmd>BufferGoto 8<CR>', opts)
vim.keymap.set('n', '<leader>9', '<Cmd>BufferGoto 9<CR>', opts)
vim.keymap.set('n', '<leader>0', '<Cmd>BufferLast<CR>', opts)
-- 4. 버퍼 고정/해제 (Pin/unpin buffer)
vim.keymap.set('n', '<A-p>', '<Cmd>BufferPin<CR>', opts)
-- 5. 버퍼 닫기 (Close buffer)
vim.keymap.set('n', '<leader>q', '<Cmd>BufferClose<CR>', opts)
vim.keymap.set('n', '<leader>qq', '<Cmd>quitall<CR>', opts)
-- 6. 매직 버퍼 픽킹 모드 (Magic buffer-picking mode)
-- 힌트 문자를 입력해 해당 버퍼로 즉시 이동/삭제
vim.keymap.set('n', '<C-p>', '<Cmd>BufferPick<CR>', opts)
vim.keymap.set('n', '<C-S-p>', '<Cmd>BufferPickDelete<CR>', opts)
-- 7. 자동 정렬 (Sort automatically by...)
vim.keymap.set('n', '<Space>bb', '<Cmd>BufferOrderByBufferNumber<CR>', opts)
vim.keymap.set('n', '<Space>bn', '<Cmd>BufferOrderByName<CR>', opts)
vim.keymap.set('n', '<Space>bd', '<Cmd>BufferOrderByDirectory<CR>', opts)
vim.keymap.set('n', '<Space>bl', '<Cmd>BufferOrderByLanguage<CR>', opts)
vim.keymap.set('n', '<Space>bw', '<Cmd>BufferOrderByWindowNumber<CR>', opts)
--
--
-- status bar: lualine
require('lualine').setup {
options = { theme = 'auto' },
}
-- ui2 (neovim 0.12.1)
-- require('vim._core.ui2').enable({
-- enable = true,
-- msg = {
-- target = "cmd", -- options: cmd(classic), msg(similar to noice)
-- pager = { height = 1 },
-- msg = { height = 0.5, timeout = 4500 },
-- dialog = { height = 0.5 },
-- cmd = { height = 0.5 },
-- },
-- })
-- Only highlight with treesitter
-- vim.cmd('syntax off')
require("nvim-highlight-colors").setup {
render = 'virtual',
virtual_symbol = '⚫︎',
virtual_symbol_suffix = '',
}
-- Oil
require('oil').setup {
keymaps = {
['<C-h>'] = false,
["g?"] = { "actions.show_help", mode = "n" },
["<CR>"] = "actions.select",
-- ["<C-s>"] = { "actions.select", opts = { vertical = true } },
-- ["<C-h>"] = { "actions.select", opts = { horizontal = true } },
-- ["<C-t>"] = { "actions.select", opts = { tab = true } },
["<C-p>"] = "actions.preview",
["<C-c>"] = { "actions.close", mode = "n" },
["<C-l>"] = "actions.refresh",
["-"] = { "actions.parent", mode = "n" },
["_"] = { "actions.open_cwd", mode = "n" },
["`"] = { "actions.cd", mode = "n" },
["g~"] = { "actions.cd", opts = { scope = "tab" }, mode = "n" },
["gs"] = { "actions.change_sort", mode = "n" },
["gx"] = "actions.open_external",
["g."] = { "actions.toggle_hidden", mode = "n" },
["g\\"] = { "actions.toggle_trash", mode = "n" },
},
-- use_default_keymaps = true,
columns = { 'icon', 'permissions', 'size', 'mtime' },
view_options = {
-- Show files and directories that start with "."
show_hidden = false,
-- This function defines what is considered a "hidden" file
is_hidden_file = function(name, bufnr)
local m = name:match("^%.")
return m ~= nil
end,
-- This function defines what will never be shown, even when `show_hidden` is set
is_always_hidden = function(name, bufnr)
return false
end,
-- Sort file names with numbers in a more intuitive order for humans.
-- Can be "fast", true, or false. "fast" will turn it off for large directories.
natural_order = "fast",
-- Sort file and directory names case insensitive
case_insensitive = false,
sort = {
-- sort order can be "asc" or "desc"
-- see :help oil-columns to see which columns are sortable
{ "type", "asc" },
{ "name", "asc" },
},
-- Customize the highlight group for the file name
highlight_filename = function(entry, is_hidden, is_link_target, is_link_orphan)
return nil
end,
},
delete_to_trash = true,
skip_confirm_for_simple_edits = true,
}
-- Keymaps
vim.keymap.set('n', '<leader><leader>', ':Oil<CR>', { silent = true })
vim.keymap.set('n', '<leader>a', function()
vim.cmd('$argadd %')
vim.cmd('argdedup')
end)
vim.keymap.set("n", "<C-h>", "<C-w>h", { desc = "Move to left window" })
vim.keymap.set("n", "<C-j>", "<C-w>j", { desc = "Move to bottom window" })
vim.keymap.set("n", "<C-k>", "<C-w>k", { desc = "Move to top window" })
vim.keymap.set("n", "<C-l>", "<C-w>l", { desc = "Move to right window" })
--vim.keymap.set('n', '<C-h>', function() vim.cmd('silent! 1argument') end)
--vim.keymap.set('n', '<C-j>', function() vim.cmd('silent! 2argument') end)
--vim.keymap.set('n', '<C-k>', function() vim.cmd('silent! 3argument') end)
vim.keymap.set('n', '<C-n>', function() vim.cmd('silent! 4argument') end)
vim.keymap.set('n', '<C-m>', function() vim.cmd('silent! 5argument') end)
-- Autocommands
vim.api.nvim_create_autocmd('FileType', {
callback = function() pcall(vim.treesitter.start) end,
})
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
vim.o.signcolumn = 'yes:1'
local client = assert(vim.lsp.get_client_by_id(args.data.client_id))
if client:supports_method('textDocument/completion') then
vim.o.complete = 'o,.,w,b,u'
vim.o.completeopt = 'menu,menuone,popup,noinsert'
vim.lsp.completion.enable(true, client.id, args.buf)
end
end
})
vim.api.nvim_create_autocmd('TextYankPost', {
callback = function() vim.highlight.on_yank() end,
})
-- 외부에서 파일 변경 시 자동 읽기 활성화
vim.o.autoread = true
vim.api.nvim_create_autocmd({ "FocusGained", "BufEnter", "CursorHold", "CursorHoldI" }, {
group = vim.api.nvim_create_augroup("CheckExternalChanges", { clear = true }),
pattern = "*",
callback = function()
if vim.fn.mode() ~= 'c' then
vim.cmd("checktime")
end
end,
})
-- Nvim-Tree
require("nvim-tree").setup({
view = {
width = 20,
},
filters = {
dotfiles = false,
},
renderer = {
group_empty = true,
},
})
vim.keymap.set("n", "<leader>e",
function()
require("nvim-tree.api").tree.toggle()
end,
{ desc = "Toggle NvimTree" }
)
-- Orgmode-Nvim
require('orgmode').setup({
org_agenda_files = '~/orgfiles/**/*',
org_default_notes_file = '~/orgfiles/refile.org',
})
-- experimental lsp support
vim.lsp.enable('org')Ref
- https://www.youtube.com/watch?v=lljs_7xB7Ps
- https://github.com/radleylewis/nvim-lite/blob/master/init.lua
- https://www.youtube.com/watch?v=v1c3VMF_bkw&t=1982s
- https://github.com/y9san9/y9san9.nvim
- https://github.com/catppuccin
세션(Session)
Vim(또는 Neovim)에서 **세션(Session)**은 현재 열려 있는 창 구조, 버퍼 목록, 작업 디렉토리 등을 그대로 저장하고 나중에 다시 불러올 수 있게 해주는 기능입니다.
주요 명령어와 단축키를 정리해 드립니다.
1. 세션 기본 명령어
Vim 내부에서 :를 눌러 명령행 모드에서 실행합니다.
| 기능 | 명령어 | 설명 |
|---|---|---|
| 세션 저장 | :mksession [파일명] | 현재 상태를 파일로 저장합니다. (기본값: Session.vim) |
| 세션 덮어쓰기 | :mksession! [파일명] | 기존 파일이 있다면 강제로 덮어씁니다. |
| 세션 불러오기 | :source [파일명] | 저장된 세션 파일을 읽어와 상태를 복구합니다. |
Tip: 파일명을 지정하지 않으면 현재 디렉토리에
Session.vim이라는 이름으로 생성됩니다.
2. 터미널에서 실행 시 세션 활용
Vim을 실행할 때 바로 세션을 불러올 수 있습니다.
- 저장된 세션으로 시작:
vi -S Session.vim - 기본 세션 파일(
Session.vim)이 있을 때:vi -S
3. 세션 저장 범위 설정 (sessionoptions)
세션에 어떤 정보까지 저장할지 결정할 수 있습니다. ~/.vimrc 또는 init.lua에 설정하거나 세션 저장 전에 입력합니다.
" 예시: 버퍼, 탭, 창 크기, 빈 창 등을 저장
:set sessionoptions=blank,buffers,curdir,folds,help,tabpages,winsize4. 유용한 단축키 및 자동화 (Tip)
Vim 자체에는 세션 전용 단축키가 기본 할당되어 있지 않지만, ~/.vimrc에 아래와 같이 등록하면 편리합니다.
추천 설정
" F2 키로 세션 즉시 저장
map <F2> :mksession! ~/.vim/sessions/last_session.vim<CR>
" F3 키로 세션 즉시 불러오기
map <F3> :source ~/.vim/sessions/last_session.vim<CR>종료 시 자동 저장 / 시작 시 자동 로드
매번 명령어를 치기 귀찮다면 autocmd를 활용해 보세요.
" Vim 종료 시 자동으로 세션 저장
autocmd VimLeave * mksession! ~/last_session.vim
" Vim 실행 시 세션 파일이 있으면 자동으로 로드 (선택 사항)
" autocmd VimEnter * source ~/last_session.vim5. 세션 관리 플러그인 추천
기본 명령어보다 더 강력한 기능을 원하신다면 아래 플러그인을 사용하는 것이 세계적으로 일반적입니다.
- vim-obsession: 세션 기록을 실시간으로 업데이트해 줍니다. (가장 가볍고 안정적)
- auto-session (Neovim 전용): 디렉토리별로 세션을 자동 관리해 줍니다.
- dashboard-nvim / alpha-nvim: 시작 화면에서 최근 세션 목록을 시각적으로 보여줍니다.
버퍼(Buffer)
Vim에서 **버퍼(Buffer)**는 파일의 내용을 메모리에 올려둔 상태를 의미합니다. 파일을 열면 버퍼가 생성되고, 저장(:w)을 해야 버퍼의 내용이 실제 파일에 기록됩니다.
버퍼를 효율적으로 관리하기 위한 주요 명령어와 단축키를 정리해 드립니다.
1. 버퍼 관리 기본 명령어
여러 파일을 동시에 다룰 때 필수적인 명령어들입니다.
| 기능 | 명령어 | 설명 |
|---|---|---|
| 목록 확인 | :ls 또는 :buffers | 현재 열려 있는 모든 버퍼 목록을 보여줍니다. |
| 다음 버퍼 | :bn (:bnext) | 다음 버퍼로 이동합니다. |
| 이전 버퍼 | :bp (:bprevious) | 이전 버퍼로 이동합니다. |
| 특정 버퍼 이동 | :b [번호 또는 이름] | 버퍼 번호나 파일 이름 일부를 입력해 이동합니다. |
| 버퍼 삭제 | :bd (:bdelete) | 현재 버퍼를 닫습니다. (수정 중이면 경고 발생) |
| 강제 삭제 | :bd! | 저장하지 않고 버퍼를 강제로 닫습니다. |
2. 버퍼 리스트의 기호 의미
:ls 명령어를 쳤을 때 파일명 옆에 붙는 기호들의 의미입니다.
%: 현재 창에 보이는 버퍼#: 바로 직전에 방문했던 버퍼 (Alt-tab 같은 느낌)a: 활성화된(active) 버퍼h: 숨겨진(hidden) 버퍼 (수정 중이지만 화면에는 안 보이는 상태)+: 변경 사항이 있지만 저장되지 않은 버퍼
3. 버퍼 전환 단축키 및 팁
Vim의 기본 키 중에서 버퍼 이동에 유용한 것들입니다.
Ctrl+^(또는6): 현재 버퍼와 직전 버퍼(#)를 빠르게 교차 전환합니다. (가장 많이 쓰임):b [탭 키]::b까지만 치고Tab을 누르면 열려 있는 버퍼 목록을 순차적으로 완성해 줍니다.
4. 추천 설정 (단축키 매핑)
버퍼 이동은 빈도가 매우 높기 때문에 ~/.vimrc에 단축키를 등록해 사용하는 것이 훨씬 편합니다.
" F5, F6로 이전/다음 버퍼 이동
map <F5> :bp<CR>
map <F6> :bn<CR>
" 리더 키(기본 \)를 활용한 빠른 이동
nnoremap <Leader>l :bn<CR>
nnoremap <Leader>h :bp<CR>
nnoremap <Leader>d :bd<CR>5. 버퍼 vs 탭(Tab) vs 창(Window)
입문자가 가장 헷갈려 하는 개념입니다. 이 관계를 이해하면 작업 효율이 올라갑니다.
- Buffer (버퍼): 메모리에 로드된 파일 그 자체. (항상 존재)
- Window (창): 버퍼를 보여주는 화면의 분할된 구역. (
:split,:vsplit) - Tab (탭): 여러 개의 창 배치를 모아놓은 하나의 화면 레이아웃. (
:tabnew)
핵심: Vim에서는 파일을 열 때마다 탭을 만드는 것보다, 버퍼를 여러 개 띄워놓고 전환하며 작업하는 것이 훨씬 빠르고 정석적인 방법입니다.