diff options
Diffstat (limited to 'common/nvim/lua/setup')
| -rwxr-xr-x | common/nvim/lua/setup/compat.lua | 104 | ||||
| -rwxr-xr-x | common/nvim/lua/setup/manager.lua | 811 | ||||
| -rwxr-xr-x | common/nvim/lua/setup/plugins.lua | 609 |
3 files changed, 0 insertions, 1524 deletions
diff --git a/common/nvim/lua/setup/compat.lua b/common/nvim/lua/setup/compat.lua deleted file mode 100755 index ef90444..0000000 --- a/common/nvim/lua/setup/compat.lua +++ /dev/null @@ -1,104 +0,0 @@ --- setup/compat.lua --- Automatically patches deprecated APIs based on Neovim version - --- Version check helper -local function has_version(major, minor, patch) - local v = vim.version() - patch = patch or 0 - return v.major > major - or (v.major == major and v.minor > minor) - or (v.major == major and v.minor == minor and v.patch >= patch) -end - --- === GLOBAL PATCHES === -- - --- Neovim 0.10+: vim.islist replaces deprecated vim.tbl_islist -if has_version(0, 10) then - if vim.tbl_islist == nil then - vim.tbl_islist = vim.islist - end -end - --- Neovim 0.12+: vim.tbl_flatten removed → shim using vim.iter -if has_version(0, 12) then - vim.tbl_flatten = function(t) - return vim.iter(t):flatten():totable() - end -end - --- === DEPRECATION SHIMS (0.13 / 1.0) === -- - --- client.is_stopped → client:is_stopped() -if has_version(0, 13) then - local mt = getmetatable(vim.lsp._client or {}) - if mt and mt.__index and mt.__index.is_stopped then - mt.__index.is_stopped = function(client, ...) - return client:is_stopped(...) - end - end -end - --- client.request → client:request() -if has_version(0, 13) then - local mt = getmetatable(vim.lsp._client or {}) - if mt and mt.__index and mt.__index.request then - mt.__index.request = function(client, ...) - return client:request(...) - end - end -end - --- vim.validate{tbl} → vim.validate(tbl) -if has_version(1, 0) then - if type(vim.validate) == "function" then - local old_validate = vim.validate - vim.validate = function(arg) - -- Handle both forms for backward compatibility - if type(arg) == "table" then - return old_validate(arg) - else - return old_validate{ arg } - end - end - end -end - --- Deprecated: vim.lsp.get_active_clients (moved in 0.11+) -if has_version(0, 11) then - if vim.lsp.get_active_clients == nil then - vim.lsp.get_active_clients = function(...) - return vim.lsp.get_clients(...) - end - end -end - --- Deprecated: vim.diagnostic.setqflist / setloclist (moved in 0.11+) -if has_version(0, 11) then - if vim.diagnostic.setqflist == nil then - vim.diagnostic.setqflist = function(diags, opts) - return vim.diagnostic.toqflist(diags, opts) - end - end - if vim.diagnostic.setloclist == nil then - vim.diagnostic.setloclist = function(diags, opts) - return vim.diagnostic.toloclist(diags, opts) - end - end -end - --- Deprecated: vim.lsp.buf.formatting/formatting_sync (removed in 0.8+) -if has_version(0, 8) then - if vim.lsp.buf.formatting == nil then - vim.lsp.buf.formatting = function(opts) - return vim.lsp.buf.format(opts) - end - end - if vim.lsp.buf.formatting_sync == nil then - vim.lsp.buf.formatting_sync = function(opts, timeout_ms) - return vim.lsp.buf.format(vim.tbl_extend("force", opts or {}, { timeout_ms = timeout_ms })) - end - end -end - --- Return something to satisfy require() -return true diff --git a/common/nvim/lua/setup/manager.lua b/common/nvim/lua/setup/manager.lua deleted file mode 100755 index 9cf1d14..0000000 --- a/common/nvim/lua/setup/manager.lua +++ /dev/null @@ -1,811 +0,0 @@ --- manager.lua - -local M = {} - --- State tracking -local state = { - manager_invoked = nil, - initialized = false, - bootstrap_completed = {}, -} - --- Path constants -local PATHS = { - lazy = vim.fn.stdpath("data") .. "/lazy/lazy.nvim", - packer = vim.fn.stdpath("data") .. "/site/pack/packer/start/packer.nvim", - packer_dir = vim.fn.stdpath("data") .. "/site/pack/packer/start", - builtin_dir = vim.fn.stdpath("data") .. "/nvim/site/pack/core/opt", -} - --- Utility functions -local function safe_require(module) - local ok, result = pcall(require, module) - return ok and result or nil -end - -local function notify(msg, level) - vim.notify("[Manager] " .. msg, level or vim.log.levels.INFO) -end - -local function execute_git_command(cmd, _) - -- Use vim.fn.system instead of os.execute for better cross-platform support and error handling - local result = vim.fn.system(cmd) - return vim.v.shell_error == 0 -end - -local function get_nvim_version() - local version = vim.version() - if version then - return version.major, version.minor, version.patch - end - - -- Fallback for older versions - local version_str = vim.fn.execute("version"):match("NVIM v(%d+%.%d+%.%d+)") - if version_str then - local major, minor, patch = version_str:match("(%d+)%.(%d+)%.(%d+)") - return tonumber(major), tonumber(minor), tonumber(patch) - end - return 0, 0, 0 -end - -local function has_builtin_manager() - local major, minor = get_nvim_version() - return major > 0 or (major == 0 and minor >= 12) -end - --- CRITICAL FIX: This function is essential to prevent runtime conflicts. --- It removes the specified manager's directory from the runtimepath. -local function cleanup_manager(manager_name) - if manager_name == "packer" then - -- Reset packer state and remove from rtp - local packer = safe_require("packer") - if packer then - pcall(packer.reset) - end - -- Remove the entire packer directory from rtp - local packer_rtp = vim.fn.glob(PATHS.packer_dir) - if packer_rtp then - local rtp_items = vim.split(vim.o.rtp, ",") - local new_rtp_items = {} - for _, item in ipairs(rtp_items) do - if item ~= packer_rtp then - table.insert(new_rtp_items, item) - end - end - vim.o.rtp = table.concat(new_rtp_items, ",") - end - elseif manager_name == "lazy" then - -- Lazy.nvim clears its state on each run, but we can remove it from rtp for good measure - local lazy_rtp = vim.fn.glob(PATHS.lazy) - if lazy_rtp then - local rtp_items = vim.split(vim.o.rtp, ",") - local new_rtp_items = {} - for _, item in ipairs(rtp_items) do - if item ~= lazy_rtp then - table.insert(new_rtp_items, item) - end - end - vim.o.rtp = table.concat(new_rtp_items, ",") - end - elseif manager_name == "builtin" then - -- Built-in manager is handled by vim.opt.packpath and doesn't need manual cleanup from rtp - -- unless we want to disable its packages, which isn't the goal here. - end -end - --- IMPROVED: Use vim.g for persistence instead of file system -local function save_manager_choice(manager_name) - vim.g.nvim_manager_choice = manager_name - -- Also save to data directory as a simple text file for true persistence across sessions - local data_dir = vim.fn.stdpath("data") - local choice_file = data_dir .. "/.manager_choice" - local file = io.open(choice_file, "w") - if file then - file:write(manager_name) - file:close() - end -end - -local function load_manager_choice() - -- First check vim.g (current session) - if vim.g.nvim_manager_choice then - return vim.g.nvim_manager_choice - end - - -- Then check persistent file - local data_dir = vim.fn.stdpath("data") - local choice_file = data_dir .. "/.manager_choice" - local file = io.open(choice_file, "r") - if file then - local choice = file:read("*a"):gsub("%s+", "") -- trim whitespace - file:close() - if choice and choice ~= "" then - vim.g.nvim_manager_choice = choice -- cache in session - return choice - end - end - - return nil -end - ---- Packer Manager Implementation --- --- Handles cloning, setup, and configuration of Packer.nvim. -local Packer = {} - -function Packer.bootstrap() - if state.bootstrap_completed.packer then - return true - end - - local fn = vim.fn - if fn.isdirectory(PATHS.packer_dir) == 0 then - fn.mkdir(PATHS.packer_dir, "p") - end - - if fn.empty(fn.glob(PATHS.packer)) > 0 then - local is_windows = vim.loop.os_uname().version:match("Windows") - local git_cmd - - if is_windows then - git_cmd = string.format( - 'git clone --depth=1 https://github.com/wbthomason/packer.nvim "%s" >nul 2>&1', - PATHS.packer - ) - else - git_cmd = string.format( - 'env -i PATH="%s" HOME="%s" git clone --depth=1 --quiet https://github.com/wbthomason/packer.nvim %q >/dev/null 2>&1', - os.getenv("PATH") or "/usr/bin:/bin", - os.getenv("HOME") or "/tmp", - PATHS.packer - ) - end - - if not execute_git_command(git_cmd, "Failed to clone packer.nvim") then - return false - end - end - - state.bootstrap_completed.packer = true - return true -end - -function Packer.setup() - if not Packer.bootstrap() then - return false - end - - -- Ensure packer.nvim is in the runtime path - vim.cmd("packadd packer.nvim") - - local packer = safe_require("packer") - if not packer then - notify("Failed to load packer.nvim", vim.log.levels.ERROR) - return false - end - - -- Reset any existing configuration from a previous run - pcall(packer.reset) - - packer.init({ - auto_reload_compiled = true, - display = { - open_fn = function() - return require("packer.util").float({ border = "rounded" }) - end, - }, - luarocks = { - python_cmd = 'python3' - }, - }) - - local plugins = safe_require("setup.plugins") - if not plugins then - notify("Failed to load plugins configuration", vim.log.levels.ERROR) - return false - end - - packer.startup(function(use) - use "wbthomason/packer.nvim" - for _, plugin in ipairs(plugins) do - -- CHECK FOR EXCLUDE HERE - Packer support for exclude option - if plugin.exclude and vim.tbl_contains(plugin.exclude, "packer") then - --notify("Excluding plugin for packer: " .. (plugin.name or plugin.as or plugin[1] or "unknown"), vim.log.levels.INFO) - goto continue - end - - -- Packer doesn't have a lazy option, so we ensure all plugins are loaded eagerly - -- by clearing any lazy-loading keys from the plugins table. - local packer_plugin = vim.deepcopy(plugin) - packer_plugin.event = nil - packer_plugin.keys = nil - packer_plugin.cmd = nil - packer_plugin.ft = nil - packer_plugin.lazy = nil - packer_plugin.exclude = nil -- Remove exclude from the actual plugin spec - use(packer_plugin) - ::continue:: - end - end) - - return true -end - -function Packer.is_available() - return vim.fn.isdirectory(PATHS.packer) == 1 -end - ---- Lazy.nvim Manager Implementation --- -local Lazy = {} - -function Lazy.bootstrap() - if state.bootstrap_completed.lazy then - return true - end - - -- Check if lazy.nvim is already cloned - if not vim.loop.fs_stat(PATHS.lazy) then - local is_windows = vim.loop.os_uname().version:match("Windows") - local git_cmd - - if is_windows then - git_cmd = string.format( - 'git clone --filter=blob:none --branch=stable https://github.com/folke/lazy.nvim.git "%s" >nul 2>&1', - PATHS.lazy - ) - else - git_cmd = string.format( - 'env -i PATH="%s" HOME="%s" git clone --filter=blob:none --branch=stable --quiet https://github.com/folke/lazy.nvim.git %q >/dev/null 2>&1', - os.getenv("PATH") or "/usr/bin:/bin", - os.getenv("HOME") or "/tmp", - PATHS.lazy - ) - end - - if not execute_git_command(git_cmd, "Failed to clone lazy.nvim") then - return false - end - end - - state.bootstrap_completed.lazy = true - return true -end - -function Lazy.setup() - if not Lazy.bootstrap() then - return false - end - - -- Ensure lazy.nvim is in the runtime path before requiring it - vim.opt.rtp:prepend(PATHS.lazy) - - local lazy = safe_require("lazy") - if not lazy then - notify("Failed to load lazy.nvim", vim.log.levels.ERROR) - return false - end - - -- FIX: Correctly require plugins and set up lazy.nvim - local plugins = safe_require("setup.plugins") - if not plugins then - notify("Failed to load plugins configuration", vim.log.levels.ERROR) - return false - end - - -- Filter out excluded plugins for Lazy - local filtered_plugins = {} - for _, plugin in ipairs(plugins) do - -- CHECK FOR EXCLUDE HERE - Lazy support for exclude option - if plugin.exclude and vim.tbl_contains(plugin.exclude, "lazy") then - --notify("Excluding plugin for lazy: " .. (plugin.name or plugin[1] or "unknown"), vim.log.levels.INFO) - else - local lazy_plugin = vim.deepcopy(plugin) - lazy_plugin.exclude = nil -- Remove exclude from the actual plugin spec - table.insert(filtered_plugins, lazy_plugin) - end - end - - -- Setup Lazy.nvim with the correct options - lazy.setup(filtered_plugins, { - { - import = "plugins", - }, - defaults = { lazy = false }, -- Set plugins to be lazy-loaded by default - install = { missing = true }, -- CRITICAL FIX: This ensures missing plugins are installed - ui = { - border = "rounded", - }, - performance = { - rtp = { - disabled_plugins = { - "gzip", "matchit", "matchparen", "netrwPlugin", - "tarPlugin", "tohtml", "tutor", "zipPlugin", - }, - }, - }, - }) - - return true -end - -function Lazy.is_available() - return vim.loop.fs_stat(PATHS.lazy) ~= nil -end - ---- Built-in manager implementation (Neovim 0.12+) --- -local Builtin = {} - -function Builtin.bootstrap() - if not has_builtin_manager() then - --notify("Built-in package manager not available in this Neovim version", vim.log.levels.WARN) - return false - end - - state.bootstrap_completed.builtin = true - return true -end - -function Builtin.setup() - if not has_builtin_manager() then - --notify("Built-in package manager not available in this Neovim version", vim.log.levels.WARN) - return false - end - - local plugins = safe_require("setup.plugins") - if not plugins then - notify("Failed to load plugins configuration", vim.log.levels.ERROR) - return false - end - - -- Convert plugins to builtin manager format - local builtin_specs = {} - for _, plugin in ipairs(plugins) do - -- CHECK FOR EXCLUDE HERE - if plugin.exclude and vim.tbl_contains(plugin.exclude, "builtin") then - --notify("Excluding plugin for builtin: " .. (plugin.name or plugin[1] or "unknown"), vim.log.levels.INFO) - goto continue - end - local spec = {} - - if type(plugin) == "string" then - -- Handle string format like "user/repo" - if plugin:match("^[%w%-_%.]+/[%w%-_%.]+$") then - -- It's a GitHub shorthand - spec.src = "https://github.com/" .. plugin - spec.name = plugin:match("/([%w%-_%.]+)$") -- Extract repo name - else - -- It's already a full URL - spec.src = plugin - end - elseif type(plugin) == "table" then - -- Handle table format - if plugin[1] and type(plugin[1]) == "string" then - -- Format like {"user/repo", ...} - if plugin[1]:match("^[%w%-_%.]+/[%w%-_%.]+$") then - spec.src = "https://github.com/" .. plugin[1] - spec.name = plugin[1]:match("/([%w%-_%.]+)$") - else - spec.src = plugin[1] - end - - -- Copy other properties - for k, v in pairs(plugin) do - if type(k) == "string" then - spec[k] = v - end - end - elseif plugin.src then - spec.src = plugin.src - for k, v in pairs(plugin) do - if k ~= "src" then - spec[k] = v - end - end - elseif plugin.url then - spec.src = plugin.url - for k, v in pairs(plugin) do - if k ~= "url" then - spec[k] = v - end - end - else - notify("Invalid plugin specification for built-in manager: " .. vim.inspect(plugin), vim.log.levels.WARN) - goto continue - end - - -- Handle name override - if plugin.name then - spec.name = plugin.name - elseif plugin.as then - spec.name = plugin.as - elseif not spec.name and spec.src then - -- Extract name from URL if not specified - spec.name = spec.src:match("/([%w%-_%.]+)%.git$") or spec.src:match("/([%w%-_%.]+)$") or spec.src - end - - -- Handle version - if plugin.version then - spec.version = plugin.version - end - - -- Remove keys that builtin manager doesn't understand - spec.lazy = nil - spec.event = nil - spec.keys = nil - spec.cmd = nil - spec.ft = nil - spec.dependencies = nil - spec.config = nil - spec.build = nil - spec.run = nil - spec.priority = nil - spec.as = nil - spec.url = nil - spec.exclude = nil - spec[1] = nil -- Remove positional argument - end - - if spec.src then - table.insert(builtin_specs, spec) - end - ::continue:: - end - - -- Debug: Show what we're about to install - --notify(string.format("Installing %d plugins with built-in manager", #builtin_specs), vim.log.levels.INFO) - - -- CRITICAL FIX: Call vim.pack.add with the specs directly, not wrapped in array - if #builtin_specs > 0 then - local ok, err = pcall(vim.pack.add, builtin_specs) - if not ok then - notify("Failed to add plugins: " .. tostring(err), vim.log.levels.ERROR) - return false - end - - --notify("Plugins added successfully. Use :Pack to install/update them.", vim.log.levels.INFO) - else - notify("No valid plugins found for built-in manager", vim.log.levels.WARN) - end - - -- Create user commands for convenience - FIXED COMMAND NAMES - vim.api.nvim_create_user_command("Package", function(opts) - local subcommand = opts.fargs[1] or "update" - local names = vim.list_slice(opts.fargs, 2) - - if subcommand == "add" then - -- For add, we need to re-run setup to add new plugins - --notify("Re-running builtin manager setup to add new plugins...") - Builtin.setup() - elseif subcommand == "update" then - if #names == 0 then - names = nil -- Update all plugins - end - vim.pack.update(names) - elseif subcommand == "status" then - local plugins = vim.pack.get() - print(string.format("Built-in manager: %d plugins managed", #plugins)) - for _, plugin in ipairs(plugins) do - local status = plugin.active and "active" or "inactive" - print(string.format(" %s (%s): %s", plugin.spec.name, status, plugin.path)) - end - else - -- Default behavior - treat as update - if subcommand then - table.insert(names, 1, subcommand) - end - if #names == 0 then - names = nil - end - vim.pack.update(names) - end - end, { - nargs = "*", - complete = function(arglead, cmdline, cursorpos) - local args = vim.split(cmdline, "%s+") - if #args <= 2 then - -- Complete subcommands - local subcommands = { "add", "update", "status" } - local matches = {} - for _, cmd in ipairs(subcommands) do - if cmd:find("^" .. arglead) then - table.insert(matches, cmd) - end - end - return matches - else - -- Complete plugin names - local plugins = vim.pack.get() - local names = {} - for _, plugin in ipairs(plugins) do - if plugin.spec.name:find("^" .. arglead) then - table.insert(names, plugin.spec.name) - end - end - return names - end - end, - desc = "Manage plugins with built-in manager. Usage: :Pack [add|update|status] [plugin_names...]" - }) - - ---- Keep the old command for backwards compatibility - --vim.api.nvim_create_user_command("PackageStatus", function() - -- vim.cmd("Pack status") - --end, { - -- nargs = 0, - -- desc = "Show status of plugins managed by built-in manager (deprecated, use :Pack status)" - --}) - - return true -end - -function Builtin.is_available() - return has_builtin_manager() -end - ---- Manager registry --- -local MANAGERS = { - packer = Packer, - lazy = Lazy, - builtin = Builtin, -} - ---- Core management functions --- -local function activate_manager(manager_name) - local manager = MANAGERS[manager_name] - if not manager then - notify("Unknown manager: " .. manager_name, vim.log.levels.ERROR) - return false - end - - -- Cleanup the old manager before activating the new one to prevent runtime conflicts. - if state.manager_invoked and state.manager_invoked ~= manager_name then - cleanup_manager(state.manager_invoked) - end - - if not manager.bootstrap() then - return false - end - - local ok = manager.setup() - if ok then - state.manager_invoked = manager_name - -- CRITICAL FIX: Persist the manager choice after successful setup - save_manager_choice(manager_name) - end - return ok -end - ---- Auto-detection and command setup --- -local function setup_auto_detection() - -- Autocmd to activate Packer when Packer commands are used - vim.api.nvim_create_autocmd("CmdUndefined", { - pattern = "Packer*", - callback = function(event) - if state.manager_invoked ~= "packer" then - local ok = activate_manager("packer") - if ok then - -- Re-execute the original command after setup - vim.cmd(event.match) - end - end - end, - desc = "Auto-activate Packer when Packer commands are used" - }) - - -- Autocmd to activate Lazy when Lazy commands are used - vim.api.nvim_create_autocmd("CmdUndefined", { - pattern = "Lazy*", - callback = function(event) - if state.manager_invoked ~= "lazy" then - local ok = activate_manager("lazy") - if ok then - -- CRITICAL FIX: Use vim.schedule to defer the command execution - -- This ensures Lazy's setup is complete before running the command. - vim.schedule(function() - pcall(vim.cmd, event.match) - end) - end - end - end, - desc = "Auto-activate Lazy and re-execute command" - }) - - vim.api.nvim_create_autocmd("CmdUndefined", { - pattern = "Package*", - callback = function(event) - if state.manager_invoked ~= "builtin" and has_builtin_manager() then - local ok = activate_manager("builtin") - if ok then - vim.cmd(event.match) - end - end - end, - desc = "Auto-activate built-in manager when Pack commands are used" - }) -end - ---- Public API --- -function M.setup() - if state.initialized then - return - end - - -- Initial bootstrap attempt for all managers to see what's available - for name, manager in pairs(MANAGERS) do - -- CRITICAL FIX: Always bootstrap, but don't set up yet - pcall(manager.bootstrap) - end - - -- CRITICAL FIX: Check for a previously saved choice - local persistent_choice = load_manager_choice() - if persistent_choice and MANAGERS[persistent_choice] then - -- If a choice exists, immediately activate that manager for this session - activate_manager(persistent_choice) - else - -- If no choice exists, set up the autocmds to wait for a command - setup_auto_detection() - end - - state.initialized = true -end - -function M.use_manager(manager_name) - if not state.initialized then - M.setup() - end - - local available = M.available_managers() - if not vim.tbl_contains(available, manager_name) then - notify(string.format("Manager '%s' is not available. Available: %s", - manager_name, table.concat(available, ", ")), vim.log.levels.WARN) - return false - end - - return activate_manager(manager_name) -end - -function M.available_managers() - local managers = {} - for name, manager in pairs(MANAGERS) do - if manager.is_available() then - table.insert(managers, name) - end - end - return managers -end - -function M.current_manager() - return state.manager_invoked -end - -function M.status() - local info = { - initialized = state.initialized, - current_manager = state.manager_invoked, - available_managers = M.available_managers(), - bootstrap_completed = state.bootstrap_completed, - } - - print("=== Neovim Plugin Manager Status ===") - print(string.format("Initialized: %s", tostring(info.initialized))) - print(string.format("Current Manager: %s", info.current_manager or "None")) - print(string.format("Available Managers: %s", table.concat(info.available_managers, ", "))) - - -- FIX: Properly format the Neovim version - local major, minor, patch = get_nvim_version() - print(string.format("Neovim Version: %d.%d.%d", major, minor, patch)) - print(string.format("Built-in Support: %s", tostring(has_builtin_manager()))) - - return info -end - --- FIX: Added M.get_nvim_version function to the public API -function M.get_nvim_version() - local major, minor, patch = get_nvim_version() - return { major = major, minor = minor, patch = patch } -end - -function M.reset_nvim() - vim.ui.input({ - prompt = "Are you sure you want to reset Neovim? This will delete all data, state, cache, and plugins. (y/N): " - }, function(input) - if input and input:lower() == "y" then - local fn = vim.fn - local is_windows = vim.loop.os_uname().version:match("Windows") - - local paths_to_remove = { - fn.stdpath("data"), - fn.stdpath("state"), - fn.stdpath("cache"), - fn.stdpath("config") .. "/plugin", - } - - local cmd = "" - if is_windows then - local paths_quoted = {} - for _, path in ipairs(paths_to_remove) do - table.insert(paths_quoted, string.format('"%s"', path)) - end - cmd = "powershell -Command \"Remove-Item " .. - table.concat(paths_quoted, ", ") .. " -Recurse -Force -ErrorAction SilentlyContinue\"" - else - local paths_quoted = {} - for _, path in ipairs(paths_to_remove) do - table.insert(paths_quoted, vim.fn.shellescape(path)) - end - cmd = "rm -rf " .. table.concat(paths_quoted, " ") - end - - notify("Resetting Neovim... Please restart after this operation.") - - vim.defer_fn(function() - local result = os.execute(cmd) - if result ~= 0 then - notify("Reset command may have failed. You might need to delete directories manually.", vim.log.levels.WARN) - else - notify("Reset completed successfully. Please restart Neovim.") - end - end, 100) - else - notify("Reset cancelled.") - end - end) -end - --- Clear manager choice function -function M.clear_choice() - vim.g.nvim_manager_choice = nil - local data_dir = vim.fn.stdpath("data") - local choice_file = data_dir .. "/.manager_choice" - os.remove(choice_file) - notify("Manager choice cleared. Next command will determine the manager.") -end - -vim.api.nvim_create_user_command("Reset", function() - M.reset_nvim() -end, { - nargs = 0, - desc = "Reset Neovim's data, state, cache, and plugin directories" -}) - -local function manager_command(opts) - local subcommand = opts.fargs[1] - - if subcommand == "status" then - M.status() - elseif subcommand == "packer" or subcommand == "Packer" then - M.use_manager("packer") - elseif subcommand == "lazy" or subcommand == "Lazy" then - M.use_manager("lazy") - elseif subcommand == "builtin" or subcommand == "built-in" or subcommand == "Builtin" or subcommand == "Built-in" then - M.use_manager("builtin") - elseif subcommand == "clear" then - M.clear_choice() - else - print("Unknown subcommand. Try 'status', 'packer', 'lazy', 'builtin' or 'clear'.") - end -end - -vim.api.nvim_create_user_command("Manager", manager_command, { - nargs = "+", - complete = function(arglead) - local subcommands = { "status", "packer", "Packer", "lazy", "Lazy", "builtin", "built-in", "Builtin", "Built-in", - "clear" } - local result = {} - for _, subcommand in ipairs(subcommands) do - if subcommand:find("^" .. arglead, 1) then - table.insert(result, subcommand) - end - end - return result - end, - desc = "Manage plugins. Subcommands: status, packer, lazy, builtin, clear" -}) - -return M diff --git a/common/nvim/lua/setup/plugins.lua b/common/nvim/lua/setup/plugins.lua deleted file mode 100755 index 0fb0886..0000000 --- a/common/nvim/lua/setup/plugins.lua +++ /dev/null @@ -1,609 +0,0 @@ --- plugins.lua - --- Helper to compare current Neovim version -local function version_at_least(minor, major) - local v = vim.version() - major = major or 0 - return v.major > major or (v.major == major and v.minor >= minor) -end - -local function version_below(minor, major) - local v = vim.version() - major = major or 0 - return v.major < major or (v.major == major and v.minor < minor) -end - --- Normalize version input: number -> {0, number}, table -> itself -local function parse_version(ver) - if type(ver) == "number" then return 0, ver end - if type(ver) == "table" then return ver[1] or 0, ver[2] or 0 end - return 0, 0 -end - --- Determine if plugin should be loaded based on version -local function should_load_plugin(min_version, max_version) - local min_major, min_minor = parse_version(min_version) - local max_major, max_minor = parse_version(max_version) - - local ok_min = not min_version or version_at_least(min_minor, min_major) - local ok_max = not max_version or version_below(max_minor, max_major) - - return ok_min and ok_max -end - --- Helper to check if a table contains a specific value -local function contains(table, val) - for _, v in ipairs(table) do - if v == val then - return true - end - end - return false -end - --- The master list of plugins with all potential options. --- Keys like 'lazy', 'event', 'keys', 'dependencies' are for Lazy.nvim. --- Keys like 'config', 'run', 'build' are for all managers. -local universal_plugins = { - -- Core - { "nvim-lua/plenary.nvim", lazy = true }, - { "lewis6991/impatient.nvim" }, - - { - "nvim-treesitter/nvim-treesitter", - min_version = 9, - event = "BufReadPre", - }, - { "nvim-treesitter/nvim-treesitter-textobjects", dependencies = { "nvim-treesitter/nvim-treesitter" } }, - { "nvim-treesitter/playground", cmd = "TSPlaygroundToggle" }, - - -- LSP - { "nvimtools/none-ls.nvim", event = "BufReadPre" }, - { "neovim/nvim-lspconfig", min_version = { 0, 9 }, event = "BufReadPre" }, - { - "mason-org/mason.nvim", - min_version = 10, - cmd = "Mason", - event = "BufReadPre", - }, - { "mason-org/mason-lspconfig.nvim", dependencies = { "mason-org/mason.nvim" } }, - { - "whoissethdaniel/mason-tool-installer.nvim", - dependencies = { "mason-org/mason.nvim" }, - event = "BufReadPre", - }, - { - "https://git.sr.ht/~whynothugo/lsp_lines.nvim", - name = 'lsp_lines.nvim', - config = function() - require("lsp_lines").setup() - vim.diagnostic.config({ - virtual_text = false, - }) - end, - event = "LspAttach", - }, - { "rmagatti/goto-preview", event = "LspAttach" }, - - -- Linters/Formatters - { "mhartington/formatter.nvim", event = "BufReadPre" }, - { - "jay-babu/mason-null-ls.nvim", - event = "BufReadPre", - }, - - -- Completion - { "hrsh7th/nvim-cmp", event = "InsertEnter", exclude = { "builtin" } }, - { "hrsh7th/cmp-nvim-lsp", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "hrsh7th/cmp-buffer", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "hrsh7th/cmp-path", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "hrsh7th/cmp-cmdline", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "petertriho/cmp-git", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "tamago324/cmp-zsh", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "f3fora/cmp-spell", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "hrsh7th/cmp-calc", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "saadparwaiz1/cmp_luasnip", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "hrsh7th/cmp-nvim-lsp-signature-help", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "rcarriga/cmp-dap", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "micangl/cmp-vimtex", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - - -- Snippets - { "L3MON4D3/LuaSnip", event = "InsertEnter" }, - { "rafamadriz/friendly-snippets", dependencies = { "L3MON4D3/LuaSnip" } }, - - -- Git - { "tpope/vim-fugitive", cmd = { "G", "Git", "Gdiffsplit" }, event = "VeryLazy" }, - { "kdheepak/lazygit.nvim", cmd = "LazyGit", keys = "<leader>gg" }, - { "lewis6991/gitsigns.nvim", min_version = 11, dependencies = { "nvim-lua/plenary.nvim" }, event = "BufReadPre" }, - - -- UI/UX & Enhancements - { "rcarriga/nvim-notify", lazy = false }, - { - "nvim-tree/nvim-tree.lua", - --cmd = { "NvimTreeToggle", "NvimTreeFocus", "NvimTreeFindFile" }, - --keys = { "<C-n>", "<leader>e" }, - lazy = false, - dependencies = { "nvim-tree/nvim-web-devicons"}, - config = function() - require("plugins.nvim-tree").setup() - end, - }, - { "ThePrimeagen/harpoon", keys = { "<leader>h" } }, - { "airblade/vim-rooter", event = "BufEnter" }, - { "ibhagwan/fzf-lua", cmd = "FzfLua" }, - - --- **Telescope** --- - { - "nvim-telescope/telescope.nvim", - dependencies = { "nvim-lua/plenary.nvim" }, - config = function() - require("plugins.telescope").setup() - end, - }, - { - "nvim-telescope/telescope-fzf-native.nvim", - build = "make", - cond = function() - return vim.fn.executable("make") == 1 - end, - dependencies = { "nvim-telescope/telescope.nvim" }, - }, - { "nvim-telescope/telescope-live-grep-args.nvim", dependencies = { "nvim-telescope/telescope.nvim" } }, - { "nvim-telescope/telescope-ui-select.nvim", dependencies = { "nvim-telescope/telescope.nvim" } }, - { "nvim-telescope/telescope-project.nvim", dependencies = { "nvim-telescope/telescope.nvim" } }, - { "nvim-telescope/telescope-media-files.nvim", dependencies = { "nvim-telescope/telescope.nvim" } }, - { "nvim-telescope/telescope-file-browser.nvim", dependencies = { "nvim-telescope/telescope.nvim" } }, - { "nvim-telescope/telescope-symbols.nvim", dependencies = { "nvim-telescope/telescope.nvim" } }, - { "nvim-telescope/telescope-dap.nvim", dependencies = { "nvim-telescope/telescope.nvim" } }, - { "axkirillov/telescope-changed-files", dependencies = { "nvim-telescope/telescope.nvim" } }, - { "smartpde/telescope-recent-files", dependencies = { "nvim-telescope/telescope.nvim" } }, - --- End Telescope --- - - -- Neovim UX - { "folke/neodev.nvim", ft = "lua" }, - { - "numToStr/Navigator.nvim", - lazy = false, - config = function() - require("Navigator").setup() - end, - }, - { "tpope/vim-eunuch", cmd = { "Rename", "Delete", "Mkdir" } }, - { "tpope/vim-unimpaired", lazy = true, event = "VeryLazy" }, - { "kylechui/nvim-surround", event = "VeryLazy" }, - { - "mbbill/undotree", - cmd = "UndotreeToggle", - keys = "<leader>u", - event = "BufReadPre" - }, - { - "myusuf3/numbers.vim", - event = "BufReadPost", - config = function() - vim.cmd("let g:numbers_exclude = ['dashboard']") - end, - }, - { "windwp/nvim-autopairs", event = "InsertEnter" }, - { "numToStr/Comment.nvim", keys = { "gc", "gb" }, event = "VeryLazy" }, - { "akinsho/toggleterm.nvim", cmd = { "ToggleTerm", "TermExec" } }, - { "tweekmonster/startuptime.vim", cmd = "StartupTime" }, - { "qpkorr/vim-bufkill", cmd = { "BD", "BUN" } }, - { - "ggandor/leap.nvim", - keys = { "s", "S" }, - event = "VeryLazy", - config = function() - require("leap").add_default_mappings() - end, - }, - { - "ggandor/flit.nvim", - keys = { "f", "F", "t", "T" }, - event = "VeryLazy", - config = function() - require("flit").setup() - end, - }, - { - "folke/which-key.nvim", - min_version = { 0, 10 }, - event = "VeryLazy", - --keys = "<leader>", - config = function() - require("which-key").setup() - end, - }, - { "folke/zen-mode.nvim", cmd = "ZenMode" }, - { "romainl/vim-cool", event = "VeryLazy" }, - { "antoinemadec/FixCursorHold.nvim", lazy = true }, - { "folke/trouble.nvim", cmd = { "Trouble", "TroubleToggle" } }, - - -- Colorschemes & Visuals (load immediately) - { "nyoom-engineering/oxocarbon.nvim", lazy = false, priority = 1000 }, - { "bluz71/vim-nightfly-guicolors", lazy = false, priority = 1000 }, - { "ayu-theme/ayu-vim", lazy = false, priority = 1000 }, - { "joshdick/onedark.vim", lazy = false, priority = 1000 }, - { "NTBBloodbath/doom-one.nvim", lazy = false, priority = 1000 }, - { "nyngwang/nvimgelion", lazy = false, priority = 1000 }, - { "projekt0n/github-nvim-theme", lazy = false, priority = 1000 }, - { "folke/tokyonight.nvim", lazy = false, priority = 1000 }, - { "ribru17/bamboo.nvim", lazy = false, priority = 1000 }, - - -- UI Enhancements - --{ "kyazdani42/nvim-web-devicons", lazy = true }, - { "nvim-tree/nvim-web-devicons", lazy = true }, - { "onsails/lspkind-nvim", dependencies = { "hrsh7th/nvim-cmp" }, exclude = { "builtin" } }, - { "kevinhwang91/nvim-ufo", dependencies = { "kevinhwang91/promise-async" }, event = "BufReadPre" }, - { - "luukvbaal/statuscol.nvim", - event = "WinNew", - config = function() - local builtin = require("statuscol.builtin") - require("statuscol").setup({ - relculright = true, - segments = { - { text = { builtin.foldfunc }, click = "v:lua.ScFa" }, - { text = { "%s" }, click = "v:lua.ScSa" }, - { text = { builtin.lnumfunc, " " }, click = "v:lua.ScLa" }, - }, - }) - end, - }, - { "lukas-reineke/indent-blankline.nvim", event = "BufReadPre" }, - { - "glepnir/dashboard-nvim", - dependencies = { "nvim-tree/nvim-web-devicons" }, - cmd = "Dashboard", - }, - { "karb94/neoscroll.nvim", event = "BufReadPre" }, - { "MunifTanjim/prettier.nvim", event = "BufWritePre" }, - { - "norcalli/nvim-colorizer.lua", - cmd = { "ColorizerToggle", "ColorizerAttachToBuffer" }, - config = function() - require("colorizer").setup({ - user_default_options = { - RGB = true, - RRGGBB = true, - names = false, - RRGGBBAA = false, - css = false, - css_fn = true, - mode = "foreground", - }, - }) - end, - }, - { "MunifTanjim/nui.nvim" }, - { "metakirby5/codi.vim", cmd = "Codi" }, - { - "kosayoda/nvim-lightbulb", - dependencies = { "antoinemadec/FixCursorHold.nvim" }, - event = "LspAttach", - }, - { "SmiteshP/nvim-navic", event = "LspAttach" }, - { - "rebelot/heirline.nvim", - event = "VeryLazy", - dependencies = { - "nvim-tree/nvim-web-devicons", -- For file icons - "lewis6991/gitsigns.nvim", -- For git status - }, - config = function() - -- Ensure gitsigns is loaded before Heirline - if package.loaded["gitsigns"] == nil then - require("gitsigns").setup() - end - local ok, heirline = pcall(require, "plugins.heirline") - if ok and heirline then - heirline.setup() - else - vim.notify("Failed to load Heirline configuration", vim.log.levels.ERROR) - end - end, - init = function() - -- Set up the statusline to use Heirline once it's loaded - vim.opt.statusline = "%{%v:lua.require'heirline'.eval_statusline()%}" - vim.opt.winbar = "%{%v:lua.require'heirline'.eval_winbar()%}" - vim.opt.tabline = "%{%v:lua.require'heirline'.eval_tabline()%}" - end, - }, - { - "samodostal/image.nvim", - config = function() - require("image").setup({}) - end, - ft = { "markdown" }, - }, - - -- Language Specific - { "simrat39/rust-tools.nvim", ft = "rust" }, - { - "saecki/crates.nvim", - dependencies = { "nvim-lua/plenary.nvim" }, - config = function() - require("crates").setup() - end, - ft = "rust", - }, - { - "akinsho/flutter-tools.nvim", - dependencies = { - "nvim-lua/plenary.nvim", - "stevearc/dressing.nvim", - }, - config = function() - require("flutter-tools").setup({ - debugger = { - enabled = true, - run_via_dap = true, - }, - }) - end, - ft = "dart", - }, - { - "iamcco/markdown-preview.nvim", - build = "cd app && npm install", - ft = "markdown", - config = function() - vim.g.mkdp_filetypes = { "markdown" } - vim.cmd("let g:mkdp_auto_close = 0") - end, - cmd = "MarkdownPreview", - }, - { - "ellisonleao/glow.nvim", - config = function() - local glow_path = vim.fn.executable("~/.local/bin/glow") == 1 and "~/.local/bin/glow" or "/usr/bin/glow" - require("glow").setup({ - style = "dark", - glow_path = glow_path, - }) - end, - ft = "markdown", - }, - - -- Debugging - { "mfussenegger/nvim-dap", event = "VeryLazy" }, - { "rcarriga/nvim-dap-ui", dependencies = { "mfussenegger/nvim-dap" }, cmd = "DapUI" }, - { "theHamsta/nvim-dap-virtual-text", dependencies = { "mfussenegger/nvim-dap" } }, - { "gabrielpoca/replacer.nvim", cmd = "Replacer" }, - { "jayp0521/mason-nvim-dap.nvim", dependencies = { "mason-org/mason.nvim" } }, - - -- Misc - { "rmagatti/auto-session", event = "VimEnter" }, - { "tpope/vim-sleuth", lazy = true }, - { "michaelb/sniprun", build = "bash ./install.sh", cmd = "SnipRun" }, - { "stevearc/overseer.nvim", cmd = "Overseer" }, - { - "nvim-neotest/neotest", - dependencies = { - "nvim-neotest/neotest-python", - "nvim-neotest/neotest-plenary", - "nvim-neotest/neotest-vim-test", - "nvim-neotest/nvim-nio", - }, - cmd = "Neotest", - }, - { "kawre/leetcode.nvim", cmd = "Leetcode" }, - { "m4xshen/hardtime.nvim", lazy = true }, - - -- LaTeX - { "lervag/vimtex", ft = "tex" }, -} - --- Helper function to detect current manager -local function detect_current_manager() - -- Check if we're currently using lazy (by checking if lazy module exists) - if package.loaded["lazy"] or package.loaded["lazy.core.util"] then - return "lazy" - end - - -- Check if we're currently using packer - if package.loaded["packer"] then - return "packer" - end - - -- Check for builtin manager - if vim.plugins and vim.plugins.spec then - return "builtin" - end - - return "unknown" -end - -local function format_for_lazy(plugin) - -- Lazy.nvim's format is the closest to our universal format, so we can - -- largely just copy the table, with some specific adjustments. - local new_plugin = vim.deepcopy(plugin) - - -- Lazy.nvim uses `dependencies` key for dependencies, not `requires` - if new_plugin.requires then - new_plugin.dependencies = new_plugin.requires - new_plugin.requires = nil - end - - -- Change 'as' to 'name' for lazy - if new_plugin.as then - new_plugin.name = new_plugin.as - new_plugin.as = nil - end - - -- Change 'run' to 'build' for lazy - if new_plugin.run then - new_plugin.build = new_plugin.run - new_plugin.run = nil - end - - return new_plugin -end - -local function format_for_packer(plugin) - -- For Packer, we need to remove lazy-loading keys to force eager loading - local new_plugin = vim.deepcopy(plugin) - - -- Convert dependencies back to requires for packer - if new_plugin.dependencies then - new_plugin.requires = new_plugin.dependencies - new_plugin.dependencies = nil - end - - -- Convert name back to as for packer - if new_plugin.name then - new_plugin.as = new_plugin.name - new_plugin.name = nil - end - - -- Convert build back to run for packer - if new_plugin.build then - new_plugin.run = new_plugin.build - new_plugin.build = nil - end - - -- Remove lazy-loading keys to force eager loading in packer - new_plugin.event = nil - new_plugin.keys = nil - new_plugin.cmd = nil - new_plugin.ft = nil - new_plugin.lazy = nil - - return new_plugin -end - -local function format_for_builtin(plugin) - -- This function is now simplified, as the main loop handles flattening - local new_plugin = vim.deepcopy(plugin) - - -- Convert GitHub shorthand to full URL if needed - if type(new_plugin) == "string" then - if new_plugin:match("^[%w%-_%.]+/[%w%-_%.]+$") then - return { - src = "https://github.com/" .. new_plugin, - name = new_plugin:match("/([%w%-_%.]+)$") - } - else - return { src = new_plugin } - end - end - - -- Handle table format - if new_plugin[1] and type(new_plugin[1]) == "string" then - local repo = new_plugin[1] - if repo:match("^[%w%-_%.]+/[%w%-_%.]+$") then - new_plugin.src = "https://github.com/" .. repo - new_plugin.name = new_plugin.name or new_plugin.as or repo:match("/([%w%-_%.]+)$") - else - new_plugin.src = repo - end - new_plugin[1] = nil -- Remove positional argument - end - - -- Convert url to src if present - if new_plugin.url then - new_plugin.src = new_plugin.url - new_plugin.url = nil - end - - -- Convert 'as' to 'name' - if new_plugin.as then - new_plugin.name = new_plugin.as - new_plugin.as = nil - end - - -- Only keep the keys that vim.pack uses: src, name, and version - new_plugin.dependencies = nil - new_plugin.config = nil - new_plugin.build = nil - new_plugin.run = nil - new_plugin.cond = nil - new_plugin.min_version = nil - new_plugin.max_version = nil - new_plugin.lazy = nil - new_plugin.priority = nil - new_plugin.event = nil - new_plugin.keys = nil - new_plugin.cmd = nil - new_plugin.ft = nil - new_plugin.requires = nil - - return new_plugin -end - --- Detect which manager is currently active and format plugins accordingly -local current_manager = detect_current_manager() -local plugins_to_process = {} -local processed_plugins = {} -- Use a set to avoid duplicates - --- Flatten the plugin list for the builtin manager -if current_manager == "builtin" then - local function get_plugin_name(plugin) - if type(plugin) == "string" then - return plugin:match("/([%w%-_%.]+)$") or plugin - elseif type(plugin) == "table" then - -- Get name from 'name', 'as', or from the src/url - return plugin.name or plugin.as or (type(plugin[1]) == "string" and plugin[1]:match("/([%w%-_%.]+)$")) or - plugin.url:match("/([%w%-_%.]+)$") - end - end - - local function add_to_process(plugin) - local name = get_plugin_name(plugin) - if name and not processed_plugins[name] then - table.insert(plugins_to_process, plugin) - processed_plugins[name] = true - end - end - - for _, plugin in ipairs(universal_plugins) do - add_to_process(plugin) - if plugin.dependencies then - for _, dep in ipairs(plugin.dependencies) do - add_to_process(dep) - end - end - if plugin.requires then - for _, req in ipairs(plugin.requires) do - add_to_process(req) - end - end - end -else - plugins_to_process = universal_plugins -end - -local finalized_plugins = {} - -for _, plugin in ipairs(plugins_to_process) do - local cond_ok = true - - -- Check for the new 'exclude' option first - if plugin.exclude and contains(plugin.exclude, current_manager) then - cond_ok = false - end - - if cond_ok and (plugin.min_version or plugin.max_version) then - cond_ok = should_load_plugin(plugin.min_version, plugin.max_version) - end - if cond_ok and plugin.cond then - cond_ok = plugin.cond() - end - - if cond_ok then - local new_plugin - if current_manager == "lazy" then - new_plugin = format_for_lazy(plugin) - elseif current_manager == "packer" then - new_plugin = format_for_packer(plugin) - elseif current_manager == "builtin" then - new_plugin = format_for_builtin(plugin) - else - -- Default to lazy format if manager is unknown - new_plugin = format_for_lazy(plugin) - end - table.insert(finalized_plugins, new_plugin) - end -end - -return finalized_plugins |
