839 lines
25 KiB
Lua
839 lines
25 KiB
Lua
-- phill Neovim config (nightly)
|
|
|
|
vim.g.mapleader = " "
|
|
vim.g.maplocalleader = " "
|
|
|
|
local opt = vim.opt
|
|
local map = vim.keymap.set
|
|
|
|
-- ============================================================================
|
|
-- Core options
|
|
-- ============================================================================
|
|
|
|
opt.number = true
|
|
opt.relativenumber = true
|
|
opt.mouse = "a"
|
|
opt.clipboard = "unnamedplus"
|
|
|
|
opt.swapfile = false
|
|
opt.backup = false
|
|
opt.writebackup = false
|
|
opt.undofile = true
|
|
|
|
opt.ignorecase = true
|
|
opt.smartcase = true
|
|
opt.incsearch = true
|
|
opt.hlsearch = false
|
|
|
|
opt.termguicolors = true
|
|
opt.signcolumn = "yes"
|
|
opt.cursorline = true
|
|
opt.splitbelow = true
|
|
opt.splitright = true
|
|
opt.wrap = false
|
|
opt.linebreak = true
|
|
opt.breakindent = true
|
|
opt.scrolloff = 8
|
|
opt.sidescrolloff = 8
|
|
opt.updatetime = 200
|
|
opt.timeoutlen = 300
|
|
opt.confirm = true
|
|
opt.showmode = false
|
|
opt.laststatus = 3
|
|
opt.pumheight = 12
|
|
-- opt.cmdheight = 0
|
|
|
|
opt.expandtab = true
|
|
opt.smartindent = true
|
|
opt.shiftround = true
|
|
opt.tabstop = 2
|
|
opt.softtabstop = 2
|
|
opt.shiftwidth = 2
|
|
|
|
opt.list = true
|
|
opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" }
|
|
opt.fillchars = { eob = " " }
|
|
|
|
opt.completeopt = { "menu", "menuone", "noselect", "popup", "fuzzy" }
|
|
opt.winborder = "single"
|
|
opt.pumborder = "single"
|
|
|
|
opt.winbar = "%=%m %t %="
|
|
opt.showtabline = 0
|
|
|
|
-- ============================================================================
|
|
-- Basic keymaps
|
|
-- ============================================================================
|
|
|
|
map("n", "<Esc>", "<cmd>nohlsearch<cr><Esc>", { silent = true, desc = "Clear search highlight" })
|
|
|
|
-- j/k over display lines when no count is given
|
|
map({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", {
|
|
expr = true,
|
|
silent = true,
|
|
desc = "Down (display line)",
|
|
})
|
|
map({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", {
|
|
expr = true,
|
|
silent = true,
|
|
desc = "Up (display line)",
|
|
})
|
|
|
|
-- Save on Ctrl-s
|
|
map("n", "<C-s>", "<cmd>update<cr>", { silent = true, desc = "Save" })
|
|
map("i", "<C-s>", "<Esc><cmd>update<cr>gi", { silent = true, desc = "Save" })
|
|
map("v", "<C-s>", "<Esc><cmd>update<cr>gv", { silent = true, desc = "Save" })
|
|
|
|
-- Window navigation on Ctrl-hjkl
|
|
map("n", "<C-h>", "<C-w>h", { silent = true, desc = "Window left" })
|
|
map("n", "<C-j>", "<C-w>j", { silent = true, desc = "Window down" })
|
|
map("n", "<C-k>", "<C-w>k", { silent = true, desc = "Window up" })
|
|
map("n", "<C-l>", "<C-w>l", { silent = true, desc = "Window right" })
|
|
|
|
map("t", "<C-h>", [[<C-\><C-n><C-w>h]], { silent = true, desc = "Window left" })
|
|
map("t", "<C-j>", [[<C-\><C-n><C-w>j]], { silent = true, desc = "Window down" })
|
|
map("t", "<C-k>", [[<C-\><C-n><C-w>k]], { silent = true, desc = "Window up" })
|
|
map("t", "<C-l>", [[<C-\><C-n><C-w>l]], { silent = true, desc = "Window right" })
|
|
|
|
-- Buffer cycling
|
|
map("n", "H", "<cmd>bprevious<cr>", { silent = true, desc = "Previous buffer" })
|
|
map("n", "L", "<cmd>bnext<cr>", { silent = true, desc = "Next buffer" })
|
|
|
|
-- ============================================================================
|
|
-- Buffer helpers
|
|
-- ============================================================================
|
|
|
|
local function listed_buffers()
|
|
return vim.tbl_filter(function(buf)
|
|
return vim.api.nvim_buf_is_valid(buf) and vim.bo[buf].buflisted
|
|
end, vim.api.nvim_list_bufs())
|
|
end
|
|
|
|
local function delete_buffer(buf, opts)
|
|
opts = opts or {}
|
|
if not buf or buf == 0 then
|
|
buf = vim.api.nvim_get_current_buf()
|
|
end
|
|
|
|
local cmd = opts.wipe
|
|
and (opts.force and "bwipeout!" or "bwipeout")
|
|
or (opts.force and "bdelete!" or "bdelete")
|
|
|
|
pcall(vim.cmd, cmd .. " " .. buf)
|
|
end
|
|
|
|
local function delete_other_buffers(force)
|
|
local current = vim.api.nvim_get_current_buf()
|
|
for _, buf in ipairs(listed_buffers()) do
|
|
if buf ~= current then
|
|
delete_buffer(buf, { force = force })
|
|
end
|
|
end
|
|
end
|
|
|
|
local function delete_all_buffers(force)
|
|
for _, buf in ipairs(listed_buffers()) do
|
|
delete_buffer(buf, { force = force })
|
|
end
|
|
end
|
|
|
|
map("n", "<leader>bb", "<cmd>buffer #<cr>", { silent = true, desc = "Last buffer" })
|
|
map("n", "<leader>bd", function() delete_buffer(0, { force = false }) end, { desc = "Delete buffer" })
|
|
map("n", "<leader>bD", function() delete_buffer(0, { force = true }) end, { desc = "Force delete buffer" })
|
|
map("n", "<leader>bw", function() delete_buffer(0, { wipe = true }) end, { desc = "Wipe buffer" })
|
|
map("n", "<leader>bo", function() delete_other_buffers(false) end, { desc = "Delete other buffers" })
|
|
map("n", "<leader>ba", function() delete_all_buffers(false) end, { desc = "Delete all buffers" })
|
|
|
|
-- ============================================================================
|
|
-- netrw stays the default file browser
|
|
-- ============================================================================
|
|
|
|
vim.g.netrw_banner = 1
|
|
vim.g.netrw_liststyle = 3
|
|
vim.g.netrw_winsize = 30
|
|
vim.g.netrw_keepdir = 0
|
|
|
|
map("n", "<leader>E", "<cmd>Ex<cr>", { silent = true, desc = "Open netrw" })
|
|
|
|
vim.api.nvim_create_autocmd("VimEnter", {
|
|
callback = function()
|
|
if vim.fn.argc() == 0 then
|
|
vim.cmd("Explore")
|
|
end
|
|
end,
|
|
})
|
|
|
|
-- ============================================================================
|
|
-- Built-in package manager (nightly)
|
|
-- ============================================================================
|
|
|
|
-- Optional post-install hooks for plugins that usually need one-time setup.
|
|
vim.api.nvim_create_autocmd("PackChanged", {
|
|
callback = function(ev)
|
|
local data = ev.data or {}
|
|
local spec = data.spec or {}
|
|
local name = spec.name
|
|
local kind = data.kind
|
|
|
|
if kind ~= "install" and kind ~= "update" then
|
|
return
|
|
end
|
|
|
|
if name == "nvim-treesitter" then
|
|
vim.schedule(function()
|
|
pcall(vim.cmd.packadd, "nvim-treesitter")
|
|
pcall(function()
|
|
require("nvim-treesitter.install").update({ with_sync = true })()
|
|
end)
|
|
end)
|
|
end
|
|
|
|
if name == "markdown-preview.nvim" then
|
|
vim.schedule(function()
|
|
pcall(vim.cmd.packadd, "markdown-preview.nvim")
|
|
pcall(function()
|
|
vim.fn["mkdp#util#install"]()
|
|
end)
|
|
end)
|
|
end
|
|
end,
|
|
})
|
|
|
|
vim.pack.add({
|
|
|
|
{ src = "https://github.com/nvim-lua/plenary.nvim" },
|
|
{ src = "https://github.com/MunifTanjim/nui.nvim" },
|
|
{ src = "https://github.com/nvim-tree/nvim-web-devicons" },
|
|
|
|
-- Themes
|
|
{ src = "https://github.com/oskarnurm/koda.nvim" },
|
|
{ src = "https://github.com/vague-theme/vague.nvim" },
|
|
{ src = "https://github.com/nendix/zen.nvim" },
|
|
{ src = "https://github.com/rebelot/kanagawa.nvim" },
|
|
|
|
-- Editing / syntax / completion
|
|
{ src = "https://github.com/nvim-treesitter/nvim-treesitter" },
|
|
|
|
{ src = "https://github.com/saghen/blink.cmp" },
|
|
|
|
{ src = "https://github.com/L3MON4D3/LuaSnip" },
|
|
{ src = "https://github.com/rafamadriz/friendly-snippets" },
|
|
{ src = "https://gitlab.com/repetitivesin/madol.nvim" },
|
|
|
|
-- LSP configs (for vim.lsp.enable)
|
|
{ src = "https://github.com/neovim/nvim-lspconfig" },
|
|
|
|
-- Navigation / search
|
|
{ src = "https://github.com/ibhagwan/fzf-lua" },
|
|
{ src = "https://github.com/nvim-neo-tree/neo-tree.nvim" },
|
|
{ src = "https://github.com/folke/flash.nvim" },
|
|
{ src = "https://github.com/leath-dub/snipe.nvim" },
|
|
{ src = "https://github.com/folke/which-key.nvim" },
|
|
{ src = "https://github.com/mikavilpas/yazi.nvim" },
|
|
{ src = "https://github.com/christoomey/vim-tmux-navigator"},
|
|
|
|
-- Git
|
|
{ src = "https://github.com/tpope/vim-fugitive" },
|
|
{ src = "https://github.com/lewis6991/gitsigns.nvim" },
|
|
{ src = "https://github.com/kdheepak/lazygit.nvim" },
|
|
|
|
-- Text objects / editing
|
|
{ src = "https://github.com/kylechui/nvim-surround" },
|
|
{ src = "https://github.com/windwp/nvim-autopairs" },
|
|
{ src = "https://github.com/abecodes/tabout.nvim" },
|
|
|
|
-- UI
|
|
{ src = "https://github.com/nvim-lualine/lualine.nvim" },
|
|
{ src = "https://github.com/chentoast/marks.nvim" },
|
|
|
|
-- Writing / docs
|
|
{ src = "https://github.com/chomosuke/typst-preview.nvim" },
|
|
{ src = "https://github.com/iamcco/markdown-preview.nvim" },
|
|
{ src = "https://github.com/MeanderingProgrammer/render-markdown.nvim" },
|
|
|
|
-- AI
|
|
{ src = "https://github.com/nickjvandyke/opencode.nvim" },
|
|
{ src = "https://github.com/zbirenbaum/copilot.lua" },
|
|
|
|
}, { confirm = false, load = true })
|
|
|
|
-- ============================================================================
|
|
-- Plugin globals before setup
|
|
-- ============================================================================
|
|
|
|
vim.g.mkdp_auto_start = 0
|
|
vim.g.mkdp_auto_close = 1
|
|
vim.g.mkdp_filetypes = { "markdown" }
|
|
|
|
-- Let native LSP own LSP features; opencode still works for its own UI/actions.
|
|
vim.g.opencode_opts = {
|
|
lsp = {
|
|
enabled = false,
|
|
},
|
|
}
|
|
|
|
vim.o.autoread = true
|
|
|
|
-- ============================================================================
|
|
-- Themes
|
|
-- ============================================================================
|
|
|
|
require("koda").setup({})
|
|
require("vague").setup({})
|
|
require("kanagawa").setup({
|
|
compile = false,
|
|
background = {
|
|
dark = "wave",
|
|
light = "lotus",
|
|
},
|
|
})
|
|
require("zen").setup({})
|
|
|
|
vim.cmd.colorscheme("vague")
|
|
|
|
-- ============================================================================
|
|
-- which-key
|
|
-- ============================================================================
|
|
|
|
local wk = require("which-key")
|
|
wk.setup({ preset = "helix" })
|
|
|
|
wk.add({
|
|
{ "<leader>b", group = "buffer" },
|
|
{ "<leader>f", group = "find" },
|
|
{ "<leader>g", group = "git" },
|
|
{ "<leader>h", group = "hunks" },
|
|
{ "<leader>l", group = "lsp" },
|
|
{ "<leader>m", group = "marks" },
|
|
{ "<leader>o", group = "opencode" },
|
|
{ "<leader>t", group = "tree" },
|
|
{ "<leader>p", group = "preview" },
|
|
{ "<leader>u", group = "toggles" },
|
|
})
|
|
|
|
-- ============================================================================
|
|
-- vim-tmux-navigator
|
|
-- ============================================================================
|
|
|
|
map("n", "<C-h>", "<cmd>TmuxNavigateLeft<CR>", { silent = true })
|
|
map("n", "<C-j>", "<cmd>TmuxNavigateDown<CR>", { silent = true })
|
|
map("n", "<C-k>", "<cmd>TmuxNavigateUp<CR>", { silent = true })
|
|
map("n", "<C-l>", "<cmd>TmuxNavigateRight<CR>", { silent = true })
|
|
|
|
|
|
-- ============================================================================
|
|
-- Treesitter
|
|
-- ============================================================================
|
|
|
|
require("nvim-treesitter").setup({
|
|
ensure_installed = {
|
|
"bash",
|
|
"c",
|
|
"cpp",
|
|
"css",
|
|
"diff",
|
|
"html",
|
|
"javascript",
|
|
"json",
|
|
"json5",
|
|
"latex",
|
|
"lua",
|
|
"luadoc",
|
|
"markdown",
|
|
"markdown_inline",
|
|
"python",
|
|
"query",
|
|
"regex",
|
|
"rust",
|
|
"toml",
|
|
"tsx",
|
|
"typst",
|
|
"typescript",
|
|
"vim",
|
|
"vimdoc",
|
|
"yaml",
|
|
},
|
|
auto_install = true,
|
|
highlight = { enable = true },
|
|
indent = { enable = true },
|
|
})
|
|
|
|
-- ============================================================================
|
|
-- LuaSnip
|
|
-- ============================================================================
|
|
|
|
local ls = require("luasnip")
|
|
|
|
ls.config.setup({
|
|
history = true,
|
|
update_events = "TextChanged,TextChangedI",
|
|
delete_check_events = "TextChanged",
|
|
enable_autosnippets = true,
|
|
})
|
|
|
|
require("luasnip.loaders.from_vscode").lazy_load()
|
|
|
|
require("madol").setup({
|
|
rmarkdown = {
|
|
snippets = {
|
|
["greek-tex"] = true,
|
|
["greek-unicode"] = false
|
|
}
|
|
}
|
|
})
|
|
|
|
map({ "i", "s" }, "<C-j>", function()
|
|
if ls.choice_active() then
|
|
ls.change_choice(1)
|
|
end
|
|
end, { desc = "LuaSnip next choice" })
|
|
|
|
map({ "i", "s" }, "<C-k>", function()
|
|
if ls.choice_active() then
|
|
ls.change_choice(-1)
|
|
end
|
|
end, { desc = "LuaSnip previous choice" })
|
|
|
|
-- ============================================================================
|
|
-- blink.cmp
|
|
-- ============================================================================
|
|
|
|
require("blink.cmp").setup({
|
|
snippets = {
|
|
preset = "luasnip",
|
|
},
|
|
completion = {
|
|
menu = { auto_show = true },
|
|
ghost_text = { enabled = false },
|
|
documentation = {
|
|
auto_show = true,
|
|
auto_show_delay_ms = 200,
|
|
},
|
|
list = {
|
|
selection = {
|
|
preselect = true,
|
|
auto_insert = false,
|
|
},
|
|
},
|
|
},
|
|
keymap = {
|
|
preset = "none",
|
|
["<C-space>"] = { "show", "show_documentation", "hide_documentation" },
|
|
["<C-e>"] = { "hide" },
|
|
|
|
["<C-up>"] = { "scroll_documentation_up" },
|
|
["<C-down>"] = { "scroll_documentation_down" },
|
|
|
|
["<CR>"] = { "accept", "fallback" },
|
|
|
|
["<C-n>"] = { "select_next", "fallback" },
|
|
["<C-p>"] = { "select_prev", "fallback" },
|
|
|
|
["<C-l>"] = { "snippet_forward", "fallback" },
|
|
["<C-h>"] = { "snippet_backward", "fallback" },
|
|
|
|
|
|
},
|
|
sources = {
|
|
default = { "lsp", "path", "snippets", "buffer" },
|
|
},
|
|
fuzzy = {
|
|
implementation = "prefer_rust_with_warning",
|
|
prebuilt_binaries = {
|
|
force_version = "v1.9.1",
|
|
}
|
|
},
|
|
})
|
|
|
|
-- ============================================================================
|
|
-- Copilot
|
|
-- Included, but practically "off by default" because auto_trigger = false.
|
|
-- Toggle it on/off with <leader>uc.
|
|
-- ============================================================================
|
|
|
|
vim.api.nvim_create_autocmd("User", {
|
|
pattern = "BlinkCmpMenuOpen",
|
|
callback = function()
|
|
vim.b.copilot_suggestion_hidden = true
|
|
end,
|
|
})
|
|
|
|
vim.api.nvim_create_autocmd("User", {
|
|
pattern = "BlinkCmpMenuClose",
|
|
callback = function()
|
|
vim.b.copilot_suggestion_hidden = false
|
|
end,
|
|
})
|
|
|
|
require("copilot").setup({
|
|
panel = {
|
|
enabled = false,
|
|
},
|
|
suggestion = {
|
|
enabled = true,
|
|
auto_trigger = false,
|
|
hide_during_completion = true,
|
|
keymap = {
|
|
accept = "<M-l>",
|
|
next = "<M-]>",
|
|
prev = "<M-[>",
|
|
dismiss = "<C-]>",
|
|
toggle_auto_trigger = false,
|
|
},
|
|
},
|
|
})
|
|
|
|
map("n", "<leader>ac", function()
|
|
require("copilot.suggestion").toggle_auto_trigger()
|
|
end, { desc = "Toggle Copilot auto-trigger" })
|
|
|
|
map("n", "<leader>ap", function()
|
|
require("copilot.panel").toggle()
|
|
end, { desc = "Toggle Copilot panel" })
|
|
|
|
-- ============================================================================
|
|
-- autopairs / tabout / surround
|
|
-- ============================================================================
|
|
|
|
require("nvim-autopairs").setup({
|
|
check_ts = true,
|
|
})
|
|
|
|
require("tabout").setup({
|
|
tabkey = "<Tab>",
|
|
backwards_tabkey = "<S-Tab>",
|
|
act_as_tab = true,
|
|
act_as_shift_tab = true,
|
|
default_tab = "<C-t>",
|
|
default_shift_tab = "<C-d>",
|
|
enable_backwards = true,
|
|
completion = false,
|
|
ignore_beginning = true,
|
|
tabouts = {
|
|
{ open = "'", close = "'" },
|
|
{ open = '"', close = '"' },
|
|
{ open = "`", close = "`" },
|
|
{ open = "(", close = ")" },
|
|
{ open = "[", close = "]" },
|
|
{ open = "{", close = "}" },
|
|
{ open = "$", close = "$" },
|
|
},
|
|
})
|
|
|
|
require("nvim-surround").setup({})
|
|
|
|
-- ============================================================================
|
|
-- flash.nvim
|
|
-- ============================================================================
|
|
|
|
require("flash").setup({})
|
|
|
|
map({ "n", "x", "o" }, "s", function() require("flash").jump() end, { desc = "Flash" })
|
|
map({ "n", "x", "o" }, "S", function() require("flash").treesitter() end, { desc = "Flash Treesitter" })
|
|
map("o", "r", function() require("flash").remote() end, { desc = "Remote Flash" })
|
|
map({ "o", "x" }, "R", function() require("flash").treesitter_search() end, { desc = "Treesitter Search" })
|
|
map("c", "<C-s>", function() require("flash").toggle() end, { desc = "Toggle Flash Search" })
|
|
|
|
-- ============================================================================
|
|
-- marks.nvim
|
|
-- ============================================================================
|
|
|
|
require("marks").setup({
|
|
default_mappings = true,
|
|
builtin_marks = { ".", "<", ">", "^" },
|
|
cyclic = true,
|
|
force_write_shada = false,
|
|
refresh_interval = 250,
|
|
})
|
|
|
|
map("n", "<leader>mb", "<cmd>MarksListBuf<cr>", { silent = true, desc = "Marks in buffer" })
|
|
map("n", "<leader>ma", "<cmd>MarksListAll<cr>", { silent = true, desc = "All marks" })
|
|
|
|
-- ============================================================================
|
|
-- snipe.nvim
|
|
-- ============================================================================
|
|
|
|
require("snipe").setup({
|
|
ui = {
|
|
position = "center",
|
|
preselect_current = true,
|
|
text_align = "file-first",
|
|
},
|
|
hints = {
|
|
dictionary = "sadflewcmpghio",
|
|
},
|
|
navigate = {
|
|
cancel_snipe = "<Esc>",
|
|
close_buffer = "D",
|
|
open_vsplit = "V",
|
|
open_split = "H",
|
|
},
|
|
sort = "last",
|
|
})
|
|
|
|
map("n", "<leader><leader>", function() require("snipe").open_buffer_menu() end, { desc = "Snipe buffers" })
|
|
|
|
-- ============================================================================
|
|
-- Markdown / Typst
|
|
-- ============================================================================
|
|
|
|
require("render-markdown").setup({
|
|
file_types = { "markdown" },
|
|
render_modes = { "n", "c", "t" },
|
|
})
|
|
|
|
require("typst-preview").setup({
|
|
follow_cursor = true,
|
|
})
|
|
|
|
-- Typst
|
|
map("n", "<leader>ptp", "<cmd>TypstPreview<cr>", { silent = true, desc = "Typst preview" })
|
|
map("n", "<leader>ptP", "<cmd>TypstPreviewToggle<cr>", { silent = true, desc = "Toggle Typst preview" })
|
|
|
|
-- Markdown
|
|
map("n", "<leader>pmp", "<cmd>MarkdownPreview<cr>", { silent = true, desc = "Markdown preview" })
|
|
map("n", "<leader>pmr", "<cmd>RenderMarkdown toggle<cr>", { silent = true, desc = "Toggle render-markdown" })
|
|
|
|
-- ============================================================================
|
|
-- fzf-lua
|
|
-- ============================================================================
|
|
|
|
require("fzf-lua").setup({
|
|
actions = {
|
|
files = {
|
|
["enter"] = require("fzf-lua.actions").file_edit,
|
|
}
|
|
}
|
|
})
|
|
|
|
map("n", "<leader>ff", function() require("fzf-lua").files() end, { desc = "Files" })
|
|
map("n", "<leader>db", function() require("fzf-lua").buffers() end, { desc = "Buffers" })
|
|
map("n", "<leader>bl", function() require("fzf-lua").buffers() end, { desc = "List buffers" })
|
|
map("n", "<leader>ft", function() require("fzf-lua").live_grep() end, { desc = "Live grep" })
|
|
map("n", "<leader>fs", function() require("fzf-lua").lsp_document_symbols() end, { desc = "Document symbols" })
|
|
map("n", "<leader>/", function() require("fzf-lua").grep_curbuf() end, { desc = "Grep current buffer" })
|
|
map("n", "<leader>fh", function() require("fzf-lua").help_tags() end, { desc = "Help tags" })
|
|
|
|
-- useful extras
|
|
map("n", "<leader>fr", function() require("fzf-lua").oldfiles() end, { desc = "Recent files" })
|
|
map("n", "<leader>fg", function() require("fzf-lua").git_files() end, { desc = "Git files" })
|
|
map("n", "<leader>fc", function() require("fzf-lua").commands() end, { desc = "Commands" })
|
|
map("n", "<leader>fk", function() require("fzf-lua").keymaps() end, { desc = "Keymaps" })
|
|
map("n", "<leader>fd", function() require("fzf-lua").diagnostics_document() end, { desc = "Document diagnostics" })
|
|
map("n", "<leader>fD", function() require("fzf-lua").diagnostics_workspace() end, { desc = "Workspace diagnostics" })
|
|
map("n", "<leader>fw", function() require("fzf-lua").grep_cword() end, { desc = "Grep word under cursor" })
|
|
|
|
-- ============================================================================
|
|
-- neo-tree
|
|
-- netrw remains default; neo-tree is opt-in on <leader>n
|
|
-- ============================================================================
|
|
|
|
require("neo-tree").setup({
|
|
close_if_last_window = true,
|
|
enable_git_status = true,
|
|
enable_diagnostics = true,
|
|
filesystem = {
|
|
hijack_netrw_behavior = "disabled",
|
|
follow_current_file = { enabled = true },
|
|
use_libuv_file_watcher = true,
|
|
},
|
|
window = {
|
|
width = 80,
|
|
},
|
|
})
|
|
|
|
map("n", "<leader>e", "<cmd>Neotree position=right toggle<cr>", {
|
|
silent = true,
|
|
desc = "Neo-tree",
|
|
})
|
|
|
|
-- ============================================================================
|
|
-- Git
|
|
-- ============================================================================
|
|
|
|
require("gitsigns").setup({
|
|
signs = {
|
|
add = { text = "▎" },
|
|
change = { text = "▎" },
|
|
delete = { text = "" },
|
|
topdelete = { text = "" },
|
|
changedelete = { text = "▎" },
|
|
untracked = { text = "▎" },
|
|
},
|
|
on_attach = function(bufnr)
|
|
local gs = package.loaded.gitsigns
|
|
|
|
local function bufmap(mode, lhs, rhs, desc)
|
|
vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, desc = desc })
|
|
end
|
|
|
|
bufmap("n", "]h", gs.next_hunk, "Next hunk")
|
|
bufmap("n", "[h", gs.prev_hunk, "Prev hunk")
|
|
bufmap("n", "<leader>hs", gs.stage_hunk, "Stage hunk")
|
|
bufmap("n", "<leader>hr", gs.reset_hunk, "Reset hunk")
|
|
bufmap("n", "<leader>hS", gs.stage_buffer, "Stage buffer")
|
|
bufmap("n", "<leader>hR", gs.reset_buffer, "Reset buffer")
|
|
bufmap("n", "<leader>hp", gs.preview_hunk, "Preview hunk")
|
|
bufmap("n", "<leader>hb", function() gs.blame_line({ full = true }) end, "Blame line")
|
|
bufmap("n", "<leader>hd", gs.diffthis, "Diff this")
|
|
bufmap("n", "<leader>hQ", gs.setqflist, "Hunks to quickfix")
|
|
end,
|
|
})
|
|
|
|
map("n", "<leader>gg", "<cmd>LazyGit<cr>", { silent = true, desc = "LazyGit" })
|
|
map("n", "<leader>gs", "<cmd>Git<cr>", { silent = true, desc = "Git status" })
|
|
map("n", "<leader>gb", "<cmd>Git blame<cr>", { silent = true, desc = "Git blame" })
|
|
map("n", "<leader>gp", "<cmd>Git push<cr>", { silent = true, desc = "Git push" })
|
|
map("n", "<leader>gl", "<cmd>Git pull<cr>", { silent = true, desc = "Git pull" })
|
|
map("n", "<leader>gc", "<cmd>Git commit<cr>", { silent = true, desc = "Git commit" })
|
|
|
|
-- ============================================================================
|
|
-- opencode.nvim
|
|
-- ============================================================================
|
|
|
|
map({ "n", "x" }, "<leader>oa", function()
|
|
require("opencode").ask("@this: ", { submit = true })
|
|
end, { desc = "Ask opencode" })
|
|
|
|
map({ "n", "x" }, "<leader>os", function()
|
|
require("opencode").select()
|
|
end, { desc = "Select opencode action" })
|
|
|
|
map({ "n", "t" }, "<leader>oo", function()
|
|
require("opencode").toggle()
|
|
end, { desc = "Toggle opencode" })
|
|
|
|
map({ "n", "x" }, "<leader>or", function()
|
|
return require("opencode").operator("@this ")
|
|
end, { expr = true, desc = "Send range to opencode" })
|
|
|
|
map("n", "<leader>ol", function()
|
|
return require("opencode").operator("@this ") .. "_"
|
|
end, { expr = true, desc = "Send line to opencode" })
|
|
|
|
map("n", "<leader>ou", function()
|
|
require("opencode").command("session.half.page.up")
|
|
end, { desc = "Opencode scroll up" })
|
|
|
|
map("n", "<leader>od", function()
|
|
require("opencode").command("session.half.page.down")
|
|
end, { desc = "Opencode scroll down" })
|
|
|
|
-- ============================================================================
|
|
-- LSP (native nightly flow)
|
|
-- No Mason. Install server binaries yourself and keep them on PATH.
|
|
-- ============================================================================
|
|
|
|
local capabilities = require("blink.cmp").get_lsp_capabilities()
|
|
|
|
vim.diagnostic.config({
|
|
underline = true,
|
|
severity_sort = true,
|
|
update_in_insert = false,
|
|
virtual_text = {
|
|
spacing = 2,
|
|
source = "if_many",
|
|
},
|
|
float = {
|
|
border = "rounded",
|
|
source = "if_many",
|
|
},
|
|
})
|
|
|
|
-- Global defaults for all enabled servers
|
|
vim.lsp.config("*", {
|
|
capabilities = capabilities,
|
|
root_markers = { ".git" },
|
|
})
|
|
|
|
-- Per-server overrides
|
|
vim.lsp.config("lua_ls", {
|
|
settings = {
|
|
Lua = {
|
|
diagnostics = {
|
|
globals = { "vim" },
|
|
},
|
|
workspace = {
|
|
checkThirdParty = false,
|
|
},
|
|
telemetry = {
|
|
enable = false,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
-- Adjust this list to the servers you actually have installed.
|
|
local servers = {
|
|
"gopls",
|
|
"lua_ls",
|
|
"tinymist",
|
|
"marksman",
|
|
"pyright",
|
|
}
|
|
|
|
for _, server in ipairs(servers) do
|
|
vim.lsp.enable(server)
|
|
end
|
|
|
|
vim.api.nvim_create_autocmd("LspAttach", {
|
|
callback = function(ev)
|
|
local bufnr = ev.buf
|
|
|
|
local function lmap(lhs, rhs, desc, mode)
|
|
vim.keymap.set(mode or "n", lhs, rhs, { buffer = bufnr, silent = true, desc = desc })
|
|
end
|
|
|
|
lmap("gd", vim.lsp.buf.definition, "Goto definition")
|
|
lmap("gD", vim.lsp.buf.declaration, "Goto declaration")
|
|
lmap("gi", vim.lsp.buf.implementation, "Goto implementation")
|
|
lmap("gt", vim.lsp.buf.type_definition, "Goto type definition")
|
|
lmap("gr", function() require("fzf-lua").lsp_references() end, "References")
|
|
lmap("K", vim.lsp.buf.hover, "Hover")
|
|
lmap("gK", vim.lsp.buf.signature_help, "Signature help")
|
|
|
|
lmap("<leader>la", vim.lsp.buf.code_action, "Code action", { "n", "x" })
|
|
lmap("<leader>lr", vim.lsp.buf.rename, "Rename")
|
|
lmap("<leader>lf", function() vim.lsp.buf.format({ async = true }) end, "Format")
|
|
lmap("<leader>ld", vim.diagnostic.open_float, "Line diagnostics")
|
|
lmap("<leader>ls", function() require("fzf-lua").lsp_document_symbols() end, "Document symbols")
|
|
lmap("<leader>lS", function() require("fzf-lua").lsp_live_workspace_symbols() end, "Workspace symbols")
|
|
|
|
lmap("[d", function() vim.diagnostic.jump({ count = -1, float = true }) end, "Prev diagnostic")
|
|
lmap("]d", function() vim.diagnostic.jump({ count = 1, float = true }) end, "Next diagnostic")
|
|
end,
|
|
})
|
|
|
|
-- ============================================================================
|
|
-- lualine
|
|
-- ============================================================================
|
|
|
|
local function opencode_statusline()
|
|
local ok, opencode = pcall(require, "opencode")
|
|
if ok and opencode.statusline then
|
|
return opencode.statusline()
|
|
end
|
|
return ""
|
|
end
|
|
|
|
require("lualine").setup({
|
|
options = {
|
|
section_separators = "",
|
|
component_separators = "",
|
|
globalstatus = true,
|
|
theme = "auto",
|
|
},
|
|
|
|
sections = {
|
|
lualine_a = { "mode" },
|
|
lualine_b = { { "branch", icon = "" }, "diff" },
|
|
lualine_c = {
|
|
{ "diagnostics" },
|
|
{ "filename", path = 1, symbols = { modified = " ●", readonly = " " } },
|
|
},
|
|
lualine_x = { "encoding", "fileformat", "filetype", opencode_statusline },
|
|
lualine_y = { "progress" },
|
|
lualine_z = { "location" },
|
|
},
|
|
})
|