Files
dotfiles/machines/desktop/config/nvim/init.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" },
},
})