Docs of Jace-Lab

NeoVIM

https://neovim.io/

설치

appimage로 설치

https://github.com/neovim/neovim/releases/ 에서 appimage 다운로드

sudo mv nvim.appimage /usr/local/bin/nvim-0.12.1
~/.zshrc
alias vi='/usr/local/bin/nvim-0.12.1'

설정 ~/.config/nvim/init.lua

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


세션(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,winsize

4. 유용한 단축키 및 자동화 (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.vim

5. 세션 관리 플러그인 추천

기본 명령어보다 더 강력한 기능을 원하신다면 아래 플러그인을 사용하는 것이 세계적으로 일반적입니다.

  • 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에서는 파일을 열 때마다 탭을 만드는 것보다, 버퍼를 여러 개 띄워놓고 전환하며 작업하는 것이 훨씬 빠르고 정석적인 방법입니다.

On this page