diff --git a/modules/profiles/base.nix b/modules/profiles/base.nix index a811050..ad8cbe4 100644 --- a/modules/profiles/base.nix +++ b/modules/profiles/base.nix @@ -262,7 +262,6 @@ in programs = { mtr.enable = true; - starship.enable = true; command-not-found.enable = false; }; @@ -297,6 +296,7 @@ in "--cmd c" ]; }; + starship.enable = true; }; home = { username = "moritz"; diff --git a/modules/programs/fish.nix b/modules/programs/fish.nix index c29dd7c..8934508 100644 --- a/modules/programs/fish.nix +++ b/modules/programs/fish.nix @@ -114,6 +114,7 @@ in ''; }; }; + starship.enableTransience = true; }; }; }; diff --git a/modules/programs/nvim/default.nix b/modules/programs/nvim/default.nix index 5c4840f..3818afd 100644 --- a/modules/programs/nvim/default.nix +++ b/modules/programs/nvim/default.nix @@ -31,6 +31,11 @@ in ) ]; home-manager.users.moritz = { + xdg.configFile."nvim/snippets" = { + recursive = true; + source = ./plugins/snippets; + }; + programs.neovim = { enable = true; package = inputs.neovim-nightly-overlay.packages.${pkgs.system}.default; diff --git a/modules/programs/nvim/plugins/coding.nix b/modules/programs/nvim/plugins/coding.nix index eb28ff5..b267434 100644 --- a/modules/programs/nvim/plugins/coding.nix +++ b/modules/programs/nvim/plugins/coding.nix @@ -83,26 +83,14 @@ with builtins; { plugin = cmp-cmdline; } { plugin = cmp-nvim-lsp; } { plugin = cmp_luasnip; } - { - plugin = copilot-cmp; - opts = { }; - dependencies = [ - { - plugin = copilot-lua; - opts = { - suggestion = { enabled = false; }; - panel = { enabled = false; }; - }; - conf = /* lua */ '' - require("copilot").setup(opts) - vim.cmd("Copilot disable") - ''; - } - ]; - } + { plugin = cmp-spell; } + { plugin = cmp-nvim-lsp-signature-help; } { plugin = friendly-snippets; } { plugin = lspkind-nvim; } - { plugin = luasnip; } + { + plugin = luasnip; + conf = readFile ./lua/luasnip.lua; + } ]; } { diff --git a/modules/programs/nvim/plugins/lua/luasnip.lua b/modules/programs/nvim/plugins/lua/luasnip.lua new file mode 100644 index 0000000..c391b09 --- /dev/null +++ b/modules/programs/nvim/plugins/lua/luasnip.lua @@ -0,0 +1,24 @@ +local ls = require("luasnip") +local types = require("luasnip.util.types") + +-- Every unspecified option will be set to the default. +ls.setup({ + history = true, + + -- Update more often, :h events for more info. + update_events = "TextChanged,TextChangedI", + -- Snippets aren't automatically removed if their text is deleted. + -- `delete_check_events` determines on which events (:h events) a check for + -- deleted snippets is performed. + -- This can be especially useful when `history` is enabled. + delete_check_events = "TextChanged", + ext_opts = { + [types.choiceNode] = { + active = { + virt_text = { { "<--", "Error" } }, + }, + }, + }, +}) + +require("luasnip.loaders.from_lua").load({ paths = "~/.config/nvim/snippets" }) diff --git a/modules/programs/nvim/plugins/lua/nvim-cmp.lua b/modules/programs/nvim/plugins/lua/nvim-cmp.lua index abe86bb..19d9ffe 100644 --- a/modules/programs/nvim/plugins/lua/nvim-cmp.lua +++ b/modules/programs/nvim/plugins/lua/nvim-cmp.lua @@ -2,25 +2,17 @@ local cmp = require("cmp") local luasnip = require("luasnip") require("luasnip.loaders.from_vscode").lazy_load() -local has_words_before = function() - if vim.api.nvim_buf_get_option(0, "buftype") == "prompt" then - return false - end - local line, col = unpack(vim.api.nvim_win_get_cursor(0)) - return col ~= 0 and vim.api.nvim_buf_get_text(0, line - 1, 0, line - 1, col, {})[1]:match("^%s*$") == nil -end - cmp.setup({ formatting = { format = require("lspkind").cmp_format({ mode = "symbol", -- show only symbol annotations maxwidth = 50, -- prevent the popup from showing more than provided characters ellipsis_char = "...", -- when popup menu exceed maxwidth, the truncated part would show ellipsis_char instead - symbol_map = { - Copilot = "", - }, }), }, + enabled = function() + return not luasnip.jumpable(1) + end, snippet = { -- REQUIRED - you must specify a snippet engine expand = function(args) @@ -31,34 +23,51 @@ cmp.setup({ [""] = cmp.mapping.scroll_docs(-4), [""] = cmp.mapping.scroll_docs(4), [""] = cmp.mapping.complete(), - [""] = cmp.mapping.abort(), + [""] = cmp.mapping.abort(), [""] = cmp.mapping.confirm({ select = true }), [""] = cmp.mapping(function(fallback) - if cmp.visible() and has_words_before() then + if cmp.visible() then cmp.select_next_item({ behavior = cmp.SelectBehavior.Select }) - elseif luasnip.expand_or_jumpable() then - luasnip.expand_or_jump() + elseif luasnip.jumpable(1) then + luasnip.jump(1) else fallback() end end, { "i", "s" }), [""] = cmp.mapping(function(fallback) if cmp.visible() then - cmp.select_prev_item() + cmp.select_prev_item({ behavior = cmp.SelectBehavior.Select }) elseif luasnip.jumpable(-1) then luasnip.jump(-1) else fallback() end end, { "i", "s" }), + [""] = cmp.mapping(function(fallback) + if luasnip.choice_active() then + luasnip.change_choice(1) + else + fallback() + end + end, { "i", "s" }), + [""] = cmp.mapping(function(fallback) + if luasnip.choice_active() then + luasnip.change_choice(-1) + else + fallback() + end + end, { "i", "s" }), }), - sources = { + sources = cmp.config.sources({ { name = "async_path", priority = 1 }, - { name = "buffer", priority = 1 }, - { name = "luasnip", priority = 2 }, - { name = "copilot", priority = 3 }, - { name = "nvim_lsp", priority = 3 }, - }, + { name = "nvim_lsp", priority = 2 }, + { name = "nvim_lsp_signature_help", priority = 3 }, + { name = "luasnip", priority = 4 }, + }, { + { name = "async_path" }, + { name = "buffer" }, + { name = "spell" }, + }), }) -- Set configuration for specific filetype. diff --git a/modules/programs/nvim/plugins/snippets/python.lua b/modules/programs/nvim/plugins/snippets/python.lua new file mode 100644 index 0000000..6453645 --- /dev/null +++ b/modules/programs/nvim/plugins/snippets/python.lua @@ -0,0 +1,242 @@ +local ls = require("luasnip") +local s = ls.snippet +local sn = ls.snippet_node +local isn = ls.indent_snippet_node +local t = ls.text_node +local i = ls.insert_node +local f = ls.function_node +local c = ls.choice_node +local d = ls.dynamic_node +local r = ls.restore_node +local events = require("luasnip.util.events") +local ai = require("luasnip.nodes.absolute_indexer") +local extras = require("luasnip.extras") +local l = extras.lambda +local rep = extras.rep +local p = extras.partial +local m = extras.match +local n = extras.nonempty +local dl = extras.dynamic_lambda +local fmt = require("luasnip.extras.fmt").fmt +local fmta = require("luasnip.extras.fmt").fmta +local conds = require("luasnip.extras.expand_conditions") +local postfix = require("luasnip.extras.postfix").postfix +local types = require("luasnip.util.types") +local parse = require("luasnip.util.parser").parse_snippet +local ms = ls.multi_snippet +local k = require("luasnip.nodes.key_indexer").new_key + +local arg_template = [[ + {arg}: {type} +]] + +local function pyarg() + return sn( + nil, + fmt(arg_template, { + arg = i(1, "arg"), + type = i(2, "Any"), + }) + ) +end + +local function pyargs(_, _, _, user_args) + local choices = { + sn(nil, i(1)), + sn(nil, { + not user_args and t(", ") or t(""), + d(1, pyarg), + d(2, pyargs, { user_args = { false } }), + }), + } + -- switch order for first call + if user_args then + local fst, snd = unpack(choices) + choices = { snd, fst } + end + + return sn(nil, c(1, choices)) +end + +local def_template = [[ +def {fname}({args}) -> {rtype}: + """ + {docs} + """ + {final} +]] + +local def = s( + "def", + fmt(def_template, { + fname = i(1, "fname"), + args = d(2, pyargs, nil, { user_args = { true } }), + rtype = i(3, "None"), + docs = i(4, "Documentation"), + final = i(5, "pass"), + }, { priority = 1001 }) +) + +local defs_template = [[ +def {mname}(self, {args}) -> {rtype}: + """ + {docs} + """ + {final} +]] + +local defs = s( + "defs", + fmt(defs_template, { + mname = i(1, "mname"), + args = d(2, pyargs, nil, { user_args = { true } }), + rtype = i(3, "None"), + docs = i(4, "Documentation"), + final = i(5, "pass"), + }, { priority = 1001 }) +) + +local enum_template = [[ +for {i}, {value} in enumerate({iter}): + {final} +]] + +local dot_enum = postfix(".enum", { + d(1, function(_, parent) + return sn( + 1, + fmt(enum_template, { + i = i(1, "i"), + value = i(2, "value"), + iter = t(parent.env.POSTFIX_MATCH), + final = i(3, "pass"), + }) + ) + end), +}) + +local enum = s( + "enum", + fmt(enum_template, { + i = i(1, "i"), + value = i(2, "value"), + iter = i(3, "iter"), + final = i(4, "pass"), + }) +) + +local for_template = [[ +for {item} in {iter}: + {final} +]] + +local dot_for = postfix(".for", { + d(1, function(_, parent) + return sn( + 1, + fmt(for_template, { + item = i(1, "item"), + iter = t(parent.env.POSTFIX_MATCH), + final = i(2, "pass"), + }) + ) + end), +}) + +local items_template = [[ +for {key}, {value} in {iter}: + {final} +]] + +local dot_items = postfix(".items", { + d(1, function(_, parent) + return sn( + 1, + fmt(items_template, { + key = i(1, "key"), + value = i(2, "value"), + iter = t(parent.env.POSTFIX_MATCH), + final = i(3, "pass"), + }) + ) + end), +}) + +local try_template = [[ +try: + {raises} +except {exception} as {ename}: + {final} +]] + +local dot_try = postfix(".try", { + d(1, function(_, parent) + return sn( + 1, + fmt(try_template, { + raises = t(parent.env.POSTFIX_MATCH), + exception = i(1, "Exception"), + ename = i(2, "e"), + final = i(3, "pass"), + }) + ) + end), +}) + +local parr = s( + "parr", + fmt( + [[ + :param {name}: {description} + :type {name}: {type} + ]], + { + name = i(1, "name"), + description = i(2, "description"), + type = i(3, "type"), + }, + { + repeat_duplicates = true, + } + ) +) + +local retr = s( + "retr", + fmt( + [[ + :return: {description} + :rtype: {rtype} + ]], + { + description = i(1, "description"), + rtype = i(2, "rtype"), + } + ) +) + +local raisr = s( + "raisr", + fmt( + [[ + :raises {exception}: {description} + ]], + { + exception = i(1, "Exception"), + description = i(2, "description"), + } + ) +) + +return { + def, + defs, + dot_enum, + dot_for, + dot_items, + dot_try, + enum, + parr, + retr, + raisr, +}