diff --git a/flake.lock b/flake.lock index df9abf5..93af7df 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1761605067, - "narHash": "sha256-XlXxfbRET+JrBLnnknmlO6rEazTe/S4Nycnkls6Oe0Q=", + "lastModified": 1761619080, + "narHash": "sha256-PsLFmU/CORWeCjJi9ALsegwr/SMjf2gHsooTR09az4c=", "owner": "nixos", "repo": "nixpkgs", - "rev": "8929c5ea8ff351a777bc983b0b8e0a46587e6909", + "rev": "fd644bba1d3a83169e4b312ce20928ba1b0abb02", "type": "github" }, "original": { @@ -495,22 +495,6 @@ "type": "github" } }, - "nvim_plugin-nosduco/remote-sshfs.nvim": { - "flake": false, - "locked": { - "lastModified": 1759193354, - "narHash": "sha256-FfUxpRfqrf0r56/gi76N2ZooWnXWO0aRtaQBS7m+SvY=", - "owner": "nosduco", - "repo": "remote-sshfs.nvim", - "rev": "45502b3892774811153aeab5f7f9b0033c82005c", - "type": "github" - }, - "original": { - "owner": "nosduco", - "repo": "remote-sshfs.nvim", - "type": "github" - } - }, "nvim_plugin-numToStr/Comment.nvim": { "flake": false, "locked": { @@ -928,7 +912,6 @@ "nvim_plugin-mfussenegger/nvim-lint": "nvim_plugin-mfussenegger/nvim-lint", "nvim_plugin-mrcjkb/rustaceanvim": "nvim_plugin-mrcjkb/rustaceanvim", "nvim_plugin-neovim/nvim-lspconfig": "nvim_plugin-neovim/nvim-lspconfig", - "nvim_plugin-nosduco/remote-sshfs.nvim": "nvim_plugin-nosduco/remote-sshfs.nvim", "nvim_plugin-numToStr/Comment.nvim": "nvim_plugin-numToStr/Comment.nvim", "nvim_plugin-nvim-lua/plenary.nvim": "nvim_plugin-nvim-lua/plenary.nvim", "nvim_plugin-nvim-lualine/lualine.nvim": "nvim_plugin-nvim-lualine/lualine.nvim", @@ -963,11 +946,11 @@ ] }, "locked": { - "lastModified": 1761532837, - "narHash": "sha256-78mCSQgC/a6/0vWYrvE/g9E3gGsJLyBBGtmHe3ZOLG4=", + "lastModified": 1761619008, + "narHash": "sha256-vp97eNmi5GG/+jlvnBpmG6EVO2F1+nqMQFF9GT2TIQg=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "4f5f89f1cfd8553b1285a4a0879ea1b2b05ad286", + "rev": "7bc7d2f706ebe5479d230d2c6806b5dc757ae4cd", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 348e44b..6c23573 100644 --- a/flake.nix +++ b/flake.nix @@ -126,8 +126,8 @@ "nvim_plugin-rafamadriz/friendly-snippets".flake = false; "nvim_plugin-ron-rs/ron.vim".url = "github:ron-rs/ron.vim"; "nvim_plugin-ron-rs/ron.vim".flake = false; - "nvim_plugin-nosduco/remote-sshfs.nvim".url = "github:nosduco/remote-sshfs.nvim"; - "nvim_plugin-nosduco/remote-sshfs.nvim".flake = false; + # "nvim_plugin-nosduco/remote-sshfs.nvim".url = "github:nosduco/remote-sshfs.nvim"; + # "nvim_plugin-nosduco/remote-sshfs.nvim".flake = false; }; outputs = { @@ -141,7 +141,7 @@ # work then we make a new version name. Helps separate any files and # "version" my neovim flake. Use this name for custom .config location # ================== - version = "hydrogen"; + version = "helium"; # =================== # Utilities @@ -170,44 +170,6 @@ "nvim_plugin-nvim-treesitter/nvim-treesitter" = nvim-treesitter.withAllGrammars; }; - # avante-nvim-lib = pkgs.rustPlatform.buildRustPackage { - # pname = "avante-nvim-lib"; - # version = "0.0.0"; - # src = inputs."nvim_plugin-yetone/avante.nvim"; - # - # buildFeatures = [ "luajit" ]; - # doCheck = false; - # cargoLock = { - # lockFile = inputs."nvim_plugin-yetone/avante.nvim" + "/Cargo.lock"; - # allowBuiltinFetchGit = true; - # }; - # - # nativeBuildInputs = with pkgs; [ - # pkg-config - # ]; - # - # buildInputs = with pkgs; [ - # openssl.dev - # ]; - # env = { - # OPENSSL_NO_VENDOR = "1"; - # OPENSSL_LIB_DIR = "${pkgs.openssl.out}/lib"; - # OPENSSL_INCLUDE_DIR = "${pkgs.openssl.dev}/include"; - # OPENSSL_DIR = "${pkgs.openssl.dev}"; - # }; - # postInstall = '' - # # mv $out/lib/libavante_repo_map.so $out/lib/avante_repo_map.so - # for f in $out/lib/lib*; do - # mv "$f" "$out/lib/''${f##*/lib}" - # done - # ''; - # meta = { - # description = "Avante nvim libraries"; - # homepage = "https://github.com/yetone/avante.nvim"; - # license = pkgs.lib.licenses.asl20; - # }; - # }; - # This will be how we put any nix related stuff into our lua config luaNixGlobal = "NIX=" @@ -226,59 +188,12 @@ (builtins.filter (n: builtins.substring 0 12 n == "nvim_plugin-") (builtins.attrNames inputs)); }); - # These are appended at the start of the path so that they take precedence over local install tools + # All runtime dependencies are now optional and checked lazily by plugins + # This keeps the neovim flake lean and allows project devShells to provide tools runtimeDependencies = with pkgs; [ - # tools - ripgrep # search - fd # search - fzf # search fuzzy - tree-sitter - glow # markdown renderer - curl # http requests - sshfs # remote dev for nosduco/remote-sshfs.nvim - # nodePackages.cspell TODO check out `typos` rust checker instead? - ]; - - # These are appended at the end of the PATH so any local installed tools will take precedence - defaultRuntimeDependencies = with pkgs; [ - # linters - markdownlint-cli - biome # (t|s)j[x] - # formatters - stylua - nixfmt-rfc-style - nodePackages.prettier - rustywind - markdownlint-cli2 - sql-formatter - libsForQt5.qt5.qtdeclarative # qmlformat - # LSPs - # python312Packages.tiktoken # needed for copilot chat - nil # nix - lua-language-server - vscode-langservers-extracted # HTML/CSS/JSON/ESLint - nodePackages.typescript-language-server - nodePackages.svelte-language-server - tailwindcss-language-server - python312Packages.python-lsp-server - rust-analyzer - marksman # markdown - taplo # toml - yaml-language-server - lemminx # xml - gopls # go - # ocamlPackages.ocaml-lsp # ocaml - # Other - typescript - nodejs_24 - clang - # zig - (pkgs.rust-bin.stable.latest.default.override { - extensions = [ - "rust-src" - "rust-analyzer" - ]; - }) + ripgrep # search - core to telescope, checked in telescope.lua init + fd # file finding - improves telescope performance, checked in telescope.lua init + tree-sitter # highlighting ]; in @@ -299,16 +214,13 @@ generatedWrapperArgs = old.generatedWrapperArgs or [ ] ++ [ - # Add runtime dependencies to neovim path - "--prefix" - "PATH" - ":" - "${lib.makeBinPath runtimeDependencies}" - # Some we will suffix so we pick up the local dev shell intead and default to these otherwise + # Add minimal runtime dependencies to neovim path + # Most tools are now optional and checked at runtime + # Project devShells take precedence via --suffix "--suffix" "PATH" ":" - "${lib.makeBinPath defaultRuntimeDependencies}" + "${lib.makeBinPath runtimeDependencies}" ] ++ [ # Set the LAZY env path to the nix store, see init.lua for how it is used diff --git a/lua/plugins/conform_formatter.lua b/lua/plugins/conform_formatter.lua index 7694bba..7524c14 100644 --- a/lua/plugins/conform_formatter.lua +++ b/lua/plugins/conform_formatter.lua @@ -52,14 +52,17 @@ return { "stevearc/conform.nvim", opts = { -- https://github.com/stevearc/conform.nvim?tab=readme-ov-file#setup + -- conform.nvim will notify if formatters are missing when format is attempted notify_on_error = true, + notify_no_formatters = true, formatters = { -- v_fmt = { -- command = "v", -- args = { "fmt" }, -- }, }, - -- Note that all these need to be available at runtime, add them to flake.nix#runtimeDependencies + -- Formatters are checked lazily on format attempt + -- conform.nvim will show errors if formatters are missing formatters_by_ft = { sql = { "sql_formatter", lsp_format = "first" }, lua = { "stylua", lsp_format = "first" }, diff --git a/lua/plugins/lint.lua b/lua/plugins/lint.lua index 4185f9a..aa96bc3 100644 --- a/lua/plugins/lint.lua +++ b/lua/plugins/lint.lua @@ -121,7 +121,7 @@ return { names = vim.tbl_filter(function(name) local linter = lint.linters[name] if not linter then - LazyVim.warn("Linter not found: " .. name, { title = "nvim-lint" }) + vim.notify("Linter not found: " .. name, vim.log.levels.WARN) end return linter and not (type(linter) == "table" and linter.condition and not linter.condition(ctx)) end, names) diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index c4b0cdb..6392ecb 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -219,7 +219,16 @@ return { for _, server_name in ipairs(lsp_servers) do local server_opts = servers[server_name] or {} vim.lsp.config(server_name, server_opts) - vim.lsp.enable(server_name) + -- Try to enable LSP and show helpful error if server not found + local ok, err = pcall(function() + vim.lsp.enable(server_name) + end) + if not ok then + vim.notify( + string.format("LSP '%s' failed to start. Install it in your project devShell.\nError: %s", server_name, err), + vim.log.levels.ERROR + ) + end end else -- TODO test this out on a non nix setup... diff --git a/lua/plugins/markdown_glow.lua b/lua/plugins/markdown_glow.lua index dfea216..cbe0a79 100644 --- a/lua/plugins/markdown_glow.lua +++ b/lua/plugins/markdown_glow.lua @@ -4,6 +4,17 @@ return { default_type = "keep", }, cmd = "Glow", + config = function(_, opts) + -- Check for glow when plugin is first used + if not U.cmd_executable("glow") then + vim.notify( + "'glow' not found on PATH. Install it to use markdown preview.", + vim.log.levels.ERROR + ) + return + end + require("glow").setup(opts) + end, keys = { { ",m", "Glow", desc = "Markdown preview" }, }, diff --git a/lua/plugins/remote-sshfs.lua b/lua/plugins/remote-sshfs.lua deleted file mode 100644 index ae93bcf..0000000 --- a/lua/plugins/remote-sshfs.lua +++ /dev/null @@ -1,17 +0,0 @@ -return { - "nosduco/remote-sshfs.nvim", - cmd = { - "RemoteSshfs", - "RemoteSSHFSConnect", - "RemoteSSHFSDisconnect", - "RemoteSSHFSEdit", - "RemoteSSHFSFindFiles", - "RemoteSSHFSLiveGrep", - }, - dependencies = { "nvim-telescope/telescope.nvim" }, - opts = {}, - config = function(_, opts) - require("remote-sshfs").setup(opts) - require("telescope").load_extension("remote-sshfs") - end, -} diff --git a/lua/plugins/telescope.lua b/lua/plugins/telescope.lua index cda1219..fcf10c8 100644 --- a/lua/plugins/telescope.lua +++ b/lua/plugins/telescope.lua @@ -7,11 +7,17 @@ return { { "aznhe21/actions-preview.nvim", event = "VeryLazy" }, }, init = function() + -- Check for essential telescope tools U.cmd_executable("rg", { [false] = function() - vim.notify("rg not installed, live grep will not function.", 2) + vim.notify("'rg' (ripgrep) not found. Required for telescope live grep. Install it in your environment.", vim.log.levels.ERROR) end, }) + + -- fd is optional but improves file finding performance + if not U.cmd_executable("fd") then + vim.notify("'fd' not found. Telescope will use 'find' instead (slower). Consider installing fd.", vim.log.levels.INFO) + end end, cmd = "Telescope", opts = function() diff --git a/lua/plugins_disabled/remote-sshfs.lua b/lua/plugins_disabled/remote-sshfs.lua new file mode 100644 index 0000000..1ba6dd3 --- /dev/null +++ b/lua/plugins_disabled/remote-sshfs.lua @@ -0,0 +1,33 @@ +return { + "nosduco/remote-sshfs.nvim", + init = function() + -- Check if sshfs is available + if not U.cmd_executable("sshfs") then + vim.notify( + "'sshfs' not found on PATH. Required for RemoteSSHFS commands", + vim.log.levels.INFO + ) + end + end, + cmd = { + "RemoteSshfs", + "RemoteSSHFSConnect", + "RemoteSSHFSDisconnect", + "RemoteSSHFSEdit", + "RemoteSSHFSFindFiles", + "RemoteSSHFSLiveGrep", + }, + dependencies = { "nvim-telescope/telescope.nvim" }, + opts = {}, + config = function(_, opts) + -- Check for sshfs when plugin is first used + if not U.cmd_executable("sshfs") then + vim.notify( + "'sshfs' not found on PATH. Install it to use RemoteSSHFS commands.", + vim.log.levels.ERROR + ) + end + require("remote-sshfs").setup(opts) + require("telescope").load_extension("remote-sshfs") + end, +} diff --git a/lua/util.lua b/lua/util.lua index a399d2e..5c19a46 100644 --- a/lua/util.lua +++ b/lua/util.lua @@ -38,6 +38,23 @@ function M.cmd_executable(cmd, callback) return executable end +-- Check if command exists and show helpful error if not +-- @param cmd string: The command to check for +-- @param feature_name string: Human-readable description of what needs this command +-- @param level number: vim.log.levels (ERROR, WARN, INFO, etc.) - defaults to ERROR +-- @return boolean: true if command exists, false otherwise +function M.require_cmd(cmd, feature_name, level) + level = level or vim.log.levels.ERROR + if vim.fn.executable(cmd) ~= 1 then + vim.notify( + string.format("'%s' not found on PATH. Required for: %s", cmd, feature_name), + level + ) + return false + end + return true +end + -- [1]: (string) lhs (required) -- [2]: (string|fun()) rhs (optional) -- mode: (string|string[]) mode (optional, defaults to "n")