--local vim = require("vim") -- https://github.com/neovim/neovim/issues/23725#issuecomment-1561364086 local ok, wf = pcall(require, "vim.lsp._watchfiles") if ok then -- disable lsp watcher. Too slow on linux wf._watchfunc = function() return function() end end end --local rt = require("rust-tools") local lint = require('lint') local lspconfig = require('lspconfig') tb = require("telescope.builtin") require('telescope').setup({ defaults = { sorting_strategy = "ascending", }, extensions = { file_browser = { hijack_netrw = true, }, }, }) require("telescope").load_extension("file_browser") require("telescope").load_extension("frecency") require('telescope').load_extension('fzy_native') require("telescope.pickers.layout_strategies").buffer_window = function(self) local layout = require("telescope.pickers.window").get_initial_window_options(self) local prompt = layout.prompt local results = layout.results local preview = layout.preview local config = self.layout_config local padding = self.window.border and 2 or 0 local width = vim.api.nvim_win_get_width(self.original_win_id) local height = vim.api.nvim_win_get_height(self.original_win_id) local pos = vim.api.nvim_win_get_position(self.original_win_id) local wline = pos[1] + 1 local wcol = pos[2] + 1 -- Height prompt.height = 1 preview.height = self.previewer and math.floor(height * 0.4) or 0 results.height = height - padding - (prompt.height + padding) - (self.previewer and (preview.height + padding) or 0) -- Line local rows = {} local mirror = config.mirror == true local top_prompt = config.prompt_position == "top" if mirror and top_prompt then rows = { prompt, results, preview } elseif mirror and not top_prompt then rows = { results, prompt, preview } elseif not mirror and top_prompt then rows = { preview, prompt, results } elseif not mirror and not top_prompt then rows = { preview, results, prompt } end local next_line = wline + padding / 2 for k, v in pairs(rows) do if v.height ~= 0 then v.line = next_line next_line = v.line + padding + v.height end end -- Width prompt.width = width - padding results.width = prompt.width preview.width = prompt.width -- Col prompt.col = wcol + padding / 2 results.col = prompt.col preview.col = prompt.col if not self.previewer then layout.preview = nil end return layout end require("nvim-treesitter.configs").setup { auto_install = false, highlight = { enable = true, disable = function(lang, buf) local max_filesize = 100 * 1024 * 1024 -- 100 MB local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf)) if ok and stats and stats.size > max_filesize then return true end end, }, indent = { enable = true } } -- completion local cmp = require('cmp') -- Global setup. cmp.setup({ snippet = { expand = function(args) end, }, window = { -- completion = cmp.config.window.bordered(), -- documentation = cmp.config.window.bordered(), }, mapping = cmp.mapping.preset.insert({ [''] = cmp.mapping.scroll_docs(-4), [''] = cmp.mapping.scroll_docs(4), [''] = cmp.mapping.complete(), [''] = cmp.mapping.confirm({ select = true }), }), sources = cmp.config.sources({ { name = 'nvim_lsp' }, --{ name = 'vsnip' }, -- For vsnip users. -- { name = 'luasnip' }, -- For luasnip users. -- { name = 'snippy' }, -- For snippy users. -- { name = 'ultisnips' }, -- For ultisnips users. }, { { name = 'buffer' }, }), completion = { autocomplete = false, keyword_length = 1, }, }) -- Setup lspconfig. --local capabilities = require('cmp_nvim_lsp').default_capabilities() local lsp_status = require('lsp-status') local function nilfunc() return nil end --capabilities = vim.tbl_extend('keep', capabilities, lsp_status.capabilities) _last_picker = nil _last_ctx = nil -- NOTE: this is currently unused because it so sucks. use gr instead! local function telescope_middleware(func, ctxfunc) local function inner() if ctxfunc == nil then ctx = nil else ctx = ctxfunc() end if func == _last_picker and vim.deep_equal(ctx, _last_ctx) then tb.resume() else _last_picker = func _last_ctx = ctx func() end end return inner end local function tokenctx() cursor0 = vim.api.nvim_win_get_cursor(0) vim.cmd.normal("lb") cursor = vim.api.nvim_win_get_cursor(0) word = vim.call('expand','') vim.api.nvim_win_set_cursor(0, cursor0) return {cursor, word} end local function lsp_keybinds(client, bufnr) local bufopts = { noremap=true, silent=true, buffer=bufnr } vim.keymap.set("n", "gd", tb.lsp_definitions, bufopts) vim.keymap.set("n", "gD", tb.lsp_implementations, bufopts) vim.keymap.set("n", "gt", tb.lsp_type_definitions, bufopts) vim.keymap.set("n", "K", vim.lsp.buf.hover, bufopts) vim.keymap.set('n', 'gu', tb.lsp_references, bufopts) -- "usages" vim.keymap.set('n', 'ge', telescope_line_diagnostics, bufopts) -- "errors" vim.keymap.set('n', 'gE', function() tb.diagnostics({ severity_limit=vim.diagnostic.severity.WARN }) end, bufopts) -- "errors" vim.keymap.set('n', 'gaE', tb.diagnostics, bufopts) -- "errors" --vim.api.nvim_command('inoremap ') --vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') vim.keymap.set('i', '', vim.lsp.buf.completion, bufopts) vim.keymap.set('i', '', vim.lsp.buf.code_action, bufopts) vim.keymap.set('n', '', vim.lsp.buf.code_action, bufopts) lsp_status.on_attach(client) end vim.keymap.set('n', '[e', function() vim.diagnostic.goto_prev{float=false, severity={min=vim.diagnostic.severity.WARN}} end, nil) vim.keymap.set('n', ']e', function() vim.diagnostic.goto_next{float=false, severity={min=vim.diagnostic.severity.WARN}} end, nil) vim.keymap.set('n', 'gf', tb.live_grep, nil) vim.keymap.set('n', 'gn', tb.find_files, nil) vim.keymap.set('n', 'gb', tb.buffers, nil) vim.keymap.set('n', 'gr', tb.resume, nil) local pickers = require("telescope.pickers") local finders = require("telescope.finders") local previewers = require("telescope.previewers") local conf = require("telescope.config").values local actions = require("telescope.actions") local action_state = require("telescope.actions.state") local make_entry = require("telescope.make_entry") lsp_status.config { indicator_errors = 'E', indicator_warnings = 'W', indicator_info = 'i', indicator_hint = '?', indicator_ok = 'Ok', diagnostics = false, } lsp_status.register_progress() function telescope_line_diagnostics(opts) opts = opts or {} local diags = vim.diagnostic.get(0, { lnum = opts.lnum or vim.api.nvim_win_get_cursor(0)[1] - 1, severity = {min = opts.severity_limit or vim.diagnostic.severity.HINT}, }) if diags[1] == nil then print("No issues under cursor") return end if diags[2] == nil then show_full_diagnostic(diags[1]) return end pickers.new(opts, { prompt_title = "Line Issues", finder = finders.new_table { results = diags, entry_maker = function(diag) return make_entry.set_default_entry_mt({ value = diag, text = diag.message, display = diag.message:gsub("\n", " - "), ordinal = diag.message, }, opts) end }, sorter = conf.generic_sorter(opts), previewer = previewers.new_buffer_previewer { define_preview = function(self, entry, status) local text = vim.split(render_full_diagnostic_and_debug(entry.value), '\n') vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, true, text) end }, attach_mappings = function(prompt_bufnr, map) actions.select_default:replace(function() actions.close(prompt_bufnr) local entry = action_state.get_selected_entry() show_full_diagnostic(entry.value) end) return true end, }):find() end function render_full_diagnostic(diag) if diag.user_data and diag.user_data.lsp and diag.user_data.lsp.data and diag.user_data.lsp.data.rendered then return diag.user_data.lsp.data.rendered end if diag.message then return diag.message end error("Bad diagnostic value") end function render_full_diagnostic_and_debug(diag) return render_full_diagnostic(diag) .. '\n\n' .. vim.inspect(diag) end function show_full_diagnostic(diag) local buf = nil; local win = nil; for _, win2 in ipairs(vim.api.nvim_tabpage_list_wins(0)) do if string.match(vim.api.nvim_buf_get_name(vim.api.nvim_win_get_buf(win2)), "$") then win = win2 buf = vim.api.nvim_win_get_buf(win) vim.api.nvim_set_current_win(win) break end end if buf == nil then vim.cmd('bel split') win = vim.api.nvim_get_current_win() buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_win_set_buf(win, buf) vim.api.nvim_buf_set_option(buf, "bufhidden", "delete") vim.api.nvim_buf_set_name(buf, "") end local text = vim.split(render_full_diagnostic_and_debug(diag), '\n') vim.api.nvim_buf_set_lines(buf, 0, -1, true, text) vim.api.nvim_win_set_cursor(win, { 1, 0 }) end function show_preview_diagnostic(diag) local width = vim.api.nvim_get_option('columns') - 15 local lines = vim.split(diag.message, "\n") local message = lines[1] if #lines > 1 and #message <= 20 then message = message .. ' ' .. lines[2] end --while true do -- local m = message:match("^[Ee]rror") -- if m == nil then m = message:match("^[Ww]arning") end -- if m == nil then m = message:match("^%d+:") end -- if m == nil then m = message:match("^[: ]+") end -- if m == nil then -- break -- else -- message = message.sub(#m + 1, #message) -- end --end if width > 0 and #message >= width then message = message:sub(1, width) .. '...' end vim.api.nvim_echo({{message}}, false, {}) end rust_root_dir = function(fname) local primary = lspconfig.util.root_pattern('rust-toolchain')(fname) local fallback = lspconfig.util.root_pattern('Cargo.toml')(fname) return primary or fallback end local pipe = io.popen('rustup which rust-analyzer --toolchain nightly 2>/dev/null') local rust_analyzer = pipe:read() if rust_analyzer == nil then pipe = io.popen('which rust-analyzer 2>/dev/null') rust_analyzer = pipe:read() end pipe = io.popen('which clangd') clangd = pipe:read() if clangd == nil then pipe = io.popen('which clangd15') clangd = pipe:read() end pipe = io.popen('which bash-language-server') bashls = pipe:read() pipe = io.popen('which pyright-langserver') pyright = pipe:read() pipe.close() if rust_analyzer ~= nil then --rt.setup({ -- server = { -- on_attach = lsp_keybinds, -- capabilities = capabilities, -- root_dir = rust_root_dir, -- cmd = {rust_analyzer}, -- }, --}) lspconfig.rust_analyzer.setup{ on_attach = lsp_keybinds, capabilities = capabilities, settings = { ["rust-analyzer"] = { diagnostics = { enable = true, }, }, }, } end if pyright ~= nil then lspconfig.pyright.setup{ on_attach = lsp_keybinds, capabilities = capabilities, cmd = {pyright, '--stdio'}, settings = { python = { analysis = { autoSearchPaths = false, diagnosticMode = "openFilesOnly", useLibraryCodeForTypes = false, }, }, }, } end if clangd ~= nil then lspconfig.clangd.setup{ on_attach = lsp_keybinds, capabilities = capabilities, cmd = {clangd, "--limit-references=1000000" }, handlers = lsp_status.extensions.clangd.setup(), init_options = { clangdFileStatus = true }, single_file_support = false, } end lspconfig.nil_ls.setup{ on_attach = lsp_keybinds, capabilities = capabilities, } lspconfig.csharp_ls.setup{ on_attach = lsp_keybinds, capabilities = capabilities, } if bashls ~= nil then lspconfig.bashls.setup{ on_attach = lsp_keybinds, capabilities = capabilities, cmd = {bashls, "start" }, } end lspconfig.gopls.setup{ on_attach = lsp_keybinds, capabilities = capabilities, } lspconfig.ts_ls.setup{ on_attach = lsp_keybinds, capabilities = capabilities, } lspconfig.lua_ls.setup{ on_attach = lsp_keybinds, capabilities = capabilities, settings = { Lua = { workspace = { library = {"/home/audrey/loenn_stubs.lua"}, }, }, }, } --lspconfig.ocamllsp.setup{ -- on_attach = lsp_keybinds, -- capabilities = capabilities, --} --vim.api.nvim_create_autocmd({ "BufWritePost", "BufReadPost" }, { -- callback = function() -- lint.try_lint() -- end --}) --lint.linters_by_ft = { -- python = {'ruff'}, -- rust = {}, --} -- LSP Diagnostics Options Setup local sign = function(opts) vim.fn.sign_define(opts.name, { texthl = opts.name, text = opts.text, numhl = '' }) end sign({name = 'DiagnosticSignError', text = '!'}) sign({name = 'DiagnosticSignWarn', text = '-'}) --sign({name = 'DiagnosticSignHint', text = '.'}) --sign({name = 'DiagnosticSignInfo', text = '+'}) vim.diagnostic.config({ virtual_text = false, signs = { severity = {min = vim.diagnostic.severity.WARN}, }, update_in_insert = true, underline = true, severity_sort = true, float = { border = 'rounded', source = 'always', header = '', prefix = '', }, }) vim.api.nvim_create_autocmd({ 'DiagnosticChanged' }, { callback = function(args) local diags = args.data.diagnostics for _, diag in pairs(diags) do if diag.severity == vim.diagnostic.severity.ERROR then show_preview_diagnostic(diag) return end end vim.api.nvim_echo({{''}}, false, {}) end, }) vim.api.nvim_create_autocmd({ 'CursorMoved' }, { callback = function() local diags = vim.diagnostic.get(0, { lnum = vim.api.nvim_win_get_cursor(0)[1] - 1, severity = {min = vim.diagnostic.severity.WARN}, }) for _, diag in pairs(diags) do show_preview_diagnostic(diag) break end end }) vim.api.nvim_create_user_command('Fmt', function() vim.lsp.buf.format({}) end, {}) show = function(x) vim.notify(vim.inspect(x)) end --vim.g.sweetie = { -- palette = { -- dark = { -- bg = "NONE", -- bg_alt = "#151523", -- bg_hl = "#505040", -- } -- }, -- overrides = { -- StatusLineNC = { fg = "#eeffee", bg = "#151523" }, -- StatusLine = {fg = "#ffffff", bg = "#151523", bold = true }, -- MatchParen = { fg = '#ae920a', reverse = false }, -- Search = { fg = '#ae920a', bg = "#0b658e" }, -- } --} require("tokyonight").setup { style = "night", transparent = true, } if vim.env.TERM == "tmux" or vim.env.TERM == "xterm" then vim.cmd.colorscheme("default") else vim.cmd.colorscheme("tokyonight") end local tabtheme = { fill = 'TabLineFill', -- Also you can do this: fill = { fg='#f2e9de', bg='#907aa9', style='italic' } head = 'TabLine', current_tab = 'TabLineSel', tab = 'TabLine', win = 'TabLine', tail = 'TabLine', } require('tabby').setup({ line = function(line) return { { { '  ', hl = tabtheme.head }, line.sep('', tabtheme.head, tabtheme.fill), }, line.tabs().foreach(function(tab) local hl = tab.is_current() and tabtheme.current_tab or tabtheme.tab local name = tab.name() if vim.t[tab.id].zoomed ~= nil then name = "[zoom] " .. name end return { line.sep('', hl, tabtheme.fill), tab.is_current() and '' or '󰆣', tab.number(), name, --tab.close_btn(''), line.sep('', hl, tabtheme.fill), hl = hl, margin = ' ', } end), --line.spacer(), --line.wins_in_tab(line.api.get_current_tab()).foreach(function(win) -- return { -- line.sep('', tabtheme.win, tabtheme.fill), -- win.is_current() and '' or '', -- win.buf_name(), -- line.sep('', tabtheme.win, tabtheme.fill), -- hl = tabtheme.win, -- margin = ' ', -- } --end), --{ -- line.sep('', tabtheme.tail, tabtheme.fill), -- { '  ', hl = tabtheme.tail }, --}, hl = tabtheme.fill, } end, -- option = {}, -- setup modules' option, }) local splashPicker = pickers.new({layout_strategy="buffer_window", initial_mode="normal"}, { prompt_title = "New Tab", finder = finders.new_table { results = { { title = "Terminal", ordinal = "0", callback = function() vim.cmd(":term") vim.cmd('startinsert') end, }, { title = "Recent Files", ordinal = "1", callback = function() vim.cmd(":Telescope frecency") end, }, { title = "File Browser (flat)", ordinal = "2", callback = function() vim.cmd(":Telescope find_files") end, }, { title = "File Browser (grep)", ordinal = "3", callback = function() vim.cmd(":Telescope live_grep") end, }, { title = "File Browser (hierarchy)", ordinal = "4", callback = function() vim.cmd(":e .") end, }, { title = "Change Workspace", ordinal = "5", callback = function() tb.find_files({find_command = {"fd", "--type", "d", "--no-ignore-vcs", ".", "/home/audrey"}, attach_mappings = function(prompt_bufnr, map) actions.select_default:replace(function() actions.close(prompt_bufnr) local selection = action_state.get_selected_entry() vim.defer_fn(function() -- uhhhhhh doesn't work. isn't there an api function which will put you in some other buffer's context? vim.cmd.lcd(selection[0]) splash() end, 1) end) return true end}) end, }, { title = "Scratch File", ordinal = "6", callback = function() vim.cmd(":enew") end, }, }, entry_maker = function(entry) return make_entry.set_default_entry_mt({ value = entry, text = entry.title, display = entry.title, ordinal = entry.ordinal, }, {}) end, }, sorter = conf.generic_sorter({}), attach_mappings = function(prompt_bufnr, map) actions.select_default:replace(function() actions.close(prompt_bufnr) local entry = action_state.get_selected_entry() entry.value.callback() end) return true end, }) splash = function() splashPicker:find() end newsplash = function(pwd) local wins = vim.api.nvim_tabpage_list_wins(0) if #wins ~= 1 or vim.api.nvim_buf_get_name(vim.api.nvim_win_get_buf(wins[1])) ~= "" then vim.cmd(":tabnew") end vim.defer_fn(function() if pwd ~= nil then vim.cmd.lcd(pwd) end splash() end, 1) end newfiles = function(pwd, files) local wins = vim.api.nvim_tabpage_list_wins(0) if #wins ~= 1 or vim.api.nvim_buf_get_name(vim.api.nvim_win_get_buf(wins[1])) ~= "" then vim.cmd(":tabnew") end vim.defer_fn(function() if pwd ~= nil then vim.cmd.lcd(pwd) end vim.cmd.arglocal(files) end, 1) end vim.opt.splitbelow = true; vim.opt.splitright = true; if vim.env.TERM ~= "tmux" and vim.env.TERM ~= "tmux-256color" then --require("flatten").setup({ --}) vim.opt.guicursor = "n-v-sm:block,i-ci-ve-c-t:ver25,r-cr-o:hor20" -- NONSENSE local opts = { noremap = true, } vim.keymap.set({'i', 'n', 't'}, '', "", opts) vim.keymap.set({'i', 'n', 't'}, 'n', function() if vim.t.zoomed == nil then vim.cmd(":tabnext") else vim.cmd(":tabclose") end end, opts) vim.keymap.set({'i', 'n', 't'}, 'p', function() if vim.t.zoomed == nil then vim.cmd(":tabNext") else vim.cmd(":tabclose") end end, opts) vim.keymap.set({'i', 'n', 't'}, 'c', function() if vim.t.zoomed == nil then vim.cmd(":tabnew") vim.defer_fn(splash, 1) else vim.cmd(":tabclose") end end, opts) vim.keymap.set({'i', 'n', 't'}, '"', function() if vim.t.zoomed == nil then vim.cmd(":split") vim.defer_fn(splash, 1) else vim.cmd(":tabclose") end end, opts) vim.keymap.set({'i', 'n', 't'}, '%', function() if vim.t.zoomed == nil then vim.cmd(":vsplit") vim.defer_fn(splash, 1) else vim.cmd(":tabclose") end end, opts) vim.keymap.set({'i', 'n', 't'}, 'z', function() if vim.t.zoomed == nil then local buf = vim.api.nvim_get_current_buf() local win = vim.api.nvim_get_current_win() vim.cmd(":tabnew") vim.api.nvim_win_set_buf(0, buf) vim.t.zoomed = win else local win = vim.t.zoomed vim.cmd(":tabclose") vim.api.nvim_set_current_win(win) end end, opts) vim.keymap.set({'i', 'n', 't'}, '[', '', opts) vim.keymap.set({'i', 'n', 't'}, '', '', opts) --vim.keymap.set({'i', 'n', 't'}, ']', function() vim.api.nvim_paste() end , opts) -- https://neovim.io/doc/user/terminal.html#terminal-osc7 vim.api.nvim_create_autocmd({ 'TermRequest' }, { desc = 'Handles OSC 7 dir change requests', callback = function(ev) if string.sub(ev.data.sequence, 1, 4) == '\x1b]7;' then local dir = string.gsub(ev.data.sequence, '\x1b]7;file://[^/]*', '') if vim.fn.isdirectory(dir) == 0 then --vim.notify('invalid dir: '..dir) return end --vim.api.nvim_buf_set_var(ev.buf, 'osc7_dir', dir) --if vim.o.autochdir and vim.api.nvim_get_current_buf() == ev.buf then vim.cmd.lcd(dir) --end end end }) if vim.env.IN_VIM == nil then vim.env.IN_VIM = "1" --if vim.fn.argv()[1] == nil then -- vim.defer_fn(splash, 1) --end end end