From 291ae1ea52096c793c4821de5a5d42a92f3aa64e Mon Sep 17 00:00:00 2001 From: RiverMatsumoto Date: Thu, 1 Jan 2026 18:36:08 -1000 Subject: [PATCH] lots of keybinds and familiar things changed --- init.lua | 379 ++++++++++++++++++++++++++++----------- lua/bootstrap/deps.lua | 33 ++++ lua/bootstrap/pacman.lua | 111 ++++++++++++ 3 files changed, 422 insertions(+), 101 deletions(-) create mode 100644 lua/bootstrap/deps.lua create mode 100644 lua/bootstrap/pacman.lua diff --git a/init.lua b/init.lua index 9d523303..523c4fda 100644 --- a/init.lua +++ b/init.lua @@ -1,7 +1,8 @@ -vim.g.mapleader = ' ' vim.g.maplocalleader = ' ' --- for chatgpt -_G.chatgpt_model = 'gpt-5.1-codex-mini' +vim.g.mapleader = ' ' + +-- install deps if need to +require("bootstrap.pacman") -- ========================= -- Lazy.nvim bootstrap @@ -73,42 +74,6 @@ require('lazy').setup({ }, 'rhysd/git-messenger.vim', - { - 'jackMort/ChatGPT.nvim', - event = 'VeryLazy', - dependencies = { - 'nvim-lua/plenary.nvim', - 'MunifTanjim/nui.nvim', - 'nvim-telescope/telescope.nvim', - }, - config = function() - require('chatgpt').setup { - openai_params = { - -- NOTE: model can be a function returning the model name - -- this is useful if you want to change the model on the fly - -- using commands - -- Example: - -- model = function() - -- if some_condition() then - -- return "gpt-5" - -- else - -- return "gpt-5-mini" - -- end - -- end, - model = function() - return _G.chatgpt_model - end, - frequency_penalty = 0, - presence_penalty = 0, - max_tokens = 4095, - temperature = 0.2, - top_p = 0.1, - n = 1, - api_key_cmd = 'echo $OPENAI_API_KEY', - }, - } - end, - }, { 'lewis6991/gitsigns.nvim', @@ -218,7 +183,24 @@ require('lazy').setup({ 'MunifTanjim/nui.nvim', }, opts = { + enable_preview = true, + filesystem = { + -- open images (and anything else) externally + commands = { + system_open = function(state) + local node = state.tree:get_node() + local path = node:get_id() -- absolute path + vim.fn.jobstart({ 'imv', path }, { detach = true }) + end, + }, + window = { + mappings = { + ['P'] = 'toggle_preview', + ['O'] = 'system_open', -- press O to open with external viewer + }, + }, + filtered_items = { visible = false, hide_dotfiles = true, @@ -230,25 +212,33 @@ require('lazy').setup({ }, }, - -- Buffers/tabs + -- LAZY PLUGIN SPEC (replace bufferline with barbar) { - 'akinsho/bufferline.nvim', - version = '*', - dependencies = 'nvim-tree/nvim-web-devicons', + 'romgrk/barbar.nvim', + dependencies = { + 'nvim-tree/nvim-web-devicons', + 'lewis6991/gitsigns.nvim', -- optional, for git status icons + }, + init = function() + vim.g.barbar_auto_setup = false + end, opts = { - options = { - mode = 'buffers', -- tabs or buffers - diagnostics = 'nvim_lsp', - show_buffer_close_icons = false, - show_close_icon = false, - hover = { - enabled = true, - delay = 200, - reveal = {'close'} - }, + animation = true, + auto_hide = false, + tabpages = false, -- show buffers, not Vim tabpages + clickable = true, + icons = { + preset = 'slanted', + button = '󰅖', + }, + + -- Treat neo-tree as a sidebar so it doesn't become a "tab" and layout stays sane + sidebar_filetypes = { + ['neo-tree'] = { event = 'BufWipeout' }, }, }, }, + 'nvim-tree/nvim-web-devicons', { @@ -335,16 +325,6 @@ require('lazy').setup({ { 'nvim-pack/nvim-spectre', opts = {} }, - { - 'romgrk/barbar.nvim', - event = 'BufEnter', - dependencies = 'nvim-tree/nvim-web-devicons', - init = function() - vim.g.barbar_auto_setup = false - end, - lazy = true, - }, - { 'lukas-reineke/indent-blankline.nvim', main = 'ibl', @@ -605,7 +585,7 @@ require('lazy').setup({ map('ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') map('rn', vim.lsp.buf.rename, '[R]e[n]ame') map('ca', vim.lsp.buf.code_action, '[C]ode [A]ction') - map('K', vim.lsp.buf.hover, 'Hover Documentation') + map('T', vim.lsp.buf.hover, 'Hover Documentation') map('', vim.lsp.buf.signature_help, 'Signature Documentation') local client = vim.lsp.get_client_by_id(event.data.client_id) @@ -866,6 +846,202 @@ require('lazy').setup({ end, }, + { + 'Kurama622/llm.nvim', + dependencies = { 'nvim-lua/plenary.nvim', 'MunifTanjim/nui.nvim' }, + cmd = { 'LLMSessionToggle', 'LLMSelectedTextHandler', 'LLMAppHandler' }, + config = function() + require('llm').setup { + -- GitHub Models (Azure inference) + url = 'https://api.openai.com/v1/chat/completions', + api_type = 'openai', + + -- Set this to what you want to use (must support /chat/completions) + model = _G.chatgpt_model or 'gpt-5-nano', + + -- Sensible coding defaults + --max_tokens = 4095, + --temperature = 0.2, + --top_p = 0.1, + + -- Keep it code-focused + prompt = 'You are a helpful programming assistant. Be concise, show code when needed, and prefer practical fixes.', + -- Visual selection -> context prompt + selected_text_handler = { + prompt = function(selection) + return string.format( + 'You are a helpful programming assistant.\n\n' .. 'Context (selected text):\n' .. '```text\n%s\n```\n\n' .. 'Task:\n', + selection + ) + end, + }, + + -- Optional cosmetics (minimal) + spinner = { + text = { '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' }, + hl = 'Title', + }, + prefix = { + user = { text = 'You: ', hl = 'Title' }, + assistant = { text = 'AI: ', hl = 'Added' }, + }, + + -- Persist chat history + save_session = true, + max_history = 30, + max_history_name_length = 40, + + -- Keymaps inside the session UI + keys = { + -- Input window + ['Input:Submit'] = { mode = 'i', key = '' }, -- Enter sends (your issue) + ['Input:Cancel'] = { mode = { 'n', 'i' }, key = '' }, + ['Input:Resend'] = { mode = { 'n', 'i' }, key = '' }, + + -- History (only if save_session=true) + ['Input:HistoryNext'] = { mode = { 'n', 'i' }, key = '' }, + ['Input:HistoryPrev'] = { mode = { 'n', 'i' }, key = '' }, + + -- Output window ("split" style) + ['Output:Ask'] = { mode = 'n', key = 'i' }, + ['Output:Cancel'] = { mode = 'n', key = '' }, + ['Output:Resend'] = { mode = 'n', key = '' }, + + -- Session window ("float" style) + ['Session:Toggle'] = { mode = 'n', key = 'ai' }, -- your chosen toggle + ['Session:Close'] = { mode = 'n', key = { '', 'Q' } }, + }, + + -- Optional diff display used by some tools/handlers + display = { + diff = { + layout = 'vertical', + opts = { + 'internal', + 'filler', + 'closeoff', + 'algorithm:patience', + 'followwrap', + 'linematch:120', + }, + provider = 'mini_diff', + disable_diagnostic = true, + }, + }, + + callbacks = { + on_response = function(resp) + local usage = resp and resp.usage + if usage then + vim.notify( + string.format( + 'LLM tokens — prompt: %d, completion: %d, total: %d', + usage.prompt_tokens or 0, + usage.completion_tokens or 0, + usage.total_tokens or 0 + ), + vim.log.levels.INFO + ) + end + end, + }, + + -- If you later add tools: + app_handler = { + -- Visual-select text -> run this -> output in a floating result window. + AskWithContext = { + handler = 'attach_to_chat_handler', + prompt = [[ + Answer the user’s question (likely code related) using the context very briefly and concisely: + ]], + opts = { + -- this is the key part: append the visual selection after the prompt + apply_visual_selection = true, -- described in docs for flexi_handler :contentReference[oaicite:2]{index=2} + is_codeblock = true, + enter_input = true, + enter_flexible_window = false, + --exit_on_move = true, + }, + }, + CodeExplain = { + handler = 'flexi_handler', + prompt = 'Explain the following code very briefly, please only return the explanation', + opts = { + enter_flexible_window = true, + }, + }, + }, + } + end, + keys = { + { 'ai', 'LLMSessionToggle', mode = 'n', silent = true, desc = 'LLM: toggle session' }, + { 'as', 'LLMSelectedTextHandler', mode = 'x', silent = true, desc = 'LLM: send selection' }, + -- If you add tools: + { 'ax', 'LLMAppHandler CodeExplain', mode = 'x', silent = true, desc = 'LLM tool: Explain' }, + { 'ai', 'LLMAppHandler AskWithContext', mode = 'x', silent = true, desc = 'LLM tool: Ask with context' }, + }, + }, + + { + 'MeanderingProgrammer/render-markdown.nvim', + dependencies = { + { + 'nvim-treesitter/nvim-treesitter', + branch = 'main', + config = function() + vim.api.nvim_create_autocmd('FileType', { + pattern = { 'llm', 'markdown' }, + callback = function() + vim.treesitter.start(0, 'markdown') + end, + }) + end, + }, + 'nvim-mini/mini.icons', + }, -- if you use standalone mini plugins + ft = { 'markdown', 'llm' }, + + config = function() + require('render-markdown').setup { + restart_highlighter = true, + heading = { + enabled = true, + sign = false, + position = 'overlay', -- inline | overlay + icons = { '󰎤 ', '󰎧 ', '󰎪 ', '󰎭 ', '󰎱 ', '󰎳 ' }, + signs = { '󰫎 ' }, + width = 'block', + left_margin = 0, + left_pad = 0, + right_pad = 0, + min_width = 0, + border = false, + border_virtual = false, + border_prefix = false, + above = '▄', + below = '▀', + backgrounds = {}, + foregrounds = { + 'RenderMarkdownH1', + 'RenderMarkdownH2', + 'RenderMarkdownH3', + 'RenderMarkdownH4', + 'RenderMarkdownH5', + 'RenderMarkdownH6', + }, + }, + dash = { + enabled = true, + icon = '─', + width = 0.5, + left_margin = 0.5, + highlight = 'RenderMarkdownDash', + }, + code = { style = 'normal' }, + } + end, + }, + -- DAP { 'mfussenegger/nvim-dap', @@ -1050,6 +1226,7 @@ local smear_profiles = { -- 1) Frost Mist eco_smear = { -- General (keep core behavior) + cursor_color = '#ffe6b2', smear_between_buffers = true, smear_between_neighbor_lines = true, min_horizontal_distance_smear = 1, -- reduces tiny smears @@ -1141,6 +1318,7 @@ local smear_profiles = { }, } +-- smear settings local smear_profile_order = { 'silver_blade', 'eco_smear', @@ -1168,6 +1346,8 @@ end, { return smear_profile_order end, }) +-- Apply a default on startup (pick one) +apply_smear_profile 'silver_blade' vim.api.nvim_create_user_command('SmearProfileNext', function() current_idx = (current_idx % #smear_profile_order) + 1 @@ -1183,8 +1363,6 @@ end, {}) vim.keymap.set('n', 'pn', 'SmearProfileNext', { desc = 'Smear profile: next' }) vim.keymap.set('n', 'pp', 'SmearProfilePrev', { desc = 'Smear profile: prev' }) --- Apply a default on startup (pick one) -apply_smear_profile 'silver_blade' -- ========================================= -- ============ END SMEAR PROFILE ========== -- ========================================= @@ -1231,14 +1409,14 @@ local function set_indent(ts) end vim.api.nvim_create_autocmd('FileType', { - pattern = { 'lua', 'javascript', 'typescript', 'tsx', 'json', 'yaml', 'toml', 'html', 'css', 'rust', 'c', 'cpp' }, + pattern = { 'lua', 'javascript', 'typescript', 'tsx', 'json', 'yaml', 'toml', 'html', 'css' }, callback = function() set_indent(2) end, }) vim.api.nvim_create_autocmd('FileType', { - pattern = { 'python', 'sh', 'bash', 'zsh', 'go' }, + pattern = { 'python', 'sh', 'bash', 'zsh', 'go', 'rust', 'cpp', 'c' }, callback = function() set_indent(4) end, @@ -1365,7 +1543,7 @@ vim.keymap.set('n', 'xw', 'TroubleToggle workspace_diagnostics' vim.keymap.set('n', 'xd', 'TroubleToggle document_diagnostics', { silent = true, noremap = true, desc = 'Document diagnostics (Trouble)' }) -- DAP -vim.keymap.set('n', '', ":lua require('dapui').toggle()", { desc = 'Toggle DAP UI' }) +vim.keymap.set('n', 'dap', ":lua require('dapui').toggle()", { desc = 'Toggle DAP UI' }) vim.keymap.set('n', 'dc', ":lua require('dap').continue()", { desc = 'DAP continue' }) vim.keymap.set('n', 'do', ":lua require('dap').step_over()", { desc = 'DAP step over' }) vim.keymap.set('n', 'di', ":lua require('dap').step_into()", { desc = 'DAP step into' }) @@ -1382,22 +1560,33 @@ vim.keymap.set('n', 'dt', ":lua require('dap').toggle_breakpoint()", vim.keymap.set('n', 'dm', ":lua require('dap-python').test_method()", { silent = true, noremap = true, desc = 'DAP test method' }) vim.keymap.set('n', 'df', ":lua require('dap-python').test_class()", { silent = true, noremap = true, desc = 'DAP test class' }) --- barbar -vim.keymap.set('n', '', 'BufferPrevious', { silent = true, noremap = true, desc = 'Previous buffer' }) -vim.keymap.set('n', '', 'BufferNext', { silent = true, noremap = true, desc = 'Next buffer' }) -vim.keymap.set('n', '', 'BufferClose', { silent = true, noremap = true, desc = 'Close buffer' }) +-- bufferline local opts = { noremap = true, silent = true } -vim.keymap.set('n', '', 'BufferLineGoToBuffer 1', vim.tbl_extend('force', opts, { desc = 'Go to buffer 1' })) -vim.keymap.set('n', '', 'BufferLineGoToBuffer 2', vim.tbl_extend('force', opts, { desc = 'Go to buffer 2' })) -vim.keymap.set('n', '', 'BufferLineGoToBuffer 3', vim.tbl_extend('force', opts, { desc = 'Go to buffer 3' })) -vim.keymap.set('n', '', 'BufferLineGoToBuffer 4', vim.tbl_extend('force', opts, { desc = 'Go to buffer 4' })) -vim.keymap.set('n', '', 'BufferLineGoToBuffer 5', vim.tbl_extend('force', opts, { desc = 'Go to buffer 5' })) -vim.keymap.set('n', '', 'BufferLineGoToBuffer 6', vim.tbl_extend('force', opts, { desc = 'Go to buffer 6' })) -vim.keymap.set('n', '', 'BufferLineGoToBuffer 7', vim.tbl_extend('force', opts, { desc = 'Go to buffer 7' })) -vim.keymap.set('n', '', 'BufferLineGoToBuffer 8', vim.tbl_extend('force', opts, { desc = 'Go to buffer 8' })) -vim.keymap.set('n', '', 'BufferLineGoToBuffer 9', vim.tbl_extend('force', opts, { desc = 'Go to buffer 9' })) + +-- KEYMAPS (Barbar) +local opts = { noremap = true, silent = true } + +vim.keymap.set('n', '', 'BufferGoto 1', vim.tbl_extend('force', opts, { desc = 'Go to buffer 1' })) +vim.keymap.set('n', '', 'BufferGoto 2', vim.tbl_extend('force', opts, { desc = 'Go to buffer 2' })) +vim.keymap.set('n', '', 'BufferGoto 3', vim.tbl_extend('force', opts, { desc = 'Go to buffer 3' })) +vim.keymap.set('n', '', 'BufferGoto 4', vim.tbl_extend('force', opts, { desc = 'Go to buffer 4' })) +vim.keymap.set('n', '', 'BufferGoto 5', vim.tbl_extend('force', opts, { desc = 'Go to buffer 5' })) +vim.keymap.set('n', '', 'BufferGoto 6', vim.tbl_extend('force', opts, { desc = 'Go to buffer 6' })) +vim.keymap.set('n', '', 'BufferGoto 7', vim.tbl_extend('force', opts, { desc = 'Go to buffer 7' })) +vim.keymap.set('n', '', 'BufferGoto 8', vim.tbl_extend('force', opts, { desc = 'Go to buffer 8' })) +vim.keymap.set('n', '', 'BufferGoto 9', vim.tbl_extend('force', opts, { desc = 'Go to buffer 9' })) vim.keymap.set('n', '', 'BufferLast', vim.tbl_extend('force', opts, { desc = 'Go to last buffer' })) +-- Close current buffer (Barbar) +vim.keymap.set('n', '', 'BufferClose', vim.tbl_extend('force', opts, { desc = 'Close buffer' })) + +-- Close current window/split +vim.keymap.set('n', '', 'close', vim.tbl_extend('force', opts, { desc = 'Close window' })) + +vim.keymap.set('n', '', 'BufferNext', { desc = 'Go to next buffer' }) +vim.keymap.set('n', '', 'BufferPrevious', { desc = 'Go to previous buffer' }) + +-- barbar colors -- quickfix vim.keymap.set('n', 'cn', ':cnext', { desc = 'Next quickfix item' }) @@ -1409,25 +1598,9 @@ vim.keymap.set('n', 'mp', ':MarkdownPreview', { desc = 'Markdown pre -- git vim.keymap.set('n', 'ga', ':Telescope coauthors', { desc = 'Select git co-authors' }) --- AI model switching -vim.keymap.set('n', 'an', function() - _G.chatgpt_model = 'gpt-5-nano' - print 'ChatGPT → gpt-5-nano' -end, { desc = 'ChatGPT model: gpt-5-nano' }) - -vim.keymap.set('n', 'ac', function() - _G.chatgpt_model = 'gpt-5.1-codex-mini' - print 'ChatGPT → gpt-5.1-codex-mini' -end, { desc = 'ChatGPT model: gpt-5.1-codex-mini' }) - -vim.keymap.set('n', 'ai', 'ChatGPT', { desc = 'Open ChatGPT prompt' }) - -- delete backwards vim.keymap.set({ 'i', 'c' }, '', '', { noremap = true, desc = 'Delete previous word' }) -vim.keymap.set('n', '', 'BufferLineCycleNext', { desc = 'Go to next tab' }) -vim.keymap.set('n', '', 'BufferLineCyclePrev', { desc = 'Go backwards a tab' }) - vim.keymap.set('n', 'tc', ':tabclose', { desc = 'Close current tab' }) vim.keymap.set('n', 'fk', ':FloatermKill!', { desc = 'Kill all floaterm terminals' }) vim.keymap.set('x', 'S', '(nvim-surround-visual)', { remap = true }, { desc = 'Surround selected text' }) @@ -1462,9 +1635,9 @@ _G.toggle_neotree = toggle_neotree vim.api.nvim_set_keymap('n', '', ':lua toggle_neotree()', { noremap = true, silent = true }) -- Floaterm -vim.api.nvim_set_keymap('n', '', ':FloatermToggle', { noremap = true }) -vim.api.nvim_set_keymap('i', '', ':FloatermToggle', { noremap = true }) -vim.api.nvim_set_keymap('t', '', ':FloatermToggle', { noremap = true, silent = true }) +vim.api.nvim_set_keymap('n', '', ':FloatermToggle', { noremap = true }) +vim.api.nvim_set_keymap('i', '', ':FloatermToggle', { noremap = true }) +vim.api.nvim_set_keymap('t', '', ':FloatermToggle', { noremap = true, silent = true }) -- Comment.nvim keymaps vim.api.nvim_set_keymap('n', '', 'lua require("Comment.api").toggle.linewise.current()', { noremap = true, silent = true }) @@ -1478,3 +1651,7 @@ vim.keymap.set('n', 'ga', ':Telescope coauthors') -- install treesitter parsers require('nvim-treesitter').install { 'c', 'rust', 'gdscript', 'c#' } + +-- LSP basics +vim.keymap.set('n', '', vim.lsp.buf.rename, { silent = true, desc = 'LSP: Rename' }) +vim.keymap.set('n', '', vim.lsp.buf.references, { silent = true, desc = 'LSP: References' }) diff --git a/lua/bootstrap/deps.lua b/lua/bootstrap/deps.lua new file mode 100644 index 00000000..f6ad05b1 --- /dev/null +++ b/lua/bootstrap/deps.lua @@ -0,0 +1,33 @@ +-- lua/bootstrap/deps.lua +-- System-level deps for this config (Arch / pacman names) + +return { + -- bootstrap + "neovim", + "git", + + -- telescope / grep + "ripgrep", + "fd", + + -- builds native plugins (telescope-fzf-native, treesitter parsers, etc.) + "base-devel", + + -- clipboard (Wayland) + "wl-clipboard", + -- X11 alternative (optional): "xclip", + + -- markdown-preview.nvim build/runtime + "nodejs", + "npm", + + -- toggleterm custom commands + "lazygit", + + -- neo-tree external opener + "imv", + + -- treesitter + "tree-sitter-cli", +} + diff --git a/lua/bootstrap/pacman.lua b/lua/bootstrap/pacman.lua new file mode 100644 index 00000000..2dbbf123 --- /dev/null +++ b/lua/bootstrap/pacman.lua @@ -0,0 +1,111 @@ +-- ~/.config/nvim/lua/bootstrap/pacman.lua +-- Fix1: run pacman inside a Neovim terminal so sudo has a real TTY. + +local M = {} + +local function has_exe(exe) + return vim.fn.executable(exe) == 1 +end + +local function pacman_has(pkg) + local out = vim.fn.system({ "pacman", "-Qi", pkg }) + return vim.v.shell_error == 0 and out ~= nil and out ~= "" +end + +local function missing_pkgs(pkgs) + local missing = {} + for _, p in ipairs(pkgs) do + if not pacman_has(p) then + table.insert(missing, p) + end + end + return missing +end + +local function shell_escape_arg(s) + -- minimal quoting for a shell command string + return "'" .. tostring(s):gsub("'", [['"'"']]) .. "'" +end + +local function open_install_terminal(pkgs) + if #pkgs == 0 then + return true + end + + if not has_exe("sudo") then + vim.notify("Missing `sudo`; cannot auto-install pacman deps.", vim.log.levels.ERROR) + return false + end + + -- Build a single shell command so sudo prompts normally. + local parts = { "sudo", "pacman", "-S", "--needed" } + for _, p in ipairs(pkgs) do + table.insert(parts, shell_escape_arg(p)) + end + local cmd = table.concat(parts, " ") + + vim.notify("Opening terminal to install:\n" .. table.concat(pkgs, ", "), vim.log.levels.WARN) + + -- Open a terminal split and run the command. User can enter sudo password normally. + vim.cmd("botright 15split") + vim.cmd("terminal " .. cmd) + vim.cmd("startinsert") + + return true +end + +function M.check() + if not has_exe("pacman") then + vim.notify("pacman not found. This bootstrap is Arch-specific.", vim.log.levels.WARN) + return {} + end + local deps = require("bootstrap.deps") + return missing_pkgs(deps) +end + +function M.install(opts) + opts = opts or {} + local miss = M.check() + if #miss == 0 then + if not opts.quiet then + vim.notify("All system deps already installed.", vim.log.levels.INFO) + end + return true + end + + local prompt = "Missing system deps:\n\n" + .. table.concat(miss, "\n") + .. "\n\nOpen a terminal and run sudo pacman to install them?" + + local ok = true + if not opts.force then + ok = (vim.fn.confirm(prompt, "&Yes\n&No", 1) == 1) + end + if not ok then + return false + end + + return open_install_terminal(miss) +end + +-- Commands +vim.api.nvim_create_user_command("DepsCheck", function() + local miss = M.check() + if #miss == 0 then + vim.notify("DepsCheck: OK (no missing packages).", vim.log.levels.INFO) + else + vim.notify("DepsCheck missing:\n" .. table.concat(miss, ", "), vim.log.levels.WARN) + end +end, {}) + +vim.api.nvim_create_user_command("DepsInstall", function() + M.install({ force = true }) +end, {}) + +-- Run once per session (prompt-based) +if vim.g.__deps_bootstrap_ran ~= true then + vim.g.__deps_bootstrap_ran = true + M.install({ force = false, quiet = true }) +end + +return M