diff --git a/.github/workflows/install_test.yaml b/.github/workflows/install_test.yaml index 046e635..fd3f219 100644 --- a/.github/workflows/install_test.yaml +++ b/.github/workflows/install_test.yaml @@ -20,16 +20,21 @@ jobs: - name: Checkout repo uses: actions/checkout@v4 + - name: Install Neovim + uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: stable + - name: Install dependencies run: | sudo apt-get update -qq - sudo apt-get install -y git curl nodejs npm ripgrep fd-find - - - name: Install Neovim - run: | - curl -LO https://github.com/neovim/neovim/releases/download/stable/nvim-linux-x86_64.tar.gz - sudo tar -xzf nvim-linux-x86_64.tar.gz -C /usr/local --strip-components=1 - rm nvim-linux-x86_64.tar.gz + sudo apt-get install -y git nodejs npm ripgrep + sudo apt-get install -y fd-find + sudo ln -sf /usr/bin/fdfind /usr/local/bin/fd - name: Install test run: make test-install NVIM_TEST_DIR=/tmp/nvim-test + + - name: Functional test + run: make test-functional NVIM_TEST_DIR=/tmp/nvim-test diff --git a/Makefile b/Makefile index e056a45..77d9d80 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: clean test-headless test-install clean-install-test +.PHONY: clean test-headless test-install test-functional clean-install-test NVIM ?= nvim NVIM_DATA ?= $(HOME)/.local/share/nvim @@ -26,5 +26,12 @@ test-install: XDG_STATE_HOME=$(NVIM_TEST_DIR)/state \ $(NVIM) --headless +qa +test-functional: + XDG_CONFIG_HOME=$(NVIM_TEST_DIR)/config \ + XDG_DATA_HOME=$(NVIM_TEST_DIR)/data \ + XDG_CACHE_HOME=$(NVIM_TEST_DIR)/cache \ + XDG_STATE_HOME=$(NVIM_TEST_DIR)/state \ + $(NVIM) --headless "+lua require('aniseed.fennel').impl().dofile('tests/headless.fnl')" "+cquit! 1" + clean-install-test: rm -rf $(NVIM_TEST_DIR) diff --git a/fnl/mods/tools/oil.fnl b/fnl/mods/tools/oil.fnl new file mode 100644 index 0000000..cd12c68 --- /dev/null +++ b/fnl/mods/tools/oil.fnl @@ -0,0 +1,6 @@ +(module mods.tools.oil {autoload {oil oil}}) + +(oil.setup {:default_file_explorer true + :view_options {:show_hidden true}}) + +(map [:n] :- oil.open {:desc "Open parent directory (oil)"}) diff --git a/fnl/mods/tools/telescope.fnl b/fnl/mods/tools/telescope.fnl index 001442d..6007468 100644 --- a/fnl/mods/tools/telescope.fnl +++ b/fnl/mods/tools/telescope.fnl @@ -104,13 +104,19 @@ (merge-table ivy_config {:severity :error :prompt_title "Workspace Errors"})) +(defn buffer-dir [] + "utils.buffer_dir, but oil:// buffers resolve to the directory they show" + (let [(ok oil) (pcall require :oil) + dir (and ok (oil.get_current_dir))] + (if dir (vim.fs.normalize dir) (utils.buffer_dir)))) + (fn with-count [f opts?] (fn [args] (var opts (or opts? {})) (var back "") (for [i 1 vim.v.count] ;; h v:count (set back (.. back "/.."))) - (var cwd (vim.fn.resolve (.. (utils.buffer_dir) back))) + (var cwd (vim.fn.resolve (.. (buffer-dir) back))) (var relwd (cwd:gsub (os.getenv :HOME) :$HOME)) (f (merge-table (merge-table ivy_config {: cwd @@ -371,7 +377,7 @@ (var magic (fn [_opts] (var opts (deep-copy (or _opts {}))) - (var cwd (utils.buffer_dir)) + (var cwd (buffer-dir)) (tset opts :fcmd_depth 4) (tset opts :cwd cwd) (tset opts :mode (or (. opts :mode) :files)) diff --git a/fnl/plugins.fnl b/fnl/plugins.fnl index 1b76ef4..043ebdb 100644 --- a/fnl/plugins.fnl +++ b/fnl/plugins.fnl @@ -48,11 +48,13 @@ (let [name (. packs i) opts (. packs (+ i 1))] (table.insert specs (to-lazy-spec name opts)))) - (bootstrap-lazy) (let [lazy (safe-require :lazy)] (when lazy - (lazy.setup specs {:ui {:border :rounded}}))))) + ;; disable rtp reset: lazy's reset guesses lib64 over lib/nvim, + ;; dropping bundled treesitter parsers on some distros + (lazy.setup specs + {:ui {:border :rounded} :performance {:rtp {:reset false}}}))))) ;; setup is used for inline setup for modules that require no or {} arg @@ -70,94 +72,105 @@ :Olical/aniseed {} ;; colorschemes — eager so the theme is applied at startup :NLKNguyen/papercolor-theme {} :fedemengo/github-nvim-theme {} - :catppuccin/nvim {} :AlexvZyl/nordic.nvim {} - :loctvl842/monokai-pro.nvim {:mod :ui.monokai} + :catppuccin/nvim {} :AlexvZyl/nordic.nvim {} :loctvl842/monokai-pro.nvim + {:mod :ui.monokai} ;; ui chrome — eager (statusline/tabline/navic must be ready before first render) - :nvim-lualine/lualine.nvim {} - :arkav/lualine-lsp-progress {:mod :ui.lualine} - :akinsho/bufferline.nvim {:requires [[:nvim-tree/nvim-web-devicons]] :mod :ui.tab} - :SmiteshP/nvim-navic {} - :nvim-focus/focus.nvim {:mod :ui.focus} - :goolord/alpha-nvim {:mod :ui.alpha} - :rcarriga/nvim-notify {:mod :ui.notify} + :nvim-lualine/lualine.nvim {} :arkav/lualine-lsp-progress + {:mod :ui.lualine} :akinsho/bufferline.nvim + {:requires [[:nvim-tree/nvim-web-devicons]] :mod :ui.tab} + :SmiteshP/nvim-navic {} :nvim-focus/focus.nvim {:mod :ui.focus} + :goolord/alpha-nvim {:mod :ui.alpha} :rcarriga/nvim-notify + {:mod :ui.notify} ;; motion / text-objects — eager so they work from keystroke 1 - :ggandor/leap.nvim {:url "https://codeberg.org/andyg/leap.nvim" :mod :tools.leap} + :ggandor/leap.nvim {:url "https://codeberg.org/andyg/leap.nvim" + :mod :tools.leap} :wellle/targets.vim {} ;; which-key — eager so every keymap registers its description :folke/which-key.nvim {:mod :tools.which-key} + ;; file explorer — eager so oil takes over directory buffers (netrw) + :stevearc/oil.nvim {:requires [[:nvim-tree/nvim-web-devicons]] + :mod :tools.oil} ;; lsp + completion — eager (attach on BufRead handled internally) :VonHeikemen/lsp-zero.nvim {:requires [[:neovim/nvim-lspconfig] - [:williamboman/mason.nvim] - [:williamboman/mason-lspconfig.nvim] - [:jay-babu/mason-null-ls.nvim] - [:nvimtools/none-ls.nvim]] - :mod :lsp.lsp} - :saghen/blink.lib {} - :saghen/blink.cmp {:run (fn [] (: ((. (require :blink.cmp) :build)) :pwait)) - :requires [[:giuxtaposition/blink-cmp-copilot] - [:saghen/blink.lib]] - :mod :lsp.blink} - :ray-x/lsp_signature.nvim {} - :wakatime/vim-wakatime {} - ;; treesitter — eager (syntax highlight needed immediately) + [:williamboman/mason.nvim] + [:williamboman/mason-lspconfig.nvim] + [:jay-babu/mason-null-ls.nvim] + [:nvimtools/none-ls.nvim]] + :mod :lsp.lsp} + :saghen/blink.lib {} :saghen/blink.cmp + {:run (fn [] + (: ((. (require :blink.cmp) :build)) :pwait)) + :requires [[:giuxtaposition/blink-cmp-copilot] [:saghen/blink.lib]] + :mod :lsp.blink} :ray-x/lsp_signature.nvim {} :wakatime/vim-wakatime + {} ;; treesitter — eager (syntax highlight needed immediately) :nvim-treesitter/nvim-treesitter {:run ":TSUpdate" :mod :tools.treesitter} ;; copilot — defer until insert mode :zbirenbaum/copilot.lua {:event :InsertEnter :mod :dev.copilot} ;; insert-mode only - :windwp/nvim-autopairs {:event :InsertEnter} - :jdhao/better-escape.vim {:event :InsertEnter :mod :tools.better-escape} + :windwp/nvim-autopairs {:event :InsertEnter} :jdhao/better-escape.vim + {:event :InsertEnter :mod :tools.better-escape} ;; buffer decorations — load once a file is open - :lewis6991/gitsigns.nvim {:event [:BufRead :BufNewFile] :mod :tools.gitsigns} - :RRethy/vim-illuminate {:event :LspAttach :mod :tools.illuminate} - :kevinhwang91/nvim-hlslens {:event [:BufRead :BufNewFile] :mod :ui.hlslens} - :lukas-reineke/indent-blankline.nvim {:event [:BufRead :BufNewFile] :mod :ui.indentblank :main :ibl} - :catgoose/nvim-colorizer.lua {:event [:BufRead :BufNewFile] :mod :ui.colorizer} - :karb94/neoscroll.nvim {:event [:BufRead :BufNewFile] :mod :ui.neoscroll} - :petertriho/nvim-scrollbar {:event [:BufRead :BufNewFile] :mod :ui.scrollbar} - :folke/todo-comments.nvim {:event [:BufRead :BufNewFile] - :requires [[:nvim-lua/plenary.nvim]] - :mod :tools.todo-comments} - :MeanderingProgrammer/render-markdown.nvim {:ft [:markdown :Avante] :mod :ui.render-markdown} - ;; filetype-specific + :lewis6991/gitsigns.nvim + {:event [:BufRead :BufNewFile] :mod :tools.gitsigns} :RRethy/vim-illuminate + {:event :LspAttach :mod :tools.illuminate} :kevinhwang91/nvim-hlslens + {:event [:BufRead :BufNewFile] :mod :ui.hlslens} + :lukas-reineke/indent-blankline.nvim + {:event [:BufRead :BufNewFile] :mod :ui.indentblank :main :ibl} + :catgoose/nvim-colorizer.lua + {:event [:BufRead :BufNewFile] :mod :ui.colorizer} :karb94/neoscroll.nvim + {:event [:BufRead :BufNewFile] :mod :ui.neoscroll} + :petertriho/nvim-scrollbar + {:event [:BufRead :BufNewFile] :mod :ui.scrollbar} + :folke/todo-comments.nvim + {:event [:BufRead :BufNewFile] + :requires [[:nvim-lua/plenary.nvim]] + :mod :tools.todo-comments} :MeanderingProgrammer/render-markdown.nvim + {:ft [:markdown :Avante] :mod :ui.render-markdown} ;; filetype-specific :ray-x/go.nvim {:ft [:go :gomod :gowork] :mod :dev.go_nvim} :Julian/lean.nvim {:ft [:lean] - :requires [[:neovim/nvim-lspconfig]] - :mod :dev.lean} - ;; commands + :requires [[:neovim/nvim-lspconfig]] + :mod :dev.lean} ;; commands :folke/trouble.nvim {:cmd [:Trouble :TroubleToggle] :mod :tools.trouble} - :folke/zen-mode.nvim {:cmd :ZenMode :mod :ui.zenmode} - :hedyhli/outline.nvim {:cmd :Outline :mod :lsp.symbols} - :esmuellert/codediff.nvim {:cmd :CodeDiff :mod :tools.codediff} - :numToStr/FTerm.nvim {:cmd :FTerm :mod :tools.fterm} + :folke/zen-mode.nvim {:cmd :ZenMode :mod :ui.zenmode} :hedyhli/outline.nvim + {:cmd :Outline :mod :lsp.symbols} :esmuellert/codediff.nvim + {:cmd :CodeDiff :mod :tools.codediff} :numToStr/FTerm.nvim + {:cmd :FTerm :mod :tools.fterm} ;; deferred — load after startup, before first user input - :nvim-telescope/telescope.nvim {:event :VeryLazy - :requires [[:nvim-lua/popup.nvim] [:nvim-lua/plenary.nvim]] - :mod :tools.telescope} - :nvim-telescope/telescope-fzf-native.nvim {:run :make} - :nvim-telescope/telescope-media-files.nvim {} + :nvim-telescope/telescope.nvim + {:event :VeryLazy + :requires [[:nvim-lua/popup.nvim] [:nvim-lua/plenary.nvim]] + :mod :tools.telescope} :nvim-telescope/telescope-fzf-native.nvim + {:run :make} :nvim-telescope/telescope-media-files.nvim {} :sopa0/telescope-makefile {:requires [[:akinsho/toggleterm.nvim]]} - :ruifm/gitlinker.nvim {:event :VeryLazy :requires [[:nvim-lua/plenary.nvim]] :mod :dev.gitlinker} + :ruifm/gitlinker.nvim {:event :VeryLazy + :requires [[:nvim-lua/plenary.nvim]] + :mod :dev.gitlinker} :Vonr/align.nvim {:event :VeryLazy :mod :tools.align} :folke/persistence.nvim {:event :VeryLazy :mod :tools.persistence} :stevearc/profile.nvim {:event :VeryLazy :mod :dev.profile} :yetone/avante.nvim {:event :VeryLazy - :requires [[:nvim-treesitter/nvim-treesitter] - [:HakonHarnes/img-clip.nvim] - [:stevearc/dressing.nvim] - [:nvim-lua/plenary.nvim] - [:MunifTanjim/nui.nvim] - [:nvim-tree/nvim-web-devicons]] - :run :make - :mod :dev.avante} + :requires [[:nvim-treesitter/nvim-treesitter] + [:HakonHarnes/img-clip.nvim] + [:stevearc/dressing.nvim] + [:nvim-lua/plenary.nvim] + [:MunifTanjim/nui.nvim] + [:nvim-tree/nvim-web-devicons]] + :run :make + :mod :dev.avante} ;; dap — load on debug commands - :mfussenegger/nvim-dap {:cmd [:DapContinue :DapToggleBreakpoint :DapNew :DapStepOver :DapStepInto]} - :mfussenegger/nvim-dap-python {:ft :python :requires [[:mfussenegger/nvim-dap]]} - :rcarriga/nvim-dap-ui {:cmd [:DapContinue :DapToggleBreakpoint] - :requires [[:mfussenegger/nvim-dap] [:nvim-neotest/nvim-nio]]} - :jay-babu/mason-nvim-dap.nvim {:cmd [:DapContinue :DapToggleBreakpoint] - :requires [[:williamboman/mason.nvim] [:mfussenegger/nvim-dap]] - :mod :dev.dap} - ;; misc + :mfussenegger/nvim-dap {:cmd [:DapContinue + :DapToggleBreakpoint + :DapNew + :DapStepOver + :DapStepInto]} + :mfussenegger/nvim-dap-python + {:ft :python :requires [[:mfussenegger/nvim-dap]]} :rcarriga/nvim-dap-ui + {:cmd [:DapContinue :DapToggleBreakpoint] + :requires [[:mfussenegger/nvim-dap] [:nvim-neotest/nvim-nio]]} + :jay-babu/mason-nvim-dap.nvim + {:cmd [:DapContinue :DapToggleBreakpoint] + :requires [[:williamboman/mason.nvim] [:mfussenegger/nvim-dap]] + :mod :dev.dap} ;; misc :gruvw/strudel.nvim {:run "npm install" :mod :misc.strudel}) (map [:n] :pi ":Lazy install" {:desc "Install plugins"}) diff --git a/lazy-lock.json b/lazy-lock.json index 0974a9d..5757ea0 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -18,10 +18,9 @@ "gitsigns.nvim": { "branch": "main", "commit": "25050e4ed39e628282831d4cbecb1850454ce915" }, "go.nvim": { "branch": "master", "commit": "0768d79bbebdb1a112a845f9cd6293bfbd544dab" }, "img-clip.nvim": { "branch": "main", "commit": "b6ddfb97b5600d99afe3452d707444afda658aca" }, - "impatient.nvim": { "branch": "main", "commit": "47302af74be7b79f002773011f0d8e85679a7618" }, "indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" }, "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, - "lean.nvim": { "branch": "main", "commit": "0773e20595bbfa79a9dbd6afc8c14411042a3d98" }, + "lean.nvim": { "branch": "main", "commit": "fde0d5692edcc0a0cadad77067dfd49a51332236" }, "leap.nvim": { "branch": "main", "commit": "d7f8ee64155b7790188f17a993390f32577cfb81" }, "lsp-zero.nvim": { "branch": "v4.x", "commit": "d388e2b71834c826e61a3eba48caec53d7602510" }, "lsp_signature.nvim": { "branch": "master", "commit": "b7ace9ddb1640ce266012a45a672dfdaedfa5ec6" }, @@ -50,6 +49,7 @@ "nvim-scrollbar": { "branch": "main", "commit": "f8e87b96cd6362ef8579be456afee3b38fd7e2a8" }, "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, "nvim-web-devicons": { "branch": "master", "commit": "dfbfaa967a6f7ec50789bead7ef87e336c1fa63c" }, + "oil.nvim": { "branch": "master", "commit": "b73018b75affd13fa38e2fc94ef753b465f770d7" }, "outline.nvim": { "branch": "main", "commit": "2a132953b944561d45b52e4541ebfff71934a742" }, "papercolor-theme": { "branch": "master", "commit": "0cfe64ffb24c21a6101b5f994ca342a74c977aef" }, "persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" }, diff --git a/tests/headless.fnl b/tests/headless.fnl new file mode 100644 index 0000000..b80d55d --- /dev/null +++ b/tests/headless.fnl @@ -0,0 +1,60 @@ +;; Functional tests run headless inside the installed test environment: +;; make test-install && make test-functional + +(local failures []) + +(fn check [cond msg] + (when (not cond) + (table.insert failures msg))) + +(local (ok err) + (pcall (fn [] + (let [lazy (require :lazy)] + (lazy.load {:plugins [:oil.nvim :telescope.nvim]})) + (let [config (vim.fn.stdpath :config) + telescope-mod (require :mods.tools.telescope) + buffer-dir (. telescope-mod :buffer-dir)] + (check (= :function (type buffer-dir)) + "mods.tools.telescope should export buffer-dir") + ;; oil buffer: cwd resolves to the directory oil is showing + (vim.cmd.edit (.. config :/fnl)) + (check (= :oil vim.bo.filetype) + (.. "editing a directory should open an oil buffer, got ft=" + vim.bo.filetype)) + (var dir (or (buffer-dir) "")) + (check (not (dir:match "^oil://")) + (.. "buffer-dir should strip the oil:// scheme, got " dir)) + (check (= 1 (vim.fn.isdirectory dir)) + (.. "buffer-dir should return a real directory, got " dir)) + (check (vim.endswith dir :/fnl) + (.. "buffer-dir should return the directory oil is showing, got " + dir)) + ;; regular buffer: falls back to telescope's buffer_dir + (vim.cmd.edit (.. config :/init.lua)) + (set dir (or (buffer-dir) "")) + (check (= 1 (vim.fn.isdirectory dir)) + (.. "buffer-dir fallback should return a real directory, got " + dir)) + ;; bundled treesitter parsers must stay on the rtp + ;; (lazy's rtp reset guesses lib64 over lib/nvim) + (let [(add-ok available) (pcall vim.treesitter.language.add + :markdown)] + (check (and add-ok available) + "markdown treesitter parser should be available")) + (let [(edit-ok edit-err) (pcall vim.cmd.edit + (.. config :/README.md))] + (check edit-ok + (.. "opening a markdown file should not error: " + (tostring edit-err)))))))) + +(when (not ok) + (table.insert failures (.. "test run errored: " (tostring err)))) + +(if (> (length failures) 0) + (do + (each [_ f (ipairs failures)] + (print (.. "FAIL: " f))) + (vim.cmd "cquit! 1")) + (do + (print "OK: headless tests passed") + (vim.cmd "quitall!")))