diff --git a/.stylua.toml b/.stylua.toml index 81b31e4..a4f1507 100644 --- a/.stylua.toml +++ b/.stylua.toml @@ -1,4 +1,2 @@ -indent_type = "Spaces" # Use spaces instead of tabs -indent_width = 2 # Number of spaces per indent level -quote_style = "ForceDouble" # Always use double quotes for strings -call_parentheses = "Always" +# I don't like stylua formatting in my config +ignore = [ "./" ] diff --git a/after/ftplugin/java.lua b/after/ftplugin/java.lua index 9401ec1..31c9ee6 100644 --- a/after/ftplugin/java.lua +++ b/after/ftplugin/java.lua @@ -5,8 +5,7 @@ local map, auto = core.misc.map, core.misc.auto local ok, jdtls = pcall(require, "jdtls") if not ok then - vim.notify("jdtls not loaded, can't setup jdtls lsp or dap", - vim.log.levels.INFO, {}) + vim.notify("jdtls not loaded, can't setup jdtls lsp or dap") return end @@ -68,8 +67,7 @@ local config = { -- setup nvim-dap local ok, dap = pcall(require, "dap") if not ok then - vim.notify("dap not loaded can't setup dap for jdtls", - vim.log.levels.INFO, {}) + vim.notify("dap not loaded can't setup dap for jdtls") return end @@ -146,20 +144,17 @@ local function version_check() if out.code ~= 0 then vim.notify(string.format( "java version check failed: exit code %s", out.code), - vim.log.levels.ERROR, { title = core.misc.appid }) + vim.log.levels.ERROR) vim.notify(string.format( - "%s", vim.inspect(out.stdout)), - vim.log.levels.ERROR, { title = core.misc.appid }) + "%s", vim.inspect(out.stdout)), vim.log.levels.ERROR) return false elseif not v then - vim.notify("no java version info found", vim.log.levels.ERROR, - { title = core.misc.appid }) + vim.notify("no java version info found", vim.log.levels.ERROR) return false elseif v.major < 21 then vim.notify(string.format( "java version %s < 21.0.0 Cannot run jdtls, bailing out", - v[1].."."..v[2].."."..v[3]), - vim.log.levels.ERROR, { title = core.misc.appid }) + v[1].."."..v[2].."."..v[3]), vim.log.levels.ERROR) return false end diff --git a/after/ftplugin/netrw.lua b/after/ftplugin/netrw.lua index d81ef0f..3f29c3b 100644 --- a/after/ftplugin/netrw.lua +++ b/after/ftplugin/netrw.lua @@ -15,6 +15,5 @@ end) -- change neovim root map_local("n", "rt", function() vim.api.nvim_set_current_dir(vim.b.netrw_curdir) - vim.notify("root dir updated: "..vim.b.netrw_curdir, vim.log.levels.LOW, - { title = core.misc.appid }) + vim.notify("root dir updated: "..vim.b.netrw_curdir) end) diff --git a/lua/conf/autos.lua b/lua/conf/autos.lua index c1f97e7..ceb669c 100644 --- a/lua/conf/autos.lua +++ b/lua/conf/autos.lua @@ -47,3 +47,5 @@ auto("BufWritePre", { vim.fn.mkdir(dir, "p") end }) + +core.color.setup_termbg_sync() diff --git a/lua/conf/binds.lua b/lua/conf/binds.lua index ca7990f..f83509d 100644 --- a/lua/conf/binds.lua +++ b/lua/conf/binds.lua @@ -23,22 +23,16 @@ map("n", "x", function() -- execute order 111 if vim.fn.getftype(fn) == "file" then local perm = vim.fn.getfperm(fn) if string.match(perm, "x", 3) then - vim.notify("Removed executable flags", vim.log.levels.INFO, { - title = core.misc.appid - }) + vim.notify("Removed executable flags") vim.fn.setfperm(fn, string.sub(fn, 1, 2).."-"..string.sub(fn, 4, 5).."-" ..string.sub(fn, 7, 8).."-") else - vim.notify("Add executable flags", vim.log.levels.INFO, { - title = core.misc.appid - }) + vim.notify("Add executable flags") vim.fn.setfperm(fn, string.sub(fn, 1, 2).."x"..string.sub(fn, 4, 5).."x" ..string.sub(fn, 7, 8).."x") end else - vim.notify("File doesn't exist", vim.log.levels.INFO, { - title = core.misc.appid - }) + vim.notify("File doesn't exist") end end, { desc = "toggle executable flag of the file" }) diff --git a/lua/conf/plugins/dap-python.lua b/lua/conf/plugins/dap-python.lua new file mode 100644 index 0000000..673b311 --- /dev/null +++ b/lua/conf/plugins/dap-python.lua @@ -0,0 +1,7 @@ +return { "mfussenegger/nvim-dap-python", + requires = "mfussenegger/nvim-dap", + function() + local debugpy = core.mason.get_pkg_path("debugpy", "/venv/bin/python3") + require("dap-python").setup(debugpy) + end +} diff --git a/lua/conf/plugins/harpoon.lua b/lua/conf/plugins/harpoon.lua index 06a00ff..4cb1d57 100644 --- a/lua/conf/plugins/harpoon.lua +++ b/lua/conf/plugins/harpoon.lua @@ -15,8 +15,7 @@ return { "ThePrimeagen/harpoon", map("n", "a", function() harpoon:list():add() - vim.notify("added "..vim.fn.expand("%:t").." to quickmarks", - vim.log.levels.INFO, { title = core.misc.appid }) + vim.notify("added "..vim.fn.expand("%:t").." to quickmarks") end, { desc = "add current file to quickmarks" }) map("n", "", function() harpoon.ui:toggle_quick_menu(harpoon:list()) end) diff --git a/lua/conf/plugins/lspconfig.lua b/lua/conf/plugins/lspconfig.lua index f2a3250..a4a3743 100644 --- a/lua/conf/plugins/lspconfig.lua +++ b/lua/conf/plugins/lspconfig.lua @@ -9,8 +9,19 @@ return { "neovim/nvim-lspconfig", require("mason-lspconfig").setup { ensure_added = { "clangd", + "mesonlsp", + + "bashls", + "jdtls", + "lua_ls", - "jdtls" + "stylua", + + -- python + "basedpyright", + "mypy", + "black", + "debugpy" } } end diff --git a/lua/conf/plugins/mellow.lua b/lua/conf/plugins/mellow.lua index a590cf9..0ebaa68 100644 --- a/lua/conf/plugins/mellow.lua +++ b/lua/conf/plugins/mellow.lua @@ -23,7 +23,17 @@ return { "mellow-theme/mellow.nvim", ["BlinkCmpMenu"] = { link = "NormalFloat" }, ["BlinkCmpMenuBorder"] = { link = "BlinkCmpMenu" }, ["BlinkCmpMenuSelection"] = { bg = c.gray01 }, - ["BlinkCmpLabelDeprecated"] = { link = "CmpItemAbbrDeprecated" } + ["BlinkCmpLabelDeprecated"] = { link = "CmpItemAbbrDeprecated" }, + + -- telescope styling so I can see when coding outside (real) + ["TelescopeResultsNormal"] = { bg = c.bg_dark }, + ["TelescopeResultsBorder"] = { link = "TelescopeResultsNormal" }, + ["TelescopeResultsTitle"] = { + bg = core.color.copyhl("TelescopeResultsNormal").background, + fg = core.color.copyhl("TelescopeResultsNormal").background + }, + ["TelescopePreviewNormal"] = { link = "NormalFloat" }, + ["TelescopePreviewBorder"] = { link = "TelescopePreviewNormal" } } end } diff --git a/lua/conf/plugins/nonels.lua b/lua/conf/plugins/nonels.lua new file mode 100644 index 0000000..263ba7e --- /dev/null +++ b/lua/conf/plugins/nonels.lua @@ -0,0 +1,31 @@ +local augroup = core.misc.augroup("nullls formatting") + +return { "nvimtools/none-ls.nvim", + function() + local null_ls = require("null-ls") + + null_ls.setup { + sources = { + null_ls.builtins.formatting.stylua, + null_ls.builtins.formatting.black, + null_ls.builtins.diagnostics.mypy + }, + + on_attach = function(client, bufnr) + if client.supports_method("textDocument/formatting") then + vim.api.nvim_clear_autocmds({ + group = augroup, + buffer = bufnr + }) + core.misc.auto("BufWritePre", { + group = augroup, + buffer = bufnr, + callback = function() + vim.lsp.buf.format({ bufnr = bufnr }) + end + }) + end + end + } + end +} diff --git a/lua/core/color.lua b/lua/core/color.lua index c4525f5..5d846ce 100644 --- a/lua/core/color.lua +++ b/lua/core/color.lua @@ -6,21 +6,162 @@ local M = {} ---@return table function M.copyhl(hlgroup, namespace) namespace = namespace or 0 + local res = {} local ok, hl = pcall(vim.api.nvim_get_hl, namespace, { name = hlgroup, create = false }) if not ok then - return {} + -- return default + return { + ["foreground"] = "#000000", + ["background"] = "#000000", + ["special"] = "#000000" + } end for _, key in pairs({ "foreground", "background", "special" }) do if hl[key] then - hl[key] = string.format("#%06x", hl[key]) + res[key] = string.format("#%06x", hl[key]) end end - return hl + return res +end + +--- Taken from https://github.com/rachartier/tiny-inline-diagnostic.nvim +---@param hex string +---@return table rgb +function M.hex_to_rgb(hex) + if hex == nil or hex == 'None' then + return {0, 0, 0} + end + + hex = hex:gsub('#', '') + hex = string.lower(hex) + + return { + tonumber(hex:sub(1, 2), 16), + tonumber(hex:sub(3, 4), 16), + tonumber(hex:sub(5, 6), 16) + } +end + +-- Source: 'runtime/lua/vim/_defaults.lua' in Neovim source +local function parse_osc11(x) + local r, g, b = x:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$') + if not (r and g and b) then + local a + r, g, b, a = x:match('^\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$') + if not (a and a:len() <= 4) then + return + end + end + if not (r and g and b) then + return + end + if not (r:len() <= 4 and g:len() <= 4 and b:len() <= 4) then + return + end + local parse_osc_hex = function(c) + return c:len() == 1 and (c..c) or c:sub(1, 2) + end + return '#'..parse_osc_hex(r)..parse_osc_hex(g)..parse_osc_hex(b) +end + +local _termbg_init +--- taken from github.com/echasnovski/mini.misc modified to work for me +--- sets up terminal background synchronization which enables neovim to set the +--- background of the terminal it is running in +function M.setup_termbg_sync() + -- Handling `'\027]11;?\007'` response was added in Neovim 0.10 + if vim.fn.has('nvim-0.10') == 0 then + vim.notify('`setup_termbg_sync()` requires Neovim>=0.10', + vim.log.levels.WARN) + end + + -- Proceed only if there is a valid stdout to use + local has_stdout_tty = false + for _, ui in ipairs(vim.api.nvim_list_uis()) do + has_stdout_tty = has_stdout_tty or ui.stdout_tty + end + if not has_stdout_tty then return end + + local augroup = vim.api.nvim_create_augroup('TermbgSync', { + clear = true, + }) + local track_au_id, bad_responses, had_proper_response = nil, {}, false + local f = function(args) + -- Process proper response only once + if had_proper_response then + return + end + + -- Neovim=0.10 uses string sequence as response, while Neovim>=0.11 sets it + -- in `sequence` table field + local seq = type(args.data) == 'table' and args.data.sequence or args.data + local ok, bg_init = pcall(parse_osc11, seq) + if not (ok and type(bg_init) == 'string') then + return table.insert(bad_responses, seq) + end + had_proper_response = true + pcall(vim.api.nvim_del_autocmd, track_au_id) + + -- Set up sync + local sync = function() + local normal = vim.api.nvim_get_hl(0, { + name = "Normal", + create = false + }) + if normal.bg == nil then + return + end + + -- NOTE: use `io.stdout` instead of `io.write` to ensure correct target + -- Otherwise after `io.output(file); file:close()` there is an error + io.stdout:write(string.format('\027]11;#%06x\007', normal.bg)) + end + vim.api.nvim_create_autocmd({ 'VimResume', 'ColorScheme' }, { + group = augroup, + callback = sync, + }) + + -- Set up reset to the color returned from the very first call + _termbg_init = _termbg_init or bg_init + local reset = function() + io.stdout:write('\027]11;'.._termbg_init..'\007') + end + vim.api.nvim_create_autocmd({ 'VimLeavePre', 'VimSuspend' }, { + group = augroup, + callback = reset, + }) + + -- Sync immediately + sync() + end + + -- Ask about current background color and process the proper response. + -- NOTE: do not use `once = true` as Neovim itself triggers `TermResponse` + -- events during startup, so this should wait until the proper one. + track_au_id = vim.api.nvim_create_autocmd('TermResponse', { + group = augroup, + callback = f, + nested = true + }) + io.stdout:write('\027]11;?\007') + vim.defer_fn(function() + if had_proper_response then + return + end + pcall(vim.api.nvim_del_augroup_by_id, augroup) + local bad_suffix = #bad_responses == 0 and '' or + (', only these: '..vim.inspect(bad_responses)) + local msg = + "`setup_termbg_sync()` did not get proper response from terminal emulator" + ..bad_suffix + + vim.notify(msg, vim.log.levels.WARN) + end, 1000) end return M diff --git a/lua/core/init.lua b/lua/core/init.lua index f8d0c35..c0b3aea 100644 --- a/lua/core/init.lua +++ b/lua/core/init.lua @@ -1,12 +1,16 @@ -- inspired by (and partially yoinked from): github.com/gonstoll/dotfiles -local M = { - misc = require("core.misc"), - folding = require("core.folding"), - lsp = require("core.lsp"), - color = require("core.color"), - snippets = vim.fs.joinpath(vim.fn.stdpath("config"), "lua/core/snippets.lua"), -} +local notify = vim.notify +--- overidden version of vim.notify +---@param msg string message +---@param level vim.log.levels? log level +---@param opts table? options +---@diagnostic disable-next-line: duplicate-set-field +vim.notify = function(msg, level, opts) + notify(msg, level or vim.log.levels.INFO, opts or { + title = require("core.misc").appid + }) +end --- check if the given table contains an item, and return the key value pair if --- it does @@ -23,6 +27,14 @@ table.contains = function(self, item) return false end +local M = { + misc = require("core.misc"), + folding = require("core.folding"), + lsp = require("core.lsp"), + color = require("core.color"), + snippets = vim.fs.joinpath(vim.fn.stdpath("config"), "lua/core/snippets.lua"), +} + M.mason = { --- Gets a path to a package in the Mason registry. --- Prefer this to `get_package`, since the package might not always be @@ -30,9 +42,11 @@ M.mason = { ---@param pkg string ---@param path? string get_pkg_path = function(pkg, path) - pcall(require, "mason") -- make sure Mason is loaded. Will fail when generating docs + pcall(require, "mason") -- make sure Mason is loaded. Will fail when + -- generating docs - local root = vim.env.MASON or vim.fs.joinpath(vim.fn.stdpath("data"), "mason") + local root = vim.env.MASON or vim.fs.joinpath(vim.fn.stdpath("data"), + "mason") path = path or "" return vim.fs.joinpath(root, "packages", pkg, path) end diff --git a/lua/core/snippets.lua b/lua/core/snippets.lua index 48dd54f..1bb0b27 100644 --- a/lua/core/snippets.lua +++ b/lua/core/snippets.lua @@ -22,6 +22,6 @@ ts_postfix = require("luasnip.extras.treesitter_postfix").treesitter_postfix postfix = require("luasnip.extras.postfix").postfix ms = ls.multi_snippet -function file_name(_, _, _) +file_name = function(_, _, _) return vim.fn.expand("%:t:r") end diff --git a/lua/snippets/python.lua b/lua/snippets/python.lua new file mode 100644 index 0000000..b304969 --- /dev/null +++ b/lua/snippets/python.lua @@ -0,0 +1,108 @@ +dofile(core.snippets) + +--- convert snake to pascal case +---@return string classname +local function py_file_name() + local fn = file_name() + local new = "" + + -- convert snake to pascal case + for i = 1, #fn do + if i == 1 then + new = fn:sub(1, 1):upper() + elseif fn:sub(i - 1, i - 1) == "_" then + new = new..fn:sub(i, i):upper() + elseif fn:sub(i, i) ~= "_" then + new = new..fn:sub(i, i) + end + end + + return new +end + +--- find the current class and return its name if not available defaults to +--- the file name +---@return string +local function python_class() + -- set the starting node to the node under the cursor + local node = require("nvim-treesitter.ts_utils").get_node_at_cursor() + + while node do + -- check if we're in a class + if node:type() == "class_definition" then + -- find the class name in the class declaration and return it + for i = 0, node:child_count() - 1 do + local child = node:child(i) + if child and child:type() == "identifier" then + return vim.treesitter.get_node_text(child, 0) + end + end + end + node = node:parent() + end + + -- if no class can be found default to the current file name + return file_name() +end + +return { + s("class", { + t("class "), + c(1, { + f(py_file_name, {}), + i(0, "MyClass") + }), + c(2, { + t(""), + sn(nil, { + t("("), + i(1, "object"), + t(")") + }) + }), + t({ ": ", "\t" }), + i(0) + }), + + s({ trig = [[fn\|def\|constr\|init]], trigEngine = "vim" }, { + t("def "), + d(1, function(_, snip) + if snip.trigger == "constr" or snip.trigger == "init" then + print(python_class()) + return sn(nil, { + t("__init__") + }) + else + return sn(nil, { + i(1, "myFunc") + }) + end + end, {}), + t("("), + d(2, function(_, snip) + -- if this is a constructor or a function in a class then we need to put + -- self as the first argument + if snip.trigger == "constr" or snip.trigger == "init" + or python_class() ~= file_name() then + + return sn(nil, { + t("self") + }) + else + return sn(nil, {}) + end + end, {}), + i(3), + t(")"), + t(" -> "), + i(4, "None"), + t({ ":", "\t" }), + i(0, "pass") + }), + + s("main", { + t({ "def main() -> None:", "\t" }), + i(0, 'print("hello world")'), + t({ "", "", 'if __name__ == "__main__":', "\tmain()" }) + }) +}