chore: base

This commit is contained in:
Paul B. Kim 2026-02-08 19:57:17 +09:00
parent 82949b8a26
commit 0ecd67991d
17 changed files with 496 additions and 45 deletions

12
.nvimlog Normal file
View File

@ -0,0 +1,12 @@
WRN 2026-02-08T10:26:22.500 ?.251198 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.251198.0
WRN 2026-02-08T10:27:17.510 ?.252159 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.252159.0
WRN 2026-02-08T10:27:27.437 ?.252367 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.252367.0
WRN 2026-02-08T12:08:26.579 ?.359867 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.359867.0
WRN 2026-02-08T12:10:44.180 ?.364737 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.364737.0
ERR 2026-02-08T12:10:44.218 ?.364737 pty_proc_spawn:186: forkpty failed: Permission denied
WRN 2026-02-08T12:18:41.628 ?.381522 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.381522.0
WRN 2026-02-08T16:12:49.348 ?.515879 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.515879.0
WRN 2026-02-08T16:33:59.951 ?.543624 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.543624.0
WRN 2026-02-08T16:57:38.954 ?.571806 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.571806.0
WRN 2026-02-08T19:51:48.962 ?.702813 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.702813.0
WRN 2026-02-08T19:51:48.968 ?.702844 server_start:199: Failed to start server: operation not permitted: /run/user/1000/nvim.702844.0

195
init.lua
View File

@ -101,8 +101,7 @@ vim.g.have_nerd_font = false
-- Make line numbers default
vim.o.number = true
-- You can also add relative line numbers, to help with jumping.
-- Experiment for yourself to see if you like it!
-- vim.o.relativenumber = true
vim.o.relativenumber = true
-- Enable mouse mode, can be useful for resizing splits for example!
vim.o.mouse = 'a'
@ -118,8 +117,13 @@ vim.schedule(function()
vim.o.clipboard = 'unnamedplus'
end)
-- Enable break indent
vim.o.breakindent = true
require('custom.wrapping').setup()
-- Default to 4-space indentation unless overridden by filetype/plugins
vim.o.tabstop = 4
vim.o.shiftwidth = 4
vim.o.softtabstop = 4
vim.o.expandtab = true
-- Save undo history
vim.o.undofile = true
@ -191,13 +195,13 @@ vim.keymap.set('t', '<Esc><Esc>', '<C-\\><C-n>', { desc = 'Exit terminal mode' }
-- vim.keymap.set('n', '<down>', '<cmd>echo "Use j to move!!"<CR>')
-- Keybinds to make split navigation easier.
-- Use CTRL+<hjkl> to switch between windows
-- NOTE: <C-h/j/k/l> are managed by vim-tmux-navigator in this config.
--
-- See `:help wincmd` for a list of all window commands
vim.keymap.set('n', '<C-h>', '<C-w><C-h>', { desc = 'Move focus to the left window' })
vim.keymap.set('n', '<C-l>', '<C-w><C-l>', { desc = 'Move focus to the right window' })
vim.keymap.set('n', '<C-j>', '<C-w><C-j>', { desc = 'Move focus to the lower window' })
vim.keymap.set('n', '<C-k>', '<C-w><C-k>', { desc = 'Move focus to the upper window' })
vim.keymap.set('n', '<leader>wh', '<C-w><C-h>', { desc = 'Move focus to the left window' })
vim.keymap.set('n', '<leader>wl', '<C-w><C-l>', { desc = 'Move focus to the right window' })
vim.keymap.set('n', '<leader>wj', '<C-w><C-j>', { desc = 'Move focus to the lower window' })
vim.keymap.set('n', '<leader>wk', '<C-w><C-k>', { desc = 'Move focus to the upper window' })
-- NOTE: Some terminals have colliding keymaps or are not able to send distinct keycodes
-- vim.keymap.set("n", "<C-S-h>", "<C-w>H", { desc = "Move window to the left" })
@ -219,6 +223,60 @@ vim.api.nvim_create_autocmd('TextYankPost', {
end,
})
local path_on_save_group = vim.api.nvim_create_augroup('kickstart-create-path-on-save', { clear = true })
-- Only create paths inside these roots (defaults to current working directory).
-- Add more roots as needed, e.g. vim.fn.expand '~/notes'
local path_create_roots = {
vim.fn.getcwd(),
}
local is_in_allowed_root = function(path)
local abs_path = vim.fn.fnamemodify(path, ':p')
for _, root in ipairs(path_create_roots) do
local abs_root = vim.fn.fnamemodify(root, ':p')
if abs_path:sub(1, #abs_root) == abs_root then
return true
end
end
return false
end
local ensure_owner_rwx = function(path)
local perms = vim.fn.getfperm(path)
if perms ~= '' and perms:sub(1, 3) ~= 'rwx' then
vim.fn.setfperm(path, 'rwx' .. perms:sub(4))
end
end
vim.api.nvim_create_autocmd('BufWritePre', {
desc = 'Create missing parent directories on save',
group = path_on_save_group,
callback = function(args)
if vim.bo[args.buf].buftype ~= '' then
return
end
local file_path = vim.api.nvim_buf_get_name(args.buf)
if file_path == '' or file_path:match '^%w+://' then
return
end
local uv = vim.uv or vim.loop
local abs_path = vim.fn.fnamemodify(file_path, ':p')
if not is_in_allowed_root(abs_path) then
return
end
local parent = vim.fn.fnamemodify(abs_path, ':h')
if uv.fs_stat(parent) == nil then
vim.fn.mkdir(parent, 'p', '0700')
end
ensure_owner_rwx(parent)
end,
})
-- [[ Install `lazy.nvim` plugin manager ]]
-- See `:help lazy.nvim.txt` or https://github.com/folke/lazy.nvim for more info
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim'
@ -665,19 +723,44 @@ require('lazy').setup({
-- - settings (table): Override the default settings passed when initializing the server.
-- For example, to see the options for `lua_ls`, you could go to: https://luals.github.io/wiki/settings/
local servers = {
-- clangd = {},
-- gopls = {},
-- pyright = {},
-- rust_analyzer = {},
-- ... etc. See `:help lspconfig-all` for a list of all the pre-configured LSPs
--
-- Some languages (like typescript) have entire language plugins that can be useful:
-- https://github.com/pmizio/typescript-tools.nvim
--
-- But for many setups, the LSP (`ts_ls`) will work just fine
-- ts_ls = {},
--
-- Languages
clangd = {},
gopls = {
settings = {
gopls = {
analyses = {
unusedparams = true,
shadow = true,
},
staticcheck = true,
gofumpt = true,
},
},
},
pyright = {
settings = {
python = {
analysis = {
typeCheckingMode = 'basic',
autoSearchPaths = true,
useLibraryCodeForTypes = true,
},
},
},
},
ruff = {},
rust_analyzer = {},
bashls = {},
awk_ls = {},
cssls = {},
htmx = {},
html = {},
jsonls = {},
yamlls = {},
taplo = {},
elixirls = {},
gh_actions_ls = {},
jqls = {},
lua_ls = {
-- cmd = { ... },
-- filetypes = { ... },
@ -692,6 +775,25 @@ require('lazy').setup({
},
},
},
-- Tools
eslint = {},
astro = {},
tailwindcss = {},
docker_language_server = {},
docker_compose_language_service = {},
marksman = {},
postgres_lsp = {},
neocmake = {},
buf_ls = {},
-- ... etc. See `:help lspconfig-all` for a list of all the pre-configured LSPs
--
-- Some languages (like typescript) have entire language plugins that can be useful:
-- https://github.com/pmizio/typescript-tools.nvim
--
-- But for many setups, the LSP (`ts_ls`) will work just fine
-- ts_ls = {},
--
}
---@type MasonLspconfigSettings
---@diagnostic disable-next-line: missing-fields
@ -715,6 +817,7 @@ require('lazy').setup({
local ensure_installed = vim.tbl_keys(servers or {})
vim.list_extend(ensure_installed, {
'stylua', -- Used to format Lua code
'markdownlint', -- Used by nvim-lint for Markdown buffers
})
require('mason-tool-installer').setup { ensure_installed = ensure_installed }
@ -933,22 +1036,36 @@ require('lazy').setup({
},
{ -- Highlight, edit, and navigate code
'nvim-treesitter/nvim-treesitter',
lazy = false,
build = ':TSUpdate',
main = 'nvim-treesitter.configs', -- Sets main module to use for opts
-- [[ Configure Treesitter ]] See `:help nvim-treesitter`
opts = {
ensure_installed = { 'bash', 'c', 'diff', 'html', 'lua', 'luadoc', 'markdown', 'markdown_inline', 'query', 'vim', 'vimdoc' },
-- Autoinstall languages that are not installed
auto_install = true,
highlight = {
enable = true,
-- Some languages depend on vim's regex highlighting system (such as Ruby) for indent rules.
-- If you are experiencing weird indenting issues, add the language to
-- the list of additional_vim_regex_highlighting and disabled languages for indent.
additional_vim_regex_highlighting = { 'ruby' },
},
indent = { enable = true, disable = { 'ruby' } },
},
config = function(_, opts)
local ts = require 'nvim-treesitter'
ts.setup()
-- Install only parsers that are not already present to avoid repeated startup spam.
if opts.auto_install and opts.ensure_installed and #opts.ensure_installed > 0 then
local installed = ts.get_installed 'parsers'
local missing = vim.tbl_filter(function(lang)
return not vim.list_contains(installed, lang)
end, opts.ensure_installed)
if #missing > 0 then
ts.install(missing)
end
end
vim.api.nvim_create_autocmd('FileType', {
group = vim.api.nvim_create_augroup('kickstart-treesitter', { clear = true }),
callback = function()
pcall(vim.treesitter.start)
end,
})
end,
-- There are additional nvim-treesitter modules that you can use to interact
-- with nvim-treesitter. You should go explore a few and see what interests you:
--
@ -961,23 +1078,11 @@ require('lazy').setup({
-- init.lua. If you want these files, they are in the repository, so you can just download them and
-- place them in the correct locations.
-- NOTE: Next step on your Neovim journey: Add/Configure additional plugins for Kickstart
--
-- Here are some example plugins that I've included in the Kickstart repository.
-- Uncomment any of the lines below to enable them (you will need to restart nvim).
--
-- require 'kickstart.plugins.debug',
-- require 'kickstart.plugins.indent_line',
-- require 'kickstart.plugins.lint',
-- require 'kickstart.plugins.autopairs',
-- require 'kickstart.plugins.neo-tree',
-- require 'kickstart.plugins.gitsigns', -- adds gitsigns recommend keymaps
-- NOTE: The import below can automatically add your own plugins, configuration, etc from `lua/custom/plugins/*.lua`
-- This is the easiest way to modularize your config.
--
-- Uncomment the following line and add your plugins to `lua/custom/plugins/*.lua` to get going.
-- { import = 'custom.plugins' },
{ import = 'custom.plugins' },
--
-- For additional information with loading, sourcing and examples see `:help lazy.nvim-🔌-plugin-spec`
-- Or use telescope!

View File

@ -0,0 +1,72 @@
return {
'ThePrimeagen/harpoon',
branch = 'harpoon2',
dependencies = { 'nvim-lua/plenary.nvim' },
config = function()
local harpoon = require 'harpoon'
harpoon:setup {
default = {
select = function(list_item, _, options)
if not list_item or not list_item.value or list_item.value == '' then
return
end
options = options or {}
local open_cmd = 'edit'
if options.vsplit then
open_cmd = 'vsplit'
elseif options.split then
open_cmd = 'split'
elseif options.tabedit then
open_cmd = 'tabedit'
end
vim.cmd(open_cmd .. ' ' .. vim.fn.fnameescape(list_item.value))
local context = list_item.context or {}
local row = math.max(1, tonumber(context.row) or 1)
local col = math.max(0, tonumber(context.col) or 0)
local line_count = vim.api.nvim_buf_line_count(0)
if line_count < 1 then
return
end
if row > line_count then
row = line_count
end
local row_text = vim.api.nvim_buf_get_lines(0, row - 1, row, false)[1] or ''
if col > #row_text then
col = #row_text
end
pcall(vim.api.nvim_win_set_cursor, 0, { row, col })
end,
},
}
vim.keymap.set('n', '<leader>a', function()
if vim.bo.buftype ~= '' then
vim.notify('Harpoon: current buffer is not a file', vim.log.levels.INFO)
return
end
harpoon:list():add()
end, { desc = 'Harpoon add' })
vim.keymap.set('n', '<leader>hm', function()
harpoon.ui:toggle_quick_menu(harpoon:list())
end, { desc = 'Harpoon menu' })
vim.keymap.set('n', '<C-e>', function()
harpoon.ui:toggle_quick_menu(harpoon:list())
end, { desc = 'Harpoon menu' })
vim.api.nvim_create_user_command('HarpoonMenu', function()
harpoon.ui:toggle_quick_menu(harpoon:list())
end, { desc = 'Toggle Harpoon quick menu' })
vim.keymap.set('n', '<C-S-P>', function()
harpoon:list():prev()
end)
vim.keymap.set('n', '<C-S-N>', function()
harpoon:list():next()
end)
end,
}

View File

@ -8,6 +8,15 @@ return {
lint.linters_by_ft = {
markdown = { 'markdownlint' },
}
lint.linters.markdownlint = vim.tbl_deep_extend('force', lint.linters.markdownlint or {}, {
args = {
'--stdin',
'--disable',
'MD013', -- line length
'MD033', -- inline HTML
'MD041', -- first line heading
},
})
-- To allow other plugins to add linters to require('lint').linters_by_ft,
-- instead set linters_by_ft like this:

View File

@ -0,0 +1,27 @@
return {
{
'MeanderingProgrammer/render-markdown.nvim',
ft = { 'markdown' },
dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' },
opts = {
file_types = { 'markdown' },
},
},
{
'iamcco/markdown-preview.nvim',
ft = { 'markdown' },
cmd = { 'MarkdownPreviewToggle', 'MarkdownPreview', 'MarkdownPreviewStop' },
build = function()
vim.fn['mkdp#util#install']()
end,
init = function()
vim.g.mkdp_auto_start = 0
vim.g.mkdp_auto_close = 1
vim.g.mkdp_refresh_slow = 0
vim.g.mkdp_filetypes = { 'markdown' }
end,
keys = {
{ '<leader>mp', '<cmd>MarkdownPreviewToggle<CR>', desc = '[M]arkdown [P]review' },
},
},
}

View File

@ -0,0 +1,18 @@
return {
'NeogitOrg/neogit',
lazy = true,
dependencies = {
'nvim-lua/plenary.nvim', -- required
'sindrets/diffview.nvim', -- optional - Diff integration
-- Only one of these is needed.
'nvim-telescope/telescope.nvim', -- optional
'ibhagwan/fzf-lua', -- optional
'nvim-mini/mini.pick', -- optional
'folke/snacks.nvim', -- optional
},
cmd = 'Neogit',
keys = {
{ '<leader>gg', '<cmd>Neogit<cr>', desc = 'Show Neogit UI' },
},
}

View File

@ -0,0 +1,83 @@
return {
'NickvanDyke/opencode.nvim',
dependencies = {
-- Recommended for `ask()` and `select()`.
-- Required for `snacks` provider.
---@module 'snacks' <- Loads `snacks.nvim` types for configuration intellisense.
{ 'folke/snacks.nvim', opts = { input = {}, picker = {}, terminal = {} } },
},
config = function()
---@type opencode.Opts
vim.g.opencode_opts = {
provider = {
enabled = 'snacks',
snacks = {
auto_close = false,
win = {
position = 'right',
border = 'rounded',
width = math.floor(vim.o.columns * 0.35),
enter = false,
},
},
},
}
-- Required for `opts.events.reload`.
vim.o.autoread = true
-- Recommended/example keymaps.
vim.keymap.set({ 'n', 'x' }, '<C-a>', function() require('opencode').ask('@this: ', { submit = true }) end, { desc = 'Ask opencode…' })
vim.keymap.set({ 'n', 'x' }, '<C-x>', function() require('opencode').select() end, { desc = 'Execute opencode action…' })
local function opencode_toggle()
local ok, err = pcall(function()
require('opencode').toggle()
end)
if not ok then
vim.notify('opencode toggle failed: ' .. tostring(err), vim.log.levels.ERROR)
end
end
vim.keymap.set({ 'n', 't' }, '<C-.>', opencode_toggle, { desc = 'Toggle opencode' })
vim.keymap.set('n', '<leader>oc', opencode_toggle, { desc = 'Toggle opencode chat' })
local opencode_term_nav_group = vim.api.nvim_create_augroup('opencode-term-nav', { clear = true })
vim.api.nvim_create_autocmd('FileType', {
group = opencode_term_nav_group,
pattern = 'opencode_terminal',
callback = function(ev)
local function tmux_nav(cmd)
local esc = vim.api.nvim_replace_termcodes('<C-\\><C-n>', true, false, true)
vim.api.nvim_feedkeys(esc, 'n', false)
vim.cmd(cmd)
end
vim.keymap.set('t', '<C-h>', function()
tmux_nav 'TmuxNavigateLeft'
end, { buffer = ev.buf, silent = true, desc = 'Tmux navigate left from opencode' })
vim.keymap.set('t', '<C-j>', function()
tmux_nav 'TmuxNavigateDown'
end, { buffer = ev.buf, silent = true, desc = 'Tmux navigate down from opencode' })
vim.keymap.set('t', '<C-k>', function()
tmux_nav 'TmuxNavigateUp'
end, { buffer = ev.buf, silent = true, desc = 'Tmux navigate up from opencode' })
vim.keymap.set('t', '<C-l>', function()
tmux_nav 'TmuxNavigateRight'
end, { buffer = ev.buf, silent = true, desc = 'Tmux navigate right from opencode' })
end,
})
vim.keymap.set({ 'n', 'x' }, 'go', function() return require('opencode').operator '@this ' end, { desc = 'Add range to opencode', expr = true })
vim.keymap.set('n', 'goo', function() return require('opencode').operator '@this ' .. '_' end, { desc = 'Add line to opencode', expr = true })
vim.keymap.set('n', '<S-C-u>', function() require('opencode').command 'session.half.page.up' end, { desc = 'Scroll opencode up' })
vim.keymap.set('n', '<S-C-d>', function() require('opencode').command 'session.half.page.down' end, { desc = 'Scroll opencode down' })
-- You may want these if you stick with the opinionated "<C-a>" and "<C-x>" above — otherwise consider "<leader>o…".
vim.keymap.set('n', '+', '<C-a>', { desc = 'Increment under cursor', noremap = true })
vim.keymap.set('n', '-', '<C-x>', { desc = 'Decrement under cursor', noremap = true })
end,
}

View File

@ -0,0 +1,21 @@
return {
'supermaven-inc/supermaven-nvim',
config = function()
require('supermaven-nvim').setup {
keymaps = {
accept_suggestion = '<Tab>',
clear_suggestion = '<C-]>',
accept_word = '<C-j>',
},
ignore_filetypes = { cpp = true }, -- or { "cpp", }
color = {
suggestion_color = '#ffffff',
cterm = 244,
},
log_level = 'info', -- set to "off" to disable logging completely
disable_inline_completion = false, -- disables inline completion for use with cmp
disable_keymaps = false, -- disables built in keymaps for more manual control
condition = function() return false end, -- condition to check for stopping supermaven, `true` means to stop supermaven when the condition is true.
}
end,
}

View File

@ -0,0 +1,18 @@
return {
'christoomey/vim-tmux-navigator',
cmd = {
'TmuxNavigateLeft',
'TmuxNavigateDown',
'TmuxNavigateUp',
'TmuxNavigateRight',
'TmuxNavigatePrevious',
'TmuxNavigatorProcessList',
},
keys = {
{ '<c-h>', '<cmd><C-U>TmuxNavigateLeft<cr>' },
{ '<c-j>', '<cmd><C-U>TmuxNavigateDown<cr>' },
{ '<c-k>', '<cmd><C-U>TmuxNavigateUp<cr>' },
{ '<c-l>', '<cmd><C-U>TmuxNavigateRight<cr>' },
{ '<c-\\>', '<cmd><C-U>TmuxNavigatePrevious<cr>' },
},
}

View File

@ -0,0 +1,5 @@
return {
'pmizio/typescript-tools.nvim',
dependencies = { 'nvim-lua/plenary.nvim', 'neovim/nvim-lspconfig' },
opts = {},
}

81
lua/custom/wrapping.lua Normal file
View File

@ -0,0 +1,81 @@
local M = {}
local defaults = {
width = 100,
patterns = { '*.md', '*.markdown' },
}
local function apply_wrap_options(local_opts, width)
local_opts.wrap = true
local_opts.linebreak = true
local_opts.breakindent = true
local_opts.textwidth = width
local_opts.colorcolumn = ''
local_opts.formatoptions:append 't'
local_opts.formatoptions:append 'a'
local_opts.formatoptions:remove 'l'
end
local function can_reflow(bufnr)
return vim.api.nvim_buf_is_valid(bufnr) and vim.bo[bufnr].modifiable and vim.bo[bufnr].buftype == ''
end
local function reflow_whole_buffer(bufnr, preserve_view)
if not can_reflow(bufnr) then
return
end
vim.api.nvim_buf_call(bufnr, function()
local view = preserve_view and vim.fn.winsaveview() or nil
vim.cmd 'silent keepjumps normal! gggqG'
if view then
vim.fn.winrestview(view)
end
end)
end
function M.setup(opts)
opts = vim.tbl_deep_extend('force', defaults, opts or {})
apply_wrap_options(vim.opt, opts.width)
local group = vim.api.nvim_create_augroup('custom_wrapping_rules', { clear = true })
vim.api.nvim_create_autocmd('FileType', {
group = group,
callback = function()
-- Apply after ftplugins so local overrides don't drop wrap options.
vim.schedule(function()
apply_wrap_options(vim.opt_local, opts.width)
end)
end,
})
vim.api.nvim_create_autocmd('BufReadPost', {
group = group,
pattern = opts.patterns,
callback = function(args)
-- Reflow existing prose on open so the hard wrap rule is applied immediately.
if vim.b[args.buf].did_initial_wrap then
return
end
vim.b[args.buf].did_initial_wrap = true
vim.schedule(function()
reflow_whole_buffer(args.buf, false)
end)
end,
})
vim.api.nvim_create_autocmd('BufWritePre', {
group = group,
pattern = opts.patterns,
callback = function(args)
if not vim.bo[args.buf].modified then
return
end
reflow_whole_buffer(args.buf, true)
end,
})
end
return M