From 364b78757815ab263980222bfd61412c3224a5b8 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sat, 21 Feb 2026 23:25:42 -0500 Subject: [PATCH 01/77] build: replace luacheck with selene Problem: luacheck is unmaintained (last release 2018) and required suppressing four warning classes to avoid false positives. It also lacks first-class vim/neovim awareness. Solution: switch to selene with std='vim' for vim-aware linting. Replace the luacheck CI job with selene, update the Makefile lint target, and delete .luacheckrc. --- .github/workflows/tests.yml | 17 +++++------------ .luacheckrc | 19 ------------------- Makefile | 2 +- selene.toml | 1 + 4 files changed, 7 insertions(+), 32 deletions(-) delete mode 100644 .luacheckrc create mode 100644 selene.toml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 462bb8f..8b1cc58 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,21 +10,14 @@ on: - main jobs: - luacheck: - name: Luacheck + selene: + name: Selene runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - - - name: Prepare - run: | - sudo apt-get update - sudo add-apt-repository universe - sudo apt install luarocks -y - sudo luarocks install luacheck - - - name: Run Luacheck - run: luacheck lua tests + - uses: NTBBloodbath/selene-action@v1.0.0 + with: + args: --display-style quiet . stylua: name: StyLua diff --git a/.luacheckrc b/.luacheckrc deleted file mode 100644 index 7efefde..0000000 --- a/.luacheckrc +++ /dev/null @@ -1,19 +0,0 @@ -max_comment_line_length = false -codes = true - -exclude_files = { - "tests/treesitter", -} - -ignore = { - "212", -- Unused argument - "631", -- Line is too long - "122", -- Setting a readonly global - "542", -- Empty if branch -} - -read_globals = { - "vim", - "a", - "assert", -} diff --git a/Makefile b/Makefile index 897b281..966374d 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ test: .PHONY: lint lint: scripts/nvim-typecheck-action ./scripts/nvim-typecheck-action/typecheck.sh --workdir scripts/nvim-typecheck-action lua - luacheck lua tests --formatter plain + selene --display-style quiet . stylua --check lua tests ## profile: use LuaJIT profiler to profile the plugin diff --git a/selene.toml b/selene.toml new file mode 100644 index 0000000..96cf5ab --- /dev/null +++ b/selene.toml @@ -0,0 +1 @@ +std = 'vim' From 50f1ade92c321b309d39954b59ca123498e46712 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sat, 21 Feb 2026 23:26:39 -0500 Subject: [PATCH 02/77] build: add nix devshell and pre-commit hooks Problem: oil.nvim had no reproducible dev environment. The .envrc set up a Python venv for the now-removed docgen pipeline, and there were no pre-commit hooks for local formatting checks. Solution: add flake.nix with stylua, selene, and prettier in the devshell. Replace the stale Python .envrc with 'use flake'. Add .pre-commit-config.yaml with stylua and prettier hooks matching other plugins in the repo collection. --- .envrc | 4 +--- .pre-commit-config.yaml | 17 ++++++++++++++++ Makefile | 2 +- flake.lock | 43 +++++++++++++++++++++++++++++++++++++++++ flake.nix | 29 +++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.envrc b/.envrc index d522e34..3550a30 100644 --- a/.envrc +++ b/.envrc @@ -1,3 +1 @@ -export VIRTUAL_ENV=venv -layout python -python -c 'import pyparsing' 2>/dev/null || pip install -r scripts/requirements.txt +use flake diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5d1f13f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +minimum_pre_commit_version: '3.5.0' + +repos: + - repo: https://github.com/JohnnyMorganz/StyLua + rev: v2.3.1 + hooks: + - id: stylua-github + name: stylua (Lua formatter) + files: \.lua$ + pass_filenames: true + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v4.0.0-alpha.8 + hooks: + - id: prettier + name: prettier + files: \.(md|toml|yaml|yml|sh)$ diff --git a/Makefile b/Makefile index 966374d..db15dd5 100644 --- a/Makefile +++ b/Makefile @@ -45,4 +45,4 @@ scripts/benchmark.nvim: ## clean: reset the repository to a clean state .PHONY: clean clean: - rm -rf scripts/nvim-typecheck-action venv .testenv perf/tmp profile.json + rm -rf scripts/nvim-typecheck-action .testenv perf/tmp profile.json diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..7501bfa --- /dev/null +++ b/flake.lock @@ -0,0 +1,43 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1771207753, + "narHash": "sha256-b9uG8yN50DRQ6A7JdZBfzq718ryYrlmGgqkRm9OOwCE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d1c15b7d5806069da59e819999d70e1cec0760bf", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "systems": "systems" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..5670f55 --- /dev/null +++ b/flake.nix @@ -0,0 +1,29 @@ +{ + description = "oil.nvim — Neovim file explorer: edit your filesystem like a buffer"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + systems.url = "github:nix-systems/default"; + }; + + outputs = + { + nixpkgs, + systems, + ... + }: + let + forEachSystem = f: nixpkgs.lib.genAttrs (import systems) (system: f nixpkgs.legacyPackages.${system}); + in + { + devShells = forEachSystem (pkgs: { + default = pkgs.mkShell { + packages = [ + pkgs.prettier + pkgs.stylua + pkgs.selene + ]; + }; + }); + }; +} From df53b172a9bc7768ea660352903731623de009d6 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sat, 21 Feb 2026 23:28:22 -0500 Subject: [PATCH 03/77] build: add luarocks packaging and bump stylua (#19) Problem: oil.nvim had no luarocks rockspec, so users of rocks.nvim and similar tools could not install it from the registry. The stylua CI action was also pinned to an older version. Solution: add scm-1 rockspec and a luarocks publish workflow that gates on tests passing before publishing on version tags. Bump stylua action from v2.0.2 to v2.1.0. Closes: barrettruth/oil.nvim#14 --- .github/workflows/luarocks.yml | 21 +++++++++++++++++++++ .github/workflows/tests.yml | 2 +- oil.nvim-scm-1.rockspec | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/luarocks.yml create mode 100644 oil.nvim-scm-1.rockspec diff --git a/.github/workflows/luarocks.yml b/.github/workflows/luarocks.yml new file mode 100644 index 0000000..999f728 --- /dev/null +++ b/.github/workflows/luarocks.yml @@ -0,0 +1,21 @@ +name: luarocks + +on: + push: + tags: + - 'v*' + +jobs: + tests: + uses: ./.github/workflows/tests.yml + + publish: + needs: tests + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: nvim-neorocks/luarocks-tag-release@v7 + env: + LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 462bb8f..4ef3bb1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,7 +35,7 @@ jobs: uses: JohnnyMorganz/stylua-action@v4 with: token: ${{ secrets.GITHUB_TOKEN }} - version: v2.0.2 + version: v2.1.0 args: --check lua tests typecheck: diff --git a/oil.nvim-scm-1.rockspec b/oil.nvim-scm-1.rockspec new file mode 100644 index 0000000..e58c602 --- /dev/null +++ b/oil.nvim-scm-1.rockspec @@ -0,0 +1,21 @@ +rockspec_format = '3.0' +package = 'oil.nvim' +version = 'scm-1' + +source = { + url = 'git+https://github.com/barrettruth/oil.nvim.git', +} + +description = { + summary = 'Neovim file explorer: edit your filesystem like a buffer', + homepage = 'https://github.com/barrettruth/oil.nvim', + license = 'MIT', +} + +dependencies = { + 'lua >= 5.1', +} + +build = { + type = 'builtin', +} From 86f553cd0a2b5d7f08851eb84ba9c2da63c385ae Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sat, 21 Feb 2026 23:52:27 -0500 Subject: [PATCH 04/77] build: replace luacheck with selene, add nix devshell and pre-commit (#20) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * build: replace luacheck with selene Problem: luacheck is unmaintained (last release 2018) and required suppressing four warning classes to avoid false positives. It also lacks first-class vim/neovim awareness. Solution: switch to selene with std='vim' for vim-aware linting. Replace the luacheck CI job with selene, update the Makefile lint target, and delete .luacheckrc. * build: add nix devshell and pre-commit hooks Problem: oil.nvim had no reproducible dev environment. The .envrc set up a Python venv for the now-removed docgen pipeline, and there were no pre-commit hooks for local formatting checks. Solution: add flake.nix with stylua, selene, and prettier in the devshell. Replace the stale Python .envrc with 'use flake'. Add .pre-commit-config.yaml with stylua and prettier hooks matching other plugins in the repo collection. * fix: format with stylua * build(selene): configure lints and add inline suppressions Problem: selene fails on 5 errors and 3 warnings from upstream code patterns that are intentional (mixed tables in config API, unused callback parameters, identical if branches for readability). Solution: globally allow mixed_table and unused_variable (high volume, inherent to the codebase design). Add inline selene:allow directives for the 8 remaining issues: if_same_then_else (4), mismatched_arg_count (1), empty_if (2), global_usage (1). Remove .envrc from tracking. * build: switch typecheck action to mrcjkb/lua-typecheck-action Problem: oil.nvim used stevearc/nvim-typecheck-action, which required cloning the action repo locally for the Makefile lint target. All other plugins in the collection use mrcjkb/lua-typecheck-action. Solution: swap to mrcjkb/lua-typecheck-action@v0 for consistency. Remove the nvim-typecheck-action git clone from the Makefile and .gitignore. Drop LuaLS from the local lint target since it requires a full language server install — CI handles it. --- .envrc | 3 - .github/workflows/tests.yml | 24 +- .gitignore | 2 +- .luacheckrc | 19 - .luarc.json | 13 +- .pre-commit-config.yaml | 17 + .stylua.toml | 3 + Makefile | 12 +- flake.lock | 43 ++ flake.nix | 29 + lua/oil/actions.lua | 288 ++++----- lua/oil/adapters/files.lua | 152 ++--- lua/oil/adapters/files/permissions.lua | 32 +- lua/oil/adapters/s3.lua | 150 ++--- lua/oil/adapters/s3/s3fs.lua | 52 +- lua/oil/adapters/ssh.lua | 142 ++--- lua/oil/adapters/ssh/connection.lua | 73 +-- lua/oil/adapters/ssh/sshfs.lua | 96 +-- lua/oil/adapters/test.lua | 24 +- lua/oil/adapters/trash.lua | 8 +- lua/oil/adapters/trash/freedesktop.lua | 185 +++--- lua/oil/adapters/trash/mac.lua | 72 +-- lua/oil/adapters/trash/windows.lua | 133 ++-- .../trash/windows/powershell-connection.lua | 16 +- .../trash/windows/powershell-trash.lua | 2 +- lua/oil/cache.lua | 43 +- lua/oil/clipboard.lua | 144 ++--- lua/oil/columns.lua | 68 +- lua/oil/config.lua | 96 +-- lua/oil/fs.lua | 66 +- lua/oil/git.lua | 32 +- lua/oil/init.lua | 586 +++++++++--------- lua/oil/keymap_util.lua | 50 +- lua/oil/layout.lua | 24 +- lua/oil/loading.lua | 20 +- lua/oil/log.lua | 28 +- lua/oil/lsp/helpers.lua | 32 +- lua/oil/lsp/workspace.lua | 80 +-- lua/oil/mutator/confirmation.lua | 58 +- lua/oil/mutator/init.lua | 142 ++--- lua/oil/mutator/parser.lua | 78 +-- lua/oil/mutator/progress.lua | 66 +- lua/oil/mutator/trie.lua | 6 +- lua/oil/pathutil.lua | 22 +- lua/oil/ringbuf.lua | 4 +- lua/oil/shell.lua | 14 +- lua/oil/util.lua | 317 +++++----- lua/oil/view.lua | 195 +++--- lua/resession/extensions/oil.lua | 4 +- perf/bootstrap.lua | 49 +- plugin/oil.lua | 2 +- selene.toml | 5 + tests/altbuf_spec.lua | 176 +++--- tests/close_spec.lua | 42 +- tests/config_spec.lua | 10 +- tests/files_spec.lua | 154 ++--- tests/manual_progress.lua | 10 +- tests/minimal_init.lua | 4 +- tests/move_rename_spec.lua | 72 +-- tests/mutator_spec.lua | 376 +++++------ tests/parser_spec.lua | 174 +++--- tests/path_spec.lua | 28 +- tests/preview_spec.lua | 24 +- tests/regression_spec.lua | 108 ++-- tests/select_spec.lua | 44 +- tests/test_util.lua | 42 +- tests/tmpdir.lua | 30 +- tests/trash_spec.lua | 154 ++--- tests/url_spec.lua | 22 +- tests/util_spec.lua | 22 +- tests/win_options_spec.lua | 62 +- vim.toml | 36 ++ 72 files changed, 2762 insertions(+), 2649 deletions(-) delete mode 100644 .envrc delete mode 100644 .luacheckrc create mode 100644 .pre-commit-config.yaml create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 selene.toml create mode 100644 vim.toml diff --git a/.envrc b/.envrc deleted file mode 100644 index d522e34..0000000 --- a/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -export VIRTUAL_ENV=venv -layout python -python -c 'import pyparsing' 2>/dev/null || pip install -r scripts/requirements.txt diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4ef3bb1..05dbd67 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,21 +10,15 @@ on: - main jobs: - luacheck: - name: Luacheck + selene: + name: Selene runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - - - name: Prepare - run: | - sudo apt-get update - sudo add-apt-repository universe - sudo apt install luarocks -y - sudo luarocks install luacheck - - - name: Run Luacheck - run: luacheck lua tests + - uses: NTBBloodbath/selene-action@v1.0.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --display-style quiet . stylua: name: StyLua @@ -43,9 +37,11 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - - uses: stevearc/nvim-typecheck-action@v2 + - uses: mrcjkb/lua-typecheck-action@v0 with: - path: lua + checklevel: Warning + directories: lua + configpath: .luarc.json run_tests: strategy: diff --git a/.gitignore b/.gitignore index c3b7755..70bd601 100644 --- a/.gitignore +++ b/.gitignore @@ -40,9 +40,9 @@ luac.out *.hex .direnv/ +.envrc .testenv/ doc/tags -scripts/nvim-typecheck-action scripts/benchmark.nvim perf/tmp/ profile.json diff --git a/.luacheckrc b/.luacheckrc deleted file mode 100644 index 7efefde..0000000 --- a/.luacheckrc +++ /dev/null @@ -1,19 +0,0 @@ -max_comment_line_length = false -codes = true - -exclude_files = { - "tests/treesitter", -} - -ignore = { - "212", -- Unused argument - "631", -- Line is too long - "122", -- Setting a readonly global - "542", -- Empty if branch -} - -read_globals = { - "vim", - "a", - "assert", -} diff --git a/.luarc.json b/.luarc.json index 68da2f2..f22884c 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,9 +1,8 @@ { - "runtime": { - "version": "LuaJIT", - "pathStrict": true - }, - "type": { - "checkTableShape": true - } + "runtime.version": "Lua 5.1", + "runtime.path": ["lua/?.lua", "lua/?/init.lua"], + "diagnostics.globals": ["vim", "jit", "bit"], + "workspace.library": ["$VIMRUNTIME/lua", "${3rd}/luv/library"], + "workspace.checkThirdParty": false, + "completion.callSnippet": "Replace" } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5d1f13f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +minimum_pre_commit_version: '3.5.0' + +repos: + - repo: https://github.com/JohnnyMorganz/StyLua + rev: v2.3.1 + hooks: + - id: stylua-github + name: stylua (Lua formatter) + files: \.lua$ + pass_filenames: true + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v4.0.0-alpha.8 + hooks: + - id: prettier + name: prettier + files: \.(md|toml|yaml|yml|sh)$ diff --git a/.stylua.toml b/.stylua.toml index 020ce91..01ded03 100644 --- a/.stylua.toml +++ b/.stylua.toml @@ -1,5 +1,8 @@ column_width = 100 +line_endings = "Unix" indent_type = "Spaces" indent_width = 2 +quote_style = "AutoPreferSingle" +call_parentheses = "Always" [sort_requires] enabled = true diff --git a/Makefile b/Makefile index 897b281..e3e622e 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,10 @@ all: lint test test: ./run_tests.sh -## lint: run linters and LuaLS typechecking +## lint: run selene and stylua .PHONY: lint -lint: scripts/nvim-typecheck-action - ./scripts/nvim-typecheck-action/typecheck.sh --workdir scripts/nvim-typecheck-action lua - luacheck lua tests --formatter plain +lint: + selene --display-style quiet . stylua --check lua tests ## profile: use LuaJIT profiler to profile the plugin @@ -36,13 +35,10 @@ benchmark: scripts/benchmark.nvim nvim --clean -u perf/bootstrap.lua -c 'lua benchmark()' @cat perf/tmp/benchmark.txt -scripts/nvim-typecheck-action: - git clone https://github.com/stevearc/nvim-typecheck-action scripts/nvim-typecheck-action - scripts/benchmark.nvim: git clone https://github.com/stevearc/benchmark.nvim scripts/benchmark.nvim ## clean: reset the repository to a clean state .PHONY: clean clean: - rm -rf scripts/nvim-typecheck-action venv .testenv perf/tmp profile.json + rm -rf .testenv perf/tmp profile.json diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..7501bfa --- /dev/null +++ b/flake.lock @@ -0,0 +1,43 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1771207753, + "narHash": "sha256-b9uG8yN50DRQ6A7JdZBfzq718ryYrlmGgqkRm9OOwCE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d1c15b7d5806069da59e819999d70e1cec0760bf", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "systems": "systems" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..5670f55 --- /dev/null +++ b/flake.nix @@ -0,0 +1,29 @@ +{ + description = "oil.nvim — Neovim file explorer: edit your filesystem like a buffer"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + systems.url = "github:nix-systems/default"; + }; + + outputs = + { + nixpkgs, + systems, + ... + }: + let + forEachSystem = f: nixpkgs.lib.genAttrs (import systems) (system: f nixpkgs.legacyPackages.${system}); + in + { + devShells = forEachSystem (pkgs: { + default = pkgs.mkShell { + packages = [ + pkgs.prettier + pkgs.stylua + pkgs.selene + ]; + }; + }); + }; +} diff --git a/lua/oil/actions.lua b/lua/oil/actions.lua index edd44ba..143a454 100644 --- a/lua/oil/actions.lua +++ b/lua/oil/actions.lua @@ -1,18 +1,18 @@ -local oil = require("oil") -local util = require("oil.util") +local oil = require('oil') +local util = require('oil.util') local M = {} M.show_help = { callback = function() - local config = require("oil.config") - require("oil.keymap_util").show_help(config.keymaps) + local config = require('oil.config') + require('oil.keymap_util').show_help(config.keymaps) end, - desc = "Show default keymaps", + desc = 'Show default keymaps', } M.select = { - desc = "Open the entry under the cursor", + desc = 'Open the entry under the cursor', callback = function(opts) opts = opts or {} local callback = opts.callback @@ -21,30 +21,30 @@ M.select = { end, parameters = { vertical = { - type = "boolean", - desc = "Open the buffer in a vertical split", + type = 'boolean', + desc = 'Open the buffer in a vertical split', }, horizontal = { - type = "boolean", - desc = "Open the buffer in a horizontal split", + type = 'boolean', + desc = 'Open the buffer in a horizontal split', }, split = { type = '"aboveleft"|"belowright"|"topleft"|"botright"', - desc = "Split modifier", + desc = 'Split modifier', }, tab = { - type = "boolean", - desc = "Open the buffer in a new tab", + type = 'boolean', + desc = 'Open the buffer in a new tab', }, close = { - type = "boolean", - desc = "Close the original oil buffer once selection is made", + type = 'boolean', + desc = 'Close the original oil buffer once selection is made', }, }, } M.select_vsplit = { - desc = "Open the entry under the cursor in a vertical split", + desc = 'Open the entry under the cursor in a vertical split', deprecated = true, callback = function() oil.select({ vertical = true }) @@ -52,7 +52,7 @@ M.select_vsplit = { } M.select_split = { - desc = "Open the entry under the cursor in a horizontal split", + desc = 'Open the entry under the cursor in a horizontal split', deprecated = true, callback = function() oil.select({ horizontal = true }) @@ -60,7 +60,7 @@ M.select_split = { } M.select_tab = { - desc = "Open the entry under the cursor in a new tab", + desc = 'Open the entry under the cursor in a new tab', deprecated = true, callback = function() oil.select({ tab = true }) @@ -68,25 +68,25 @@ M.select_tab = { } M.preview = { - desc = "Open the entry under the cursor in a preview window, or close the preview window if already open", + desc = 'Open the entry under the cursor in a preview window, or close the preview window if already open', parameters = { vertical = { - type = "boolean", - desc = "Open the buffer in a vertical split", + type = 'boolean', + desc = 'Open the buffer in a vertical split', }, horizontal = { - type = "boolean", - desc = "Open the buffer in a horizontal split", + type = 'boolean', + desc = 'Open the buffer in a horizontal split', }, split = { type = '"aboveleft"|"belowright"|"topleft"|"botright"', - desc = "Split modifier", + desc = 'Split modifier', }, }, callback = function(opts) local entry = oil.get_cursor_entry() if not entry then - vim.notify("Could not find entry under cursor", vim.log.levels.ERROR) + vim.notify('Could not find entry under cursor', vim.log.levels.ERROR) return end local winid = util.get_preview_win() @@ -95,7 +95,7 @@ M.preview = { if entry.id == cur_id then vim.api.nvim_win_close(winid, true) if util.is_floating_win() then - local layout = require("oil.layout") + local layout = require('oil.layout') local win_opts = layout.get_fullscreen_win_opts() vim.api.nvim_win_set_config(0, win_opts) end @@ -107,13 +107,13 @@ M.preview = { } M.preview_scroll_down = { - desc = "Scroll down in the preview window", + desc = 'Scroll down in the preview window', callback = function() local winid = util.get_preview_win() if winid then vim.api.nvim_win_call(winid, function() vim.cmd.normal({ - args = { vim.api.nvim_replace_termcodes("", true, true, true) }, + args = { vim.api.nvim_replace_termcodes('', true, true, true) }, bang = true, }) end) @@ -122,13 +122,13 @@ M.preview_scroll_down = { } M.preview_scroll_up = { - desc = "Scroll up in the preview window", + desc = 'Scroll up in the preview window', callback = function() local winid = util.get_preview_win() if winid then vim.api.nvim_win_call(winid, function() vim.cmd.normal({ - args = { vim.api.nvim_replace_termcodes("", true, true, true) }, + args = { vim.api.nvim_replace_termcodes('', true, true, true) }, bang = true, }) end) @@ -137,50 +137,50 @@ M.preview_scroll_up = { } M.preview_scroll_left = { - desc = "Scroll left in the preview window", + desc = 'Scroll left in the preview window', callback = function() local winid = util.get_preview_win() if winid then vim.api.nvim_win_call(winid, function() - vim.cmd.normal({ "zH", bang = true }) + vim.cmd.normal({ 'zH', bang = true }) end) end end, } M.preview_scroll_right = { - desc = "Scroll right in the preview window", + desc = 'Scroll right in the preview window', callback = function() local winid = util.get_preview_win() if winid then vim.api.nvim_win_call(winid, function() - vim.cmd.normal({ "zL", bang = true }) + vim.cmd.normal({ 'zL', bang = true }) end) end end, } M.parent = { - desc = "Navigate to the parent path", + desc = 'Navigate to the parent path', callback = oil.open, } M.close = { - desc = "Close oil and restore original buffer", + desc = 'Close oil and restore original buffer', callback = function(opts) opts = opts or {} oil.close(opts) end, parameters = { exit_if_last_buf = { - type = "boolean", - desc = "Exit vim if oil is closed as the last buffer", + type = 'boolean', + desc = 'Exit vim if oil is closed as the last buffer', }, }, } M.close_float = { - desc = "Close oil if the window is floating, otherwise do nothing", + desc = 'Close oil if the window is floating, otherwise do nothing', callback = function(opts) if vim.w.is_oil_win then opts = opts or {} @@ -189,8 +189,8 @@ M.close_float = { end, parameters = { exit_if_last_buf = { - type = "boolean", - desc = "Exit vim if oil is closed as the last buffer", + type = 'boolean', + desc = 'Exit vim if oil is closed as the last buffer', }, }, } @@ -202,42 +202,42 @@ local function cd(cmd, silent) if dir then vim.cmd({ cmd = cmd, args = { dir } }) if not silent then - vim.notify(string.format("CWD: %s", dir), vim.log.levels.INFO) + vim.notify(string.format('CWD: %s', dir), vim.log.levels.INFO) end else - vim.notify("Cannot :cd; not in a directory", vim.log.levels.WARN) + vim.notify('Cannot :cd; not in a directory', vim.log.levels.WARN) end end M.cd = { - desc = ":cd to the current oil directory", + desc = ':cd to the current oil directory', callback = function(opts) opts = opts or {} - local cmd = "cd" - if opts.scope == "tab" then - cmd = "tcd" - elseif opts.scope == "win" then - cmd = "lcd" + local cmd = 'cd' + if opts.scope == 'tab' then + cmd = 'tcd' + elseif opts.scope == 'win' then + cmd = 'lcd' end cd(cmd, opts.silent) end, parameters = { scope = { type = 'nil|"tab"|"win"', - desc = "Scope of the directory change (e.g. use |:tcd| or |:lcd|)", + desc = 'Scope of the directory change (e.g. use |:tcd| or |:lcd|)', }, silent = { - type = "boolean", - desc = "Do not show a message when changing directories", + type = 'boolean', + desc = 'Do not show a message when changing directories', }, }, } M.tcd = { - desc = ":tcd to the current oil directory", + desc = ':tcd to the current oil directory', deprecated = true, callback = function() - cd("tcd") + cd('tcd') end, } @@ -249,46 +249,46 @@ M.open_cwd = { } M.toggle_hidden = { - desc = "Toggle hidden files and directories", + desc = 'Toggle hidden files and directories', callback = function() - require("oil.view").toggle_hidden() + require('oil.view').toggle_hidden() end, } M.open_terminal = { - desc = "Open a terminal in the current directory", + desc = 'Open a terminal in the current directory', callback = function() - local config = require("oil.config") + local config = require('oil.config') local bufname = vim.api.nvim_buf_get_name(0) local adapter = config.get_adapter_by_scheme(bufname) if not adapter then return end - if adapter.name == "files" then + if adapter.name == 'files' then local dir = oil.get_current_dir() - assert(dir, "Oil buffer with files adapter must have current directory") + assert(dir, 'Oil buffer with files adapter must have current directory') local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_current_buf(bufnr) - if vim.fn.has("nvim-0.11") == 1 then + if vim.fn.has('nvim-0.11') == 1 then vim.fn.jobstart(vim.o.shell, { cwd = dir, term = true }) else ---@diagnostic disable-next-line: deprecated vim.fn.termopen(vim.o.shell, { cwd = dir }) end - elseif adapter.name == "ssh" then + elseif adapter.name == 'ssh' then local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_current_buf(bufnr) - local url = require("oil.adapters.ssh").parse_url(bufname) - local cmd = require("oil.adapters.ssh.connection").create_ssh_command(url) + local url = require('oil.adapters.ssh').parse_url(bufname) + local cmd = require('oil.adapters.ssh.connection').create_ssh_command(url) local term_id - if vim.fn.has("nvim-0.11") == 1 then + if vim.fn.has('nvim-0.11') == 1 then term_id = vim.fn.jobstart(cmd, { term = true }) else ---@diagnostic disable-next-line: deprecated term_id = vim.fn.termopen(cmd) end if term_id then - vim.api.nvim_chan_send(term_id, string.format("cd %s\n", url.path)) + vim.api.nvim_chan_send(term_id, string.format('cd %s\n', url.path)) end else vim.notify( @@ -304,25 +304,25 @@ M.open_terminal = { ---@return nil|string[] cmd ---@return nil|string error local function get_open_cmd(path) - if vim.fn.has("mac") == 1 then - return { "open", path } - elseif vim.fn.has("win32") == 1 then - if vim.fn.executable("rundll32") == 1 then - return { "rundll32", "url.dll,FileProtocolHandler", path } + if vim.fn.has('mac') == 1 then + return { 'open', path } + elseif vim.fn.has('win32') == 1 then + if vim.fn.executable('rundll32') == 1 then + return { 'rundll32', 'url.dll,FileProtocolHandler', path } else - return nil, "rundll32 not found" + return nil, 'rundll32 not found' end - elseif vim.fn.executable("explorer.exe") == 1 then - return { "explorer.exe", path } - elseif vim.fn.executable("xdg-open") == 1 then - return { "xdg-open", path } + elseif vim.fn.executable('explorer.exe') == 1 then + return { 'explorer.exe', path } + elseif vim.fn.executable('xdg-open') == 1 then + return { 'xdg-open', path } else - return nil, "no handler found" + return nil, 'no handler found' end end M.open_external = { - desc = "Open the entry under the cursor in an external program", + desc = 'Open the entry under the cursor in an external program', callback = function() local entry = oil.get_cursor_entry() local dir = oil.get_current_dir() @@ -338,20 +338,20 @@ M.open_external = { local cmd, err = get_open_cmd(path) if not cmd then - vim.notify(string.format("Could not open %s: %s", path, err), vim.log.levels.ERROR) + vim.notify(string.format('Could not open %s: %s', path, err), vim.log.levels.ERROR) return end local jid = vim.fn.jobstart(cmd, { detach = true }) - assert(jid > 0, "Failed to start job") + assert(jid > 0, 'Failed to start job') end, } M.refresh = { - desc = "Refresh current directory list", + desc = 'Refresh current directory list', callback = function(opts) opts = opts or {} if vim.bo.modified and not opts.force then - local ok, choice = pcall(vim.fn.confirm, "Discard changes?", "No\nYes") + local ok, choice = pcall(vim.fn.confirm, 'Discard changes?', 'No\nYes') if not ok or choice ~= 2 then return end @@ -363,26 +363,26 @@ M.refresh = { end, parameters = { force = { - desc = "When true, do not prompt user if they will be discarding changes", - type = "boolean", + desc = 'When true, do not prompt user if they will be discarding changes', + type = 'boolean', }, }, } local function open_cmdline_with_path(path) local escaped = - vim.api.nvim_replace_termcodes(": " .. vim.fn.fnameescape(path) .. "", true, false, true) - vim.api.nvim_feedkeys(escaped, "n", false) + vim.api.nvim_replace_termcodes(': ' .. vim.fn.fnameescape(path) .. '', true, false, true) + vim.api.nvim_feedkeys(escaped, 'n', false) end M.open_cmdline = { - desc = "Open vim cmdline with current entry as an argument", + desc = 'Open vim cmdline with current entry as an argument', callback = function(opts) - opts = vim.tbl_deep_extend("keep", opts or {}, { + opts = vim.tbl_deep_extend('keep', opts or {}, { shorten_path = true, }) - local config = require("oil.config") - local fs = require("oil.fs") + local config = require('oil.config') + local fs = require('oil.fs') local entry = oil.get_cursor_entry() if not entry then return @@ -393,7 +393,7 @@ M.open_cmdline = { return end local adapter = config.get_adapter_by_scheme(scheme) - if not adapter or not path or adapter.name ~= "files" then + if not adapter or not path or adapter.name ~= 'files' then return end local fullpath = fs.posix_to_os_path(path) .. entry.name @@ -407,18 +407,18 @@ M.open_cmdline = { end, parameters = { modify = { - desc = "Modify the path with |fnamemodify()| using this as the mods argument", - type = "string", + desc = 'Modify the path with |fnamemodify()| using this as the mods argument', + type = 'string', }, shorten_path = { - desc = "Use relative paths when possible", - type = "boolean", + desc = 'Use relative paths when possible', + type = 'boolean', }, }, } M.yank_entry = { - desc = "Yank the filepath of the entry under the cursor to a register", + desc = 'Yank the filepath of the entry under the cursor to a register', callback = function(opts) opts = opts or {} local entry = oil.get_cursor_entry() @@ -427,8 +427,8 @@ M.yank_entry = { return end local name = entry.name - if entry.type == "directory" then - name = name .. "/" + if entry.type == 'directory' then + name = name .. '/' end local path = dir .. name if opts.modify then @@ -438,14 +438,14 @@ M.yank_entry = { end, parameters = { modify = { - desc = "Modify the path with |fnamemodify()| using this as the mods argument", - type = "string", + desc = 'Modify the path with |fnamemodify()| using this as the mods argument', + type = 'string', }, }, } M.copy_entry_path = { - desc = "Yank the filepath of the entry under the cursor to a register", + desc = 'Yank the filepath of the entry under the cursor to a register', deprecated = true, callback = function() local entry = oil.get_cursor_entry() @@ -458,7 +458,7 @@ M.copy_entry_path = { } M.copy_entry_filename = { - desc = "Yank the filename of the entry under the cursor to a register", + desc = 'Yank the filename of the entry under the cursor to a register', deprecated = true, callback = function() local entry = oil.get_cursor_entry() @@ -470,30 +470,30 @@ M.copy_entry_filename = { } M.copy_to_system_clipboard = { - desc = "Copy the entry under the cursor to the system clipboard", + desc = 'Copy the entry under the cursor to the system clipboard', callback = function() - require("oil.clipboard").copy_to_system_clipboard() + require('oil.clipboard').copy_to_system_clipboard() end, } M.paste_from_system_clipboard = { - desc = "Paste the system clipboard into the current oil directory", + desc = 'Paste the system clipboard into the current oil directory', callback = function(opts) - require("oil.clipboard").paste_from_system_clipboard(opts and opts.delete_original) + require('oil.clipboard').paste_from_system_clipboard(opts and opts.delete_original) end, parameters = { delete_original = { - type = "boolean", - desc = "Delete the original file after copying", + type = 'boolean', + desc = 'Delete the original file after copying', }, }, } M.open_cmdline_dir = { - desc = "Open vim cmdline with current directory as an argument", + desc = 'Open vim cmdline with current directory as an argument', deprecated = true, callback = function() - local fs = require("oil.fs") + local fs = require('oil.fs') local dir = oil.get_current_dir() if dir then open_cmdline_with_path(fs.shorten_path(dir)) @@ -502,7 +502,7 @@ M.open_cmdline_dir = { } M.change_sort = { - desc = "Change the sort order", + desc = 'Change the sort order', callback = function(opts) opts = opts or {} @@ -511,21 +511,21 @@ M.change_sort = { return end - local sort_cols = { "name", "size", "atime", "mtime", "ctime", "birthtime" } - vim.ui.select(sort_cols, { prompt = "Sort by", kind = "oil_sort_col" }, function(col) + local sort_cols = { 'name', 'size', 'atime', 'mtime', 'ctime', 'birthtime' } + vim.ui.select(sort_cols, { prompt = 'Sort by', kind = 'oil_sort_col' }, function(col) if not col then return end vim.ui.select( - { "ascending", "descending" }, - { prompt = "Sort order", kind = "oil_sort_order" }, + { 'ascending', 'descending' }, + { prompt = 'Sort order', kind = 'oil_sort_order' }, function(order) if not order then return end - order = order == "ascending" and "asc" or "desc" + order = order == 'ascending' and 'asc' or 'desc' oil.set_sort({ - { "type", "asc" }, + { 'type', 'asc' }, { col, order }, }) end @@ -534,24 +534,24 @@ M.change_sort = { end, parameters = { sort = { - type = "oil.SortSpec[]", - desc = "List of columns plus direction (see |oil.set_sort|) instead of interactive selection", + type = 'oil.SortSpec[]', + desc = 'List of columns plus direction (see |oil.set_sort|) instead of interactive selection', }, }, } M.toggle_trash = { - desc = "Jump to and from the trash for the current directory", + desc = 'Jump to and from the trash for the current directory', callback = function() - local fs = require("oil.fs") + local fs = require('oil.fs') local bufname = vim.api.nvim_buf_get_name(0) local scheme, path = util.parse_url(bufname) local bufnr = vim.api.nvim_get_current_buf() local url - if scheme == "oil://" then - url = "oil-trash://" .. path - elseif scheme == "oil-trash://" then - url = "oil://" .. path + if scheme == 'oil://' then + url = 'oil-trash://' .. path + elseif scheme == 'oil-trash://' then + url = 'oil://' .. path -- The non-linux trash implementations don't support per-directory trash, -- so jump back to the stored source buffer. if not fs.is_linux then @@ -561,7 +561,7 @@ M.toggle_trash = { end end else - vim.notify("No trash found for buffer", vim.log.levels.WARN) + vim.notify('No trash found for buffer', vim.log.levels.WARN) return end vim.cmd.edit({ args = { url } }) @@ -570,11 +570,11 @@ M.toggle_trash = { } M.send_to_qflist = { - desc = "Sends files in the current oil directory to the quickfix list, replacing the previous entries.", + desc = 'Sends files in the current oil directory to the quickfix list, replacing the previous entries.', callback = function(opts) - opts = vim.tbl_deep_extend("keep", opts or {}, { - target = "qflist", - action = "r", + opts = vim.tbl_deep_extend('keep', opts or {}, { + target = 'qflist', + action = 'r', only_matching_search = false, }) util.send_to_quickfix({ @@ -586,48 +586,48 @@ M.send_to_qflist = { parameters = { target = { type = '"qflist"|"loclist"', - desc = "The target list to send files to", + desc = 'The target list to send files to', }, action = { type = '"r"|"a"', - desc = "Replace or add to current quickfix list (see |setqflist-action|)", + desc = 'Replace or add to current quickfix list (see |setqflist-action|)', }, only_matching_search = { - type = "boolean", - desc = "Whether to only add the files that matches the last search. This option only applies when search highlighting is active", + type = 'boolean', + desc = 'Whether to only add the files that matches the last search. This option only applies when search highlighting is active', }, }, } M.add_to_qflist = { - desc = "Adds files in the current oil directory to the quickfix list, keeping the previous entries.", + desc = 'Adds files in the current oil directory to the quickfix list, keeping the previous entries.', deprecated = true, callback = function() util.send_to_quickfix({ - target = "qflist", - mode = "a", + target = 'qflist', + mode = 'a', }) end, } M.send_to_loclist = { - desc = "Sends files in the current oil directory to the location list, replacing the previous entries.", + desc = 'Sends files in the current oil directory to the location list, replacing the previous entries.', deprecated = true, callback = function() util.send_to_quickfix({ - target = "loclist", - mode = "r", + target = 'loclist', + mode = 'r', }) end, } M.add_to_loclist = { - desc = "Adds files in the current oil directory to the location list, keeping the previous entries.", + desc = 'Adds files in the current oil directory to the location list, keeping the previous entries.', deprecated = true, callback = function() util.send_to_quickfix({ - target = "loclist", - mode = "a", + target = 'loclist', + mode = 'a', }) end, } @@ -637,7 +637,7 @@ M.add_to_loclist = { M._get_actions = function() local ret = {} for name, action in pairs(M) do - if type(action) == "table" and action.desc then + if type(action) == 'table' and action.desc then table.insert(ret, { name = name, desc = action.desc, diff --git a/lua/oil/adapters/files.lua b/lua/oil/adapters/files.lua index 228e263..e6331ba 100644 --- a/lua/oil/adapters/files.lua +++ b/lua/oil/adapters/files.lua @@ -1,12 +1,12 @@ -local cache = require("oil.cache") -local columns = require("oil.columns") -local config = require("oil.config") -local constants = require("oil.constants") -local fs = require("oil.fs") -local git = require("oil.git") -local log = require("oil.log") -local permissions = require("oil.adapters.files.permissions") -local util = require("oil.util") +local cache = require('oil.cache') +local columns = require('oil.columns') +local config = require('oil.config') +local constants = require('oil.constants') +local fs = require('oil.fs') +local git = require('oil.git') +local log = require('oil.log') +local permissions = require('oil.adapters.files.permissions') +local util = require('oil.util') local uv = vim.uv or vim.loop local M = {} @@ -25,7 +25,7 @@ local function read_link_data(path, cb) assert(link) local stat_path = link if not fs.is_absolute(link) then - stat_path = fs.join(vim.fn.fnamemodify(path, ":h"), link) + stat_path = fs.join(vim.fn.fnamemodify(path, ':h'), link) end uv.fs_stat(stat_path, function(stat_err, stat) cb(nil, link, stat) @@ -43,7 +43,7 @@ end ---@return string M.to_short_os_path = function(path, entry_type) local shortpath = fs.shorten_path(fs.posix_to_os_path(path)) - if entry_type == "directory" then + if entry_type == 'directory' then shortpath = util.addslash(shortpath, true) end return shortpath @@ -61,13 +61,13 @@ file_columns.size = { return columns.EMPTY end if stat.size >= 1e9 then - return string.format("%.1fG", stat.size / 1e9) + return string.format('%.1fG', stat.size / 1e9) elseif stat.size >= 1e6 then - return string.format("%.1fM", stat.size / 1e6) + return string.format('%.1fM', stat.size / 1e6) elseif stat.size >= 1e3 then - return string.format("%.1fk", stat.size / 1e3) + return string.format('%.1fk', stat.size / 1e3) else - return string.format("%d", stat.size) + return string.format('%d', stat.size) end end, @@ -82,7 +82,7 @@ file_columns.size = { end, parse = function(line, conf) - return line:match("^(%d+%S*)%s+(.*)$") + return line:match('^(%d+%S*)%s+(.*)$') end, } @@ -120,7 +120,7 @@ if not fs.is_windows then local _, path = util.parse_url(action.url) assert(path) return string.format( - "CHMOD %s %s", + 'CHMOD %s %s', permissions.mode_to_octal_str(action.value), M.to_short_os_path(path, action.entry_type) ) @@ -147,10 +147,10 @@ end local current_year -- Make sure we run this import-time effect in the main loop (mostly for tests) vim.schedule(function() - current_year = vim.fn.strftime("%Y") + current_year = vim.fn.strftime('%Y') end) -for _, time_key in ipairs({ "ctime", "mtime", "atime", "birthtime" }) do +for _, time_key in ipairs({ 'ctime', 'mtime', 'atime', 'birthtime' }) do file_columns[time_key] = { require_stat = true, @@ -165,11 +165,11 @@ for _, time_key in ipairs({ "ctime", "mtime", "atime", "birthtime" }) do if fmt then ret = vim.fn.strftime(fmt, stat[time_key].sec) else - local year = vim.fn.strftime("%Y", stat[time_key].sec) + local year = vim.fn.strftime('%Y', stat[time_key].sec) if year ~= current_year then - ret = vim.fn.strftime("%b %d %Y", stat[time_key].sec) + ret = vim.fn.strftime('%b %d %Y', stat[time_key].sec) else - ret = vim.fn.strftime("%b %d %H:%M", stat[time_key].sec) + ret = vim.fn.strftime('%b %d %H:%M', stat[time_key].sec) end end return ret @@ -183,20 +183,20 @@ for _, time_key in ipairs({ "ctime", "mtime", "atime", "birthtime" }) do -- and whitespace with a pattern that matches any amount of whitespace -- e.g. "%b %d %Y" -> "%S+%s+%S+%s+%S+" pattern = fmt - :gsub("%%.", "%%S+") - :gsub("%s+", "%%s+") + :gsub('%%.', '%%S+') + :gsub('%s+', '%%s+') -- escape `()[]` because those are special characters in Lua patterns :gsub( - "%(", - "%%(" + '%(', + '%%(' ) - :gsub("%)", "%%)") - :gsub("%[", "%%[") - :gsub("%]", "%%]") + :gsub('%)', '%%)') + :gsub('%[', '%%[') + :gsub('%]', '%%]') else - pattern = "%S+%s+%d+%s+%d%d:?%d%d" + pattern = '%S+%s+%d+%s+%d%d:?%d%d' end - return line:match("^(" .. pattern .. ")%s+(.+)$") + return line:match('^(' .. pattern .. ')%s+(.+)$') end, get_sort_value = function(entry) @@ -238,17 +238,17 @@ M.normalize_url = function(url, callback) assert(path) if fs.is_windows then - if path == "/" then + if path == '/' then return callback(url) else - local is_root_drive = path:match("^/%u$") + local is_root_drive = path:match('^/%u$') if is_root_drive then - return callback(url .. "/") + return callback(url .. '/') end end end - local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":p") + local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ':p') uv.fs_realpath(os_path, function(err, new_os_path) local realpath if fs.is_windows then @@ -264,8 +264,8 @@ M.normalize_url = function(url, callback) vim.schedule_wrap(function(stat_err, stat) local is_directory if stat then - is_directory = stat.type == "directory" - elseif vim.endswith(realpath, "/") or (fs.is_windows and vim.endswith(realpath, "\\")) then + is_directory = stat.type == 'directory' + elseif vim.endswith(realpath, '/') or (fs.is_windows and vim.endswith(realpath, '\\')) then is_directory = true else local filetype = vim.filetype.match({ filename = vim.fs.basename(realpath) }) @@ -276,7 +276,7 @@ M.normalize_url = function(url, callback) local norm_path = util.addslash(fs.os_to_posix_path(realpath)) callback(scheme .. norm_path) else - callback(vim.fn.fnamemodify(realpath, ":.")) + callback(vim.fn.fnamemodify(realpath, ':.')) end end) ) @@ -292,11 +292,11 @@ M.get_entry_path = function(url, entry, cb) local scheme, path = util.parse_url(parent_url) M.normalize_url(scheme .. path .. entry.name, cb) else - if entry.type == "directory" then + if entry.type == 'directory' then cb(url) else local _, path = util.parse_url(url) - local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(assert(path)), ":p") + local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(assert(path)), ':p') cb(os_path) end end @@ -321,10 +321,10 @@ local function fetch_entry_metadata(parent_dir, entry, require_stat, cb) end -- Make sure we always get fs_stat info for links - if entry[FIELD_TYPE] == "link" then + if entry[FIELD_TYPE] == 'link' then read_link_data(entry_path, function(link_err, link, link_stat) if link_err then - log.warn("Error reading link data %s: %s", entry_path, link_err) + log.warn('Error reading link data %s: %s', entry_path, link_err) return cb() end meta.link = link @@ -336,7 +336,7 @@ local function fetch_entry_metadata(parent_dir, entry, require_stat, cb) -- The link is broken, so let's use the stat of the link itself uv.fs_lstat(entry_path, function(stat_err, stat) if stat_err then - log.warn("Error lstat link file %s: %s", entry_path, stat_err) + log.warn('Error lstat link file %s: %s', entry_path, stat_err) return cb() end meta.stat = stat @@ -350,7 +350,7 @@ local function fetch_entry_metadata(parent_dir, entry, require_stat, cb) elseif require_stat then uv.fs_stat(entry_path, function(stat_err, stat) if stat_err then - log.warn("Error stat file %s: %s", entry_path, stat_err) + log.warn('Error stat file %s: %s', entry_path, stat_err) return cb() end assert(stat) @@ -368,11 +368,11 @@ end if fs.is_windows then local old_fetch_metadata = fetch_entry_metadata fetch_entry_metadata = function(parent_dir, entry, require_stat, cb) - if entry[FIELD_TYPE] == "link" then + if entry[FIELD_TYPE] == 'link' then local entry_path = fs.posix_to_os_path(parent_dir .. entry[FIELD_NAME]) uv.fs_lstat(entry_path, function(stat_err, stat) if stat_err then - log.warn("Error lstat link file %s: %s", entry_path, stat_err) + log.warn('Error lstat link file %s: %s', entry_path, stat_err) return old_fetch_metadata(parent_dir, entry, require_stat, cb) end assert(stat) @@ -398,17 +398,17 @@ local function list_windows_drives(url, column_defs, cb) local _, path = util.parse_url(url) assert(path) local require_stat = columns_require_stat(column_defs) - local stdout = "" - local jid = vim.fn.jobstart({ "wmic", "logicaldisk", "get", "name" }, { + local stdout = '' + local jid = vim.fn.jobstart({ 'wmic', 'logicaldisk', 'get', 'name' }, { stdout_buffered = true, on_stdout = function(_, data) - stdout = table.concat(data, "\n") + stdout = table.concat(data, '\n') end, on_exit = function(_, code) if code ~= 0 then - return cb("Error listing windows devices") + return cb('Error listing windows devices') end - local lines = vim.split(stdout, "\n", { plain = true, trimempty = true }) + local lines = vim.split(stdout, '\n', { plain = true, trimempty = true }) -- Remove the "Name" header table.remove(lines, 1) local internal_entries = {} @@ -421,12 +421,12 @@ local function list_windows_drives(url, column_defs, cb) end) for _, disk in ipairs(lines) do - if disk:match("^%s*$") then + if disk:match('^%s*$') then -- Skip empty line complete_disk_cb() else - disk = disk:gsub(":%s*$", "") - local cache_entry = cache.create_entry(url, disk, "directory") + disk = disk:gsub(':%s*$', '') + local cache_entry = cache.create_entry(url, disk, 'directory') table.insert(internal_entries, cache_entry) fetch_entry_metadata(path, cache_entry, require_stat, complete_disk_cb) end @@ -434,7 +434,7 @@ local function list_windows_drives(url, column_defs, cb) end, }) if jid <= 0 then - cb("Could not list windows devices") + cb('Could not list windows devices') end end @@ -444,7 +444,7 @@ end M.list = function(url, column_defs, cb) local _, path = util.parse_url(url) assert(path) - if fs.is_windows and path == "/" then + if fs.is_windows and path == '/' then return list_windows_drives(url, column_defs, cb) end local dir = fs.posix_to_os_path(path) @@ -453,7 +453,7 @@ M.list = function(url, column_defs, cb) ---@diagnostic disable-next-line: param-type-mismatch, discard-returns uv.fs_opendir(dir, function(open_err, fd) if open_err then - if open_err:match("^ENOENT: no such file or directory") then + if open_err:match('^ENOENT: no such file or directory') then -- If the directory doesn't exist, treat the list as a success. We will be able to traverse -- and edit a not-yet-existing directory. return cb() @@ -505,7 +505,7 @@ M.is_modifiable = function(bufnr) local bufname = vim.api.nvim_buf_get_name(bufnr) local _, path = util.parse_url(bufname) assert(path) - if fs.is_windows and path == "/" then + if fs.is_windows and path == '/' then return false end local dir = fs.posix_to_os_path(path) @@ -515,30 +515,30 @@ M.is_modifiable = function(bufnr) end -- fs_access can return nil, force boolean return - return uv.fs_access(dir, "W") == true + return uv.fs_access(dir, 'W') == true end ---@param action oil.Action ---@return string M.render_action = function(action) - if action.type == "create" then + if action.type == 'create' then local _, path = util.parse_url(action.url) assert(path) - local ret = string.format("CREATE %s", M.to_short_os_path(path, action.entry_type)) + local ret = string.format('CREATE %s', M.to_short_os_path(path, action.entry_type)) if action.link then - ret = ret .. " -> " .. fs.posix_to_os_path(action.link) + ret = ret .. ' -> ' .. fs.posix_to_os_path(action.link) end return ret - elseif action.type == "delete" then + elseif action.type == 'delete' then local _, path = util.parse_url(action.url) assert(path) local short_path = M.to_short_os_path(path, action.entry_type) if config.delete_to_trash then - return string.format(" TRASH %s", short_path) + return string.format(' TRASH %s', short_path) else - return string.format("DELETE %s", short_path) + return string.format('DELETE %s', short_path) end - elseif action.type == "move" or action.type == "copy" then + elseif action.type == 'move' or action.type == 'copy' then local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) if dest_adapter == M then local _, src_path = util.parse_url(action.src_url) @@ -546,7 +546,7 @@ M.render_action = function(action) local _, dest_path = util.parse_url(action.dest_url) assert(dest_path) return string.format( - " %s %s -> %s", + ' %s %s -> %s', action.type:upper(), M.to_short_os_path(src_path, action.entry_type), M.to_short_os_path(dest_path, action.entry_type) @@ -563,7 +563,7 @@ end ---@param action oil.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) - if action.type == "create" then + if action.type == 'create' then local _, path = util.parse_url(action.url) assert(path) path = fs.posix_to_os_path(path) @@ -579,16 +579,16 @@ M.perform_action = function(action, cb) end) end - if action.entry_type == "directory" then + if action.entry_type == 'directory' then uv.fs_mkdir(path, config.new_dir_mode, function(err) -- Ignore if the directory already exists - if not err or err:match("^EEXIST:") then + if not err or err:match('^EEXIST:') then cb() else cb(err) end end) - elseif action.entry_type == "link" and action.link then + elseif action.entry_type == 'link' and action.link then local flags = nil local target = fs.posix_to_os_path(action.link) if fs.is_windows then @@ -602,7 +602,7 @@ M.perform_action = function(action, cb) else fs.touch(path, config.new_file_mode, cb) end - elseif action.type == "delete" then + elseif action.type == 'delete' then local _, path = util.parse_url(action.url) assert(path) path = fs.posix_to_os_path(path) @@ -619,11 +619,11 @@ M.perform_action = function(action, cb) end if config.delete_to_trash then - require("oil.adapters.trash").delete_to_trash(path, cb) + require('oil.adapters.trash').delete_to_trash(path, cb) else fs.recursive_delete(action.entry_type, path, cb) end - elseif action.type == "move" then + elseif action.type == 'move' then local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) if dest_adapter == M then local _, src_path = util.parse_url(action.src_url) @@ -641,7 +641,7 @@ M.perform_action = function(action, cb) -- We should never hit this because we don't implement supported_cross_adapter_actions cb("files adapter doesn't support cross-adapter move") end - elseif action.type == "copy" then + elseif action.type == 'copy' then local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) if dest_adapter == M then local _, src_path = util.parse_url(action.src_url) @@ -656,7 +656,7 @@ M.perform_action = function(action, cb) cb("files adapter doesn't support cross-adapter copy") end else - cb(string.format("Bad action type: %s", action.type)) + cb(string.format('Bad action type: %s', action.type)) end end diff --git a/lua/oil/adapters/files/permissions.lua b/lua/oil/adapters/files/permissions.lua index 6c306a6..32c8488 100644 --- a/lua/oil/adapters/files/permissions.lua +++ b/lua/oil/adapters/files/permissions.lua @@ -4,7 +4,7 @@ local M = {} ---@param num integer ---@return string local function perm_to_str(exe_modifier, num) - local str = (bit.band(num, 4) ~= 0 and "r" or "-") .. (bit.band(num, 2) ~= 0 and "w" or "-") + local str = (bit.band(num, 4) ~= 0 and 'r' or '-') .. (bit.band(num, 2) ~= 0 and 'w' or '-') if exe_modifier then if bit.band(num, 1) ~= 0 then return str .. exe_modifier @@ -12,7 +12,7 @@ local function perm_to_str(exe_modifier, num) return str .. exe_modifier:upper() end else - return str .. (bit.band(num, 1) ~= 0 and "x" or "-") + return str .. (bit.band(num, 1) ~= 0 and 'x' or '-') end end @@ -20,9 +20,9 @@ end ---@return string M.mode_to_str = function(mode) local extra = bit.rshift(mode, 9) - return perm_to_str(bit.band(extra, 4) ~= 0 and "s", bit.rshift(mode, 6)) - .. perm_to_str(bit.band(extra, 2) ~= 0 and "s", bit.rshift(mode, 3)) - .. perm_to_str(bit.band(extra, 1) ~= 0 and "t", mode) + return perm_to_str(bit.band(extra, 4) ~= 0 and 's', bit.rshift(mode, 6)) + .. perm_to_str(bit.band(extra, 2) ~= 0 and 's', bit.rshift(mode, 3)) + .. perm_to_str(bit.band(extra, 1) ~= 0 and 't', mode) end ---@param mode integer @@ -38,25 +38,25 @@ end ---@param str string String of 3 characters ---@return nil|integer local function str_to_mode(str) - local r, w, x = unpack(vim.split(str, "", {})) + local r, w, x = unpack(vim.split(str, '', {})) local mode = 0 - if r == "r" then + if r == 'r' then mode = bit.bor(mode, 4) - elseif r ~= "-" then + elseif r ~= '-' then return nil end - if w == "w" then + if w == 'w' then mode = bit.bor(mode, 2) - elseif w ~= "-" then + elseif w ~= '-' then return nil end -- t means sticky and executable -- T means sticky, not executable -- s means setuid/setgid and executable -- S means setuid/setgid and not executable - if x == "x" or x == "t" or x == "s" then + if x == 'x' or x == 't' or x == 's' then mode = bit.bor(mode, 1) - elseif x ~= "-" and x ~= "T" and x ~= "S" then + elseif x ~= '-' and x ~= 'T' and x ~= 'S' then return nil end return mode @@ -67,13 +67,13 @@ end local function parse_extra_bits(perm) perm = perm:lower() local mode = 0 - if perm:sub(3, 3) == "s" then + if perm:sub(3, 3) == 's' then mode = bit.bor(mode, 4) end - if perm:sub(6, 6) == "s" then + if perm:sub(6, 6) == 's' then mode = bit.bor(mode, 2) end - if perm:sub(9, 9) == "t" then + if perm:sub(9, 9) == 't' then mode = bit.bor(mode, 1) end return mode @@ -83,7 +83,7 @@ end ---@return nil|integer ---@return nil|string M.parse = function(line) - local strval, rem = line:match("^([r%-][w%-][xsS%-][r%-][w%-][xsS%-][r%-][w%-][xtT%-])%s*(.*)$") + local strval, rem = line:match('^([r%-][w%-][xsS%-][r%-][w%-][xsS%-][r%-][w%-][xtT%-])%s*(.*)$') if not strval then return end diff --git a/lua/oil/adapters/s3.lua b/lua/oil/adapters/s3.lua index b7b5400..81557c7 100644 --- a/lua/oil/adapters/s3.lua +++ b/lua/oil/adapters/s3.lua @@ -1,11 +1,11 @@ -local config = require("oil.config") -local constants = require("oil.constants") -local files = require("oil.adapters.files") -local fs = require("oil.fs") -local loading = require("oil.loading") -local pathutil = require("oil.pathutil") -local s3fs = require("oil.adapters.s3.s3fs") -local util = require("oil.util") +local config = require('oil.config') +local constants = require('oil.constants') +local files = require('oil.adapters.files') +local fs = require('oil.fs') +local loading = require('oil.loading') +local pathutil = require('oil.pathutil') +local s3fs = require('oil.adapters.s3.s3fs') +local util = require('oil.util') local M = {} local FIELD_META = constants.FIELD_META @@ -21,11 +21,11 @@ M.parse_url = function(oil_url) local scheme, url = util.parse_url(oil_url) assert(scheme and url, string.format("Malformed input url '%s'", oil_url)) local ret = { scheme = scheme } - local bucket, path = url:match("^([^/]+)/?(.*)$") + local bucket, path = url:match('^([^/]+)/?(.*)$') ret.bucket = bucket - ret.path = path ~= "" and path or nil + ret.path = path ~= '' and path or nil if not ret.bucket and ret.path then - error(string.format("Parsing error for s3 url: %s", oil_url)) + error(string.format('Parsing error for s3 url: %s', oil_url)) end ---@cast ret oil.s3Url return ret @@ -36,43 +36,43 @@ end local function url_to_str(url) local pieces = { url.scheme } if url.bucket then - assert(url.bucket ~= "") + assert(url.bucket ~= '') table.insert(pieces, url.bucket) - table.insert(pieces, "/") + table.insert(pieces, '/') end if url.path then - assert(url.path ~= "") + assert(url.path ~= '') table.insert(pieces, url.path) end - return table.concat(pieces, "") + return table.concat(pieces, '') end ---@param url oil.s3Url ---@param is_folder boolean ---@return string local function url_to_s3(url, is_folder) - local pieces = { "s3://" } + local pieces = { 's3://' } if url.bucket then - assert(url.bucket ~= "") + assert(url.bucket ~= '') table.insert(pieces, url.bucket) - table.insert(pieces, "/") + table.insert(pieces, '/') end if url.path then - assert(url.path ~= "") + assert(url.path ~= '') table.insert(pieces, url.path) - if is_folder and not vim.endswith(url.path, "/") then - table.insert(pieces, "/") + if is_folder and not vim.endswith(url.path, '/') then + table.insert(pieces, '/') end end - return table.concat(pieces, "") + return table.concat(pieces, '') end ---@param url oil.s3Url ---@return boolean local function is_bucket(url) - assert(url.bucket and url.bucket ~= "") + assert(url.bucket and url.bucket ~= '') if url.path then - assert(url.path ~= "") + assert(url.path ~= '') return false end return true @@ -83,20 +83,20 @@ s3_columns.size = { render = function(entry, conf) local meta = entry[FIELD_META] if not meta or not meta.size then - return "" + return '' elseif meta.size >= 1e9 then - return string.format("%.1fG", meta.size / 1e9) + return string.format('%.1fG', meta.size / 1e9) elseif meta.size >= 1e6 then - return string.format("%.1fM", meta.size / 1e6) + return string.format('%.1fM', meta.size / 1e6) elseif meta.size >= 1e3 then - return string.format("%.1fk", meta.size / 1e3) + return string.format('%.1fk', meta.size / 1e3) else - return string.format("%d", meta.size) + return string.format('%d', meta.size) end end, parse = function(line, conf) - return line:match("^(%d+%S*)%s+(.*)$") + return line:match('^(%d+%S*)%s+(.*)$') end, get_sort_value = function(entry) @@ -113,21 +113,21 @@ s3_columns.birthtime = { render = function(entry, conf) local meta = entry[FIELD_META] if not meta or not meta.date then - return "" + return '' else return meta.date end end, parse = function(line, conf) - return line:match("^(%d+%-%d+%-%d+%s%d+:%d+:%d+)%s+(.*)$") + return line:match('^(%d+%-%d+%-%d+%s%d+:%d+:%d+)%s+(.*)$') end, get_sort_value = function(entry) local meta = entry[FIELD_META] if meta and meta.date then local year, month, day, hour, min, sec = - meta.date:match("^(%d+)%-(%d+)%-(%d+)%s(%d+):(%d+):(%d+)$") + meta.date:match('^(%d+)%-(%d+)%-(%d+)%s(%d+):(%d+):(%d+)$') local time = os.time({ year = year, month = month, day = day, hour = hour, min = min, sec = sec }) return time @@ -148,9 +148,9 @@ end M.get_parent = function(bufname) local res = M.parse_url(bufname) if res.path then - assert(res.path ~= "") + assert(res.path ~= '') local path = pathutil.parent(res.path) - res.path = path ~= "" and path or nil + res.path = path ~= '' and path or nil else res.bucket = nil end @@ -168,8 +168,8 @@ end ---@param column_defs string[] ---@param callback fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) M.list = function(url, column_defs, callback) - if vim.fn.executable("aws") ~= 1 then - callback("`aws` is not executable. Can you run `aws s3 ls`?") + if vim.fn.executable('aws') ~= 1 then + callback('`aws` is not executable. Can you run `aws s3 ls`?') return end @@ -187,16 +187,16 @@ end ---@param action oil.Action ---@return string M.render_action = function(action) - local is_folder = action.entry_type == "directory" - if action.type == "create" then + local is_folder = action.entry_type == 'directory' + if action.type == 'create' then local res = M.parse_url(action.url) - local extra = is_bucket(res) and "BUCKET " or "" - return string.format("CREATE %s%s", extra, url_to_s3(res, is_folder)) - elseif action.type == "delete" then + local extra = is_bucket(res) and 'BUCKET ' or '' + return string.format('CREATE %s%s', extra, url_to_s3(res, is_folder)) + elseif action.type == 'delete' then local res = M.parse_url(action.url) - local extra = is_bucket(res) and "BUCKET " or "" - return string.format("DELETE %s%s", extra, url_to_s3(res, is_folder)) - elseif action.type == "move" or action.type == "copy" then + local extra = is_bucket(res) and 'BUCKET ' or '' + return string.format('DELETE %s%s', extra, url_to_s3(res, is_folder)) + elseif action.type == 'move' or action.type == 'copy' then local src = action.src_url local dest = action.dest_url if config.get_adapter_by_scheme(src) ~= M then @@ -210,7 +210,7 @@ M.render_action = function(action) dest = files.to_short_os_path(path, action.entry_type) src = url_to_s3(M.parse_url(src), is_folder) end - return string.format(" %s %s -> %s", action.type:upper(), src, dest) + return string.format(' %s %s -> %s', action.type:upper(), src, dest) else error(string.format("Bad action type: '%s'", action.type)) end @@ -219,30 +219,30 @@ end ---@param action oil.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) - local is_folder = action.entry_type == "directory" - if action.type == "create" then + local is_folder = action.entry_type == 'directory' + if action.type == 'create' then local res = M.parse_url(action.url) local bucket = is_bucket(res) - if action.entry_type == "directory" and bucket then + if action.entry_type == 'directory' and bucket then s3fs.mb(url_to_s3(res, true), cb) - elseif action.entry_type == "directory" or action.entry_type == "file" then + elseif action.entry_type == 'directory' or action.entry_type == 'file' then s3fs.touch(url_to_s3(res, is_folder), cb) else - cb(string.format("Bad entry type on s3 create action: %s", action.entry_type)) + cb(string.format('Bad entry type on s3 create action: %s', action.entry_type)) end - elseif action.type == "delete" then + elseif action.type == 'delete' then local res = M.parse_url(action.url) local bucket = is_bucket(res) - if action.entry_type == "directory" and bucket then + if action.entry_type == 'directory' and bucket then s3fs.rb(url_to_s3(res, true), cb) - elseif action.entry_type == "directory" or action.entry_type == "file" then + elseif action.entry_type == 'directory' or action.entry_type == 'file' then s3fs.rm(url_to_s3(res, is_folder), is_folder, cb) else - cb(string.format("Bad entry type on s3 delete action: %s", action.entry_type)) + cb(string.format('Bad entry type on s3 delete action: %s', action.entry_type)) end - elseif action.type == "move" then + elseif action.type == 'move' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) if @@ -250,7 +250,7 @@ M.perform_action = function(action, cb) then cb( string.format( - "We should never attempt to move from the %s adapter to the %s adapter.", + 'We should never attempt to move from the %s adapter to the %s adapter.', src_adapter.name, dest_adapter.name ) @@ -276,7 +276,7 @@ M.perform_action = function(action, cb) assert(dest) s3fs.mv(src, dest, is_folder, cb) - elseif action.type == "copy" then + elseif action.type == 'copy' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) if @@ -284,7 +284,7 @@ M.perform_action = function(action, cb) then cb( string.format( - "We should never attempt to copy from the %s adapter to the %s adapter.", + 'We should never attempt to copy from the %s adapter to the %s adapter.', src_adapter.name, dest_adapter.name ) @@ -311,11 +311,11 @@ M.perform_action = function(action, cb) s3fs.cp(src, dest, is_folder, cb) else - cb(string.format("Bad action type: %s", action.type)) + cb(string.format('Bad action type: %s', action.type)) end end -M.supported_cross_adapter_actions = { files = "move" } +M.supported_cross_adapter_actions = { files = 'move' } ---@param bufnr integer M.read_file = function(bufnr) @@ -323,11 +323,11 @@ M.read_file = function(bufnr) local bufname = vim.api.nvim_buf_get_name(bufnr) local url = M.parse_url(bufname) local basename = pathutil.basename(bufname) - local cache_dir = vim.fn.stdpath("cache") - assert(type(cache_dir) == "string") - local tmpdir = fs.join(cache_dir, "oil") + local cache_dir = vim.fn.stdpath('cache') + assert(type(cache_dir) == 'string') + local tmpdir = fs.join(cache_dir, 'oil') fs.mkdirp(tmpdir) - local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, "s3_XXXXXX")) + local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, 's3_XXXXXX')) if fd then vim.loop.fs_close(fd) end @@ -336,9 +336,9 @@ M.read_file = function(bufnr) s3fs.cp(url_to_s3(url, false), tmpfile, false, function(err) loading.set_loading(bufnr, false) vim.bo[bufnr].modifiable = true - vim.cmd.doautocmd({ args = { "BufReadPre", bufname }, mods = { silent = true } }) + vim.cmd.doautocmd({ args = { 'BufReadPre', bufname }, mods = { silent = true } }) if err then - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, vim.split(err, "\n")) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, vim.split(err, '\n')) else vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {}) vim.api.nvim_buf_call(bufnr, function() @@ -352,7 +352,7 @@ M.read_file = function(bufnr) if filetype then vim.bo[bufnr].filetype = filetype end - vim.cmd.doautocmd({ args = { "BufReadPost", bufname }, mods = { silent = true } }) + vim.cmd.doautocmd({ args = { 'BufReadPost', bufname }, mods = { silent = true } }) vim.api.nvim_buf_delete(tmp_bufnr, { force = true }) end) end @@ -361,14 +361,14 @@ end M.write_file = function(bufnr) local bufname = vim.api.nvim_buf_get_name(bufnr) local url = M.parse_url(bufname) - local cache_dir = vim.fn.stdpath("cache") - assert(type(cache_dir) == "string") - local tmpdir = fs.join(cache_dir, "oil") - local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, "s3_XXXXXXXX")) + local cache_dir = vim.fn.stdpath('cache') + assert(type(cache_dir) == 'string') + local tmpdir = fs.join(cache_dir, 'oil') + local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, 's3_XXXXXXXX')) if fd then vim.loop.fs_close(fd) end - vim.cmd.doautocmd({ args = { "BufWritePre", bufname }, mods = { silent = true } }) + vim.cmd.doautocmd({ args = { 'BufWritePre', bufname }, mods = { silent = true } }) vim.bo[bufnr].modifiable = false vim.cmd.write({ args = { tmpfile }, bang = true, mods = { silent = true, noautocmd = true } }) local tmp_bufnr = vim.fn.bufadd(tmpfile) @@ -376,10 +376,10 @@ M.write_file = function(bufnr) s3fs.cp(tmpfile, url_to_s3(url, false), false, function(err) vim.bo[bufnr].modifiable = true if err then - vim.notify(string.format("Error writing file: %s", err), vim.log.levels.ERROR) + vim.notify(string.format('Error writing file: %s', err), vim.log.levels.ERROR) else vim.bo[bufnr].modified = false - vim.cmd.doautocmd({ args = { "BufWritePost", bufname }, mods = { silent = true } }) + vim.cmd.doautocmd({ args = { 'BufWritePost', bufname }, mods = { silent = true } }) end vim.loop.fs_unlink(tmpfile) vim.api.nvim_buf_delete(tmp_bufnr, { force = true }) diff --git a/lua/oil/adapters/s3/s3fs.lua b/lua/oil/adapters/s3/s3fs.lua index 2e16307..a81f10c 100644 --- a/lua/oil/adapters/s3/s3fs.lua +++ b/lua/oil/adapters/s3/s3fs.lua @@ -1,8 +1,8 @@ -local cache = require("oil.cache") -local config = require("oil.config") -local constants = require("oil.constants") -local shell = require("oil.shell") -local util = require("oil.util") +local cache = require('oil.cache') +local config = require('oil.config') +local constants = require('oil.constants') +local shell = require('oil.shell') +local util = require('oil.util') local M = {} @@ -13,11 +13,11 @@ local FIELD_META = constants.FIELD_META ---@return oil.EntryType ---@return table Metadata for entry local function parse_ls_line_bucket(line) - local date, name = line:match("^(%d+%-%d+%-%d+%s%d+:%d+:%d+)%s+(.*)$") + local date, name = line:match('^(%d+%-%d+%-%d+%s%d+:%d+:%d+)%s+(.*)$') if not date or not name then error(string.format("Could not parse '%s'", line)) end - local type = "directory" + local type = 'directory' local meta = { date = date } return name, type, meta end @@ -27,18 +27,18 @@ end ---@return oil.EntryType ---@return table Metadata for entry local function parse_ls_line_file(line) - local name = line:match("^%s+PRE%s+(.*)/$") - local type = "directory" + local name = line:match('^%s+PRE%s+(.*)/$') + local type = 'directory' local meta = {} if name then return name, type, meta end local date, size - date, size, name = line:match("^(%d+%-%d+%-%d+%s%d+:%d+:%d+)%s+(%d+)%s+(.*)$") + date, size, name = line:match('^(%d+%-%d+%-%d+%s%d+:%d+:%d+)%s+(%d+)%s+(.*)$') if not name then error(string.format("Could not parse '%s'", line)) end - type = "file" + type = 'file' meta = { date = date, size = tonumber(size) } return name, type, meta end @@ -46,7 +46,7 @@ end ---@param cmd string[] cmd and flags ---@return string[] Shell command to run local function create_s3_command(cmd) - local full_cmd = vim.list_extend({ "aws", "s3" }, cmd) + local full_cmd = vim.list_extend({ 'aws', 's3' }, cmd) return vim.list_extend(full_cmd, config.extra_s3_args) end @@ -54,7 +54,7 @@ end ---@param path string ---@param callback fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) function M.list_dir(url, path, callback) - local cmd = create_s3_command({ "ls", path, "--color=off", "--no-cli-pager" }) + local cmd = create_s3_command({ 'ls', path, '--color=off', '--no-cli-pager' }) shell.run(cmd, function(err, lines) if err then return callback(err) @@ -63,13 +63,13 @@ function M.list_dir(url, path, callback) local cache_entries = {} local url_path, _ _, url_path = util.parse_url(url) - local is_top_level = url_path == nil or url_path:match("/") == nil + local is_top_level = url_path == nil or url_path:match('/') == nil local parse_ls_line = is_top_level and parse_ls_line_bucket or parse_ls_line_file for _, line in ipairs(lines) do - if line ~= "" then + if line ~= '' then local name, type, meta = parse_ls_line(line) -- in s3 '-' can be used to create an "empty folder" - if name ~= "-" then + if name ~= '-' then local cache_entry = cache.create_entry(url, name, type) table.insert(cache_entries, cache_entry) cache_entry[FIELD_META] = meta @@ -85,8 +85,8 @@ end ---@param callback fun(err: nil|string) function M.touch(path, callback) -- here "-" means that we copy from stdin - local cmd = create_s3_command({ "cp", "-", path }) - shell.run(cmd, { stdin = "null" }, callback) + local cmd = create_s3_command({ 'cp', '-', path }) + shell.run(cmd, { stdin = 'null' }, callback) end --- Remove files @@ -94,9 +94,9 @@ end ---@param is_folder boolean ---@param callback fun(err: nil|string) function M.rm(path, is_folder, callback) - local main_cmd = { "rm", path } + local main_cmd = { 'rm', path } if is_folder then - table.insert(main_cmd, "--recursive") + table.insert(main_cmd, '--recursive') end local cmd = create_s3_command(main_cmd) shell.run(cmd, callback) @@ -106,7 +106,7 @@ end ---@param bucket string ---@param callback fun(err: nil|string) function M.rb(bucket, callback) - local cmd = create_s3_command({ "rb", bucket }) + local cmd = create_s3_command({ 'rb', bucket }) shell.run(cmd, callback) end @@ -114,7 +114,7 @@ end ---@param bucket string ---@param callback fun(err: nil|string) function M.mb(bucket, callback) - local cmd = create_s3_command({ "mb", bucket }) + local cmd = create_s3_command({ 'mb', bucket }) shell.run(cmd, callback) end @@ -124,9 +124,9 @@ end ---@param is_folder boolean ---@param callback fun(err: nil|string) function M.mv(src, dest, is_folder, callback) - local main_cmd = { "mv", src, dest } + local main_cmd = { 'mv', src, dest } if is_folder then - table.insert(main_cmd, "--recursive") + table.insert(main_cmd, '--recursive') end local cmd = create_s3_command(main_cmd) shell.run(cmd, callback) @@ -138,9 +138,9 @@ end ---@param is_folder boolean ---@param callback fun(err: nil|string) function M.cp(src, dest, is_folder, callback) - local main_cmd = { "cp", src, dest } + local main_cmd = { 'cp', src, dest } if is_folder then - table.insert(main_cmd, "--recursive") + table.insert(main_cmd, '--recursive') end local cmd = create_s3_command(main_cmd) shell.run(cmd, callback) diff --git a/lua/oil/adapters/ssh.lua b/lua/oil/adapters/ssh.lua index ae4291f..b78d02f 100644 --- a/lua/oil/adapters/ssh.lua +++ b/lua/oil/adapters/ssh.lua @@ -1,13 +1,13 @@ -local config = require("oil.config") -local constants = require("oil.constants") -local files = require("oil.adapters.files") -local fs = require("oil.fs") -local loading = require("oil.loading") -local pathutil = require("oil.pathutil") -local permissions = require("oil.adapters.files.permissions") -local shell = require("oil.shell") -local sshfs = require("oil.adapters.ssh.sshfs") -local util = require("oil.util") +local config = require('oil.config') +local constants = require('oil.constants') +local files = require('oil.adapters.files') +local fs = require('oil.fs') +local loading = require('oil.loading') +local pathutil = require('oil.pathutil') +local permissions = require('oil.adapters.files.permissions') +local shell = require('oil.shell') +local sshfs = require('oil.adapters.ssh.sshfs') +local util = require('oil.util') local M = {} local FIELD_NAME = constants.FIELD_NAME @@ -22,7 +22,7 @@ local FIELD_META = constants.FIELD_META ---@param args string[] local function scp(args, ...) - local cmd = vim.list_extend({ "scp", "-C" }, config.extra_scp_args) + local cmd = vim.list_extend({ 'scp', '-C' }, config.extra_scp_args) vim.list_extend(cmd, args) shell.run(cmd, ...) end @@ -33,21 +33,21 @@ M.parse_url = function(oil_url) local scheme, url = util.parse_url(oil_url) assert(scheme and url, string.format("Malformed input url '%s'", oil_url)) local ret = { scheme = scheme } - local username, rem = url:match("^([^@%s]+)@(.*)$") + local username, rem = url:match('^([^@%s]+)@(.*)$') ret.user = username url = rem or url - local host, port, path = url:match("^([^:]+):(%d+)/(.*)$") + local host, port, path = url:match('^([^:]+):(%d+)/(.*)$') if host then ret.host = host ret.port = tonumber(port) ret.path = path else - host, path = url:match("^([^/]+)/(.*)$") + host, path = url:match('^([^/]+)/(.*)$') ret.host = host ret.path = path end if not ret.host or not ret.path then - error(string.format("Malformed SSH url: %s", oil_url)) + error(string.format('Malformed SSH url: %s', oil_url)) end ---@cast ret oil.sshUrl @@ -60,33 +60,33 @@ local function url_to_str(url) local pieces = { url.scheme } if url.user then table.insert(pieces, url.user) - table.insert(pieces, "@") + table.insert(pieces, '@') end table.insert(pieces, url.host) if url.port then - table.insert(pieces, string.format(":%d", url.port)) + table.insert(pieces, string.format(':%d', url.port)) end - table.insert(pieces, "/") + table.insert(pieces, '/') table.insert(pieces, url.path) - return table.concat(pieces, "") + return table.concat(pieces, '') end ---@param url oil.sshUrl ---@return string local function url_to_scp(url) - local pieces = { "scp://" } + local pieces = { 'scp://' } if url.user then table.insert(pieces, url.user) - table.insert(pieces, "@") + table.insert(pieces, '@') end table.insert(pieces, url.host) if url.port then - table.insert(pieces, string.format(":%d", url.port)) + table.insert(pieces, string.format(':%d', url.port)) end - table.insert(pieces, "/") + table.insert(pieces, '/') local escaped_path = util.url_escape(url.path) table.insert(pieces, escaped_path) - return table.concat(pieces, "") + return table.concat(pieces, '') end ---@param url1 oil.sshUrl @@ -103,7 +103,7 @@ local _connections = {} local function get_connection(url, allow_retry) local res = M.parse_url(url) res.scheme = config.adapter_to_scheme.ssh - res.path = "" + res.path = '' local key = url_to_str(res) local conn = _connections[key] if not conn or (allow_retry and conn:get_connection_error()) then @@ -137,7 +137,7 @@ ssh_columns.permissions = { end, render_action = function(action) - return string.format("CHMOD %s %s", permissions.mode_to_octal_str(action.value), action.url) + return string.format('CHMOD %s %s', permissions.mode_to_octal_str(action.value), action.url) end, perform_action = function(action, callback) @@ -151,20 +151,20 @@ ssh_columns.size = { render = function(entry, conf) local meta = entry[FIELD_META] if not meta or not meta.size then - return "" + return '' elseif meta.size >= 1e9 then - return string.format("%.1fG", meta.size / 1e9) + return string.format('%.1fG', meta.size / 1e9) elseif meta.size >= 1e6 then - return string.format("%.1fM", meta.size / 1e6) + return string.format('%.1fM', meta.size / 1e6) elseif meta.size >= 1e3 then - return string.format("%.1fk", meta.size / 1e3) + return string.format('%.1fk', meta.size / 1e3) else - return string.format("%d", meta.size) + return string.format('%d', meta.size) end end, parse = function(line, conf) - return line:match("^(%d+%S*)%s+(.*)$") + return line:match('^(%d+%S*)%s+(.*)$') end, get_sort_value = function(entry) @@ -206,13 +206,13 @@ M.normalize_url = function(url, callback) local conn = get_connection(url, true) local path = res.path - if path == "" then - path = "." + if path == '' then + path = '.' end conn:realpath(path, function(err, abspath) if err then - vim.notify(string.format("Error normalizing url %s: %s", url, err), vim.log.levels.WARN) + vim.notify(string.format('Error normalizing url %s: %s', url, err), vim.log.levels.WARN) callback(url) else res.path = abspath @@ -259,15 +259,15 @@ end ---@param action oil.Action ---@return string M.render_action = function(action) - if action.type == "create" then - local ret = string.format("CREATE %s", action.url) + if action.type == 'create' then + local ret = string.format('CREATE %s', action.url) if action.link then - ret = ret .. " -> " .. action.link + ret = ret .. ' -> ' .. action.link end return ret - elseif action.type == "delete" then - return string.format("DELETE %s", action.url) - elseif action.type == "move" or action.type == "copy" then + elseif action.type == 'delete' then + return string.format('DELETE %s', action.url) + elseif action.type == 'move' or action.type == 'copy' then local src = action.src_url local dest = action.dest_url if config.get_adapter_by_scheme(src) == M then @@ -279,7 +279,7 @@ M.render_action = function(action) assert(path) src = files.to_short_os_path(path, action.entry_type) end - return string.format(" %s %s -> %s", action.type:upper(), src, dest) + return string.format(' %s %s -> %s', action.type:upper(), src, dest) else error(string.format("Bad action type: '%s'", action.type)) end @@ -288,21 +288,21 @@ end ---@param action oil.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) - if action.type == "create" then + if action.type == 'create' then local res = M.parse_url(action.url) local conn = get_connection(action.url) - if action.entry_type == "directory" then + if action.entry_type == 'directory' then conn:mkdir(res.path, cb) - elseif action.entry_type == "link" and action.link then + elseif action.entry_type == 'link' and action.link then conn:mklink(res.path, action.link, cb) else conn:touch(res.path, cb) end - elseif action.type == "delete" then + elseif action.type == 'delete' then local res = M.parse_url(action.url) local conn = get_connection(action.url) conn:rm(res.path, cb) - elseif action.type == "move" then + elseif action.type == 'move' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) if src_adapter == M and dest_adapter == M then @@ -311,7 +311,7 @@ M.perform_action = function(action, cb) local src_conn = get_connection(action.src_url) local dest_conn = get_connection(action.dest_url) if src_conn ~= dest_conn then - scp({ "-r", url_to_scp(src_res), url_to_scp(dest_res) }, function(err) + scp({ '-r', url_to_scp(src_res), url_to_scp(dest_res) }, function(err) if err then return cb(err) end @@ -321,16 +321,16 @@ M.perform_action = function(action, cb) src_conn:mv(src_res.path, dest_res.path, cb) end else - cb("We should never attempt to move across adapters") + cb('We should never attempt to move across adapters') end - elseif action.type == "copy" then + elseif action.type == 'copy' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) if src_adapter == M and dest_adapter == M then local src_res = M.parse_url(action.src_url) local dest_res = M.parse_url(action.dest_url) if not url_hosts_equal(src_res, dest_res) then - scp({ "-r", url_to_scp(src_res), url_to_scp(dest_res) }, cb) + scp({ '-r', url_to_scp(src_res), url_to_scp(dest_res) }, cb) else local src_conn = get_connection(action.src_url) src_conn:cp(src_res.path, dest_res.path, cb) @@ -349,14 +349,14 @@ M.perform_action = function(action, cb) src_arg = fs.posix_to_os_path(path) dest_arg = url_to_scp(M.parse_url(action.dest_url)) end - scp({ "-r", src_arg, dest_arg }, cb) + scp({ '-r', src_arg, dest_arg }, cb) end else - cb(string.format("Bad action type: %s", action.type)) + cb(string.format('Bad action type: %s', action.type)) end end -M.supported_cross_adapter_actions = { files = "copy" } +M.supported_cross_adapter_actions = { files = 'copy' } ---@param bufnr integer M.read_file = function(bufnr) @@ -365,11 +365,11 @@ M.read_file = function(bufnr) local url = M.parse_url(bufname) local scp_url = url_to_scp(url) local basename = pathutil.basename(bufname) - local cache_dir = vim.fn.stdpath("cache") - assert(type(cache_dir) == "string") - local tmpdir = fs.join(cache_dir, "oil") + local cache_dir = vim.fn.stdpath('cache') + assert(type(cache_dir) == 'string') + local tmpdir = fs.join(cache_dir, 'oil') fs.mkdirp(tmpdir) - local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, "ssh_XXXXXX")) + local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, 'ssh_XXXXXX')) if fd then vim.loop.fs_close(fd) end @@ -378,9 +378,9 @@ M.read_file = function(bufnr) scp({ scp_url, tmpfile }, function(err) loading.set_loading(bufnr, false) vim.bo[bufnr].modifiable = true - vim.cmd.doautocmd({ args = { "BufReadPre", bufname }, mods = { silent = true } }) + vim.cmd.doautocmd({ args = { 'BufReadPre', bufname }, mods = { silent = true } }) if err then - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, vim.split(err, "\n")) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, vim.split(err, '\n')) else vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {}) vim.api.nvim_buf_call(bufnr, function() @@ -394,9 +394,9 @@ M.read_file = function(bufnr) if filetype then vim.bo[bufnr].filetype = filetype end - vim.cmd.doautocmd({ args = { "BufReadPost", bufname }, mods = { silent = true } }) + vim.cmd.doautocmd({ args = { 'BufReadPost', bufname }, mods = { silent = true } }) vim.api.nvim_buf_delete(tmp_bufnr, { force = true }) - vim.keymap.set("n", "gf", M.goto_file, { buffer = bufnr }) + vim.keymap.set('n', 'gf', M.goto_file, { buffer = bufnr }) end) end @@ -405,14 +405,14 @@ M.write_file = function(bufnr) local bufname = vim.api.nvim_buf_get_name(bufnr) local url = M.parse_url(bufname) local scp_url = url_to_scp(url) - local cache_dir = vim.fn.stdpath("cache") - assert(type(cache_dir) == "string") - local tmpdir = fs.join(cache_dir, "oil") - local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, "ssh_XXXXXXXX")) + local cache_dir = vim.fn.stdpath('cache') + assert(type(cache_dir) == 'string') + local tmpdir = fs.join(cache_dir, 'oil') + local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, 'ssh_XXXXXXXX')) if fd then vim.loop.fs_close(fd) end - vim.cmd.doautocmd({ args = { "BufWritePre", bufname }, mods = { silent = true } }) + vim.cmd.doautocmd({ args = { 'BufWritePre', bufname }, mods = { silent = true } }) vim.bo[bufnr].modifiable = false vim.cmd.write({ args = { tmpfile }, bang = true, mods = { silent = true, noautocmd = true } }) local tmp_bufnr = vim.fn.bufadd(tmpfile) @@ -420,10 +420,10 @@ M.write_file = function(bufnr) scp({ tmpfile, scp_url }, function(err) vim.bo[bufnr].modifiable = true if err then - vim.notify(string.format("Error writing file: %s", err), vim.log.levels.ERROR) + vim.notify(string.format('Error writing file: %s', err), vim.log.levels.ERROR) else vim.bo[bufnr].modified = false - vim.cmd.doautocmd({ args = { "BufWritePost", bufname }, mods = { silent = true } }) + vim.cmd.doautocmd({ args = { 'BufWritePost', bufname }, mods = { silent = true } }) end vim.loop.fs_unlink(tmpfile) vim.api.nvim_buf_delete(tmp_bufnr, { force = true }) @@ -432,7 +432,7 @@ end M.goto_file = function() local url = M.parse_url(vim.api.nvim_buf_get_name(0)) - local fname = vim.fn.expand("") + local fname = vim.fn.expand('') local fullpath = fname if not fs.is_absolute(fname) then local pardir = vim.fs.dirname(url.path) @@ -459,7 +459,7 @@ M.goto_file = function() vim.cmd.edit({ args = { url_to_str(url) } }) return end - for suffix in vim.gsplit(vim.o.suffixesadd, ",", { plain = true, trimempty = true }) do + for suffix in vim.gsplit(vim.o.suffixesadd, ',', { plain = true, trimempty = true }) do local suffixname = basename .. suffix if name_map[suffixname] then url.path = fullpath .. suffix diff --git a/lua/oil/adapters/ssh/connection.lua b/lua/oil/adapters/ssh/connection.lua index 6a47c07..6dbaa49 100644 --- a/lua/oil/adapters/ssh/connection.lua +++ b/lua/oil/adapters/ssh/connection.lua @@ -1,6 +1,6 @@ -local config = require("oil.config") -local layout = require("oil.layout") -local util = require("oil.util") +local config = require('oil.config') +local layout = require('oil.layout') +local util = require('oil.util') ---@class (exact) oil.sshCommand ---@field cmd string|string[] @@ -24,12 +24,12 @@ local function output_extend(agg, output) local start = #agg if vim.tbl_isempty(agg) then for _, line in ipairs(output) do - line = line:gsub("\r", "") + line = line:gsub('\r', '') table.insert(agg, line) end else for i, v in ipairs(output) do - v = v:gsub("\r", "") + v = v:gsub('\r', '') if i == 1 then agg[#agg] = agg[#agg] .. v else @@ -53,7 +53,7 @@ local function get_last_lines(bufnr, num_lines) vim.api.nvim_buf_get_lines(bufnr, end_line - need_lines, end_line, false), lines ) - while not vim.tbl_isempty(lines) and lines[#lines]:match("^%s*$") do + while not vim.tbl_isempty(lines) and lines[#lines]:match('^%s*$') do table.remove(lines) end end_line = end_line - need_lines @@ -66,14 +66,14 @@ end function SSHConnection.create_ssh_command(url) local host = url.host if url.user then - host = url.user .. "@" .. host + host = url.user .. '@' .. host end local command = { - "ssh", + 'ssh', host, } if url.port then - table.insert(command, "-p") + table.insert(command, '-p') table.insert(command, url.port) end return command @@ -84,8 +84,8 @@ end function SSHConnection.new(url) local command = SSHConnection.create_ssh_command(url) vim.list_extend(command, { - "/bin/sh", - "-c", + '/bin/sh', + '-c', -- HACK: For some reason in my testing if I just have "echo READY" it doesn't appear, but if I echo -- anything prior to that, it *will* appear. The first line gets swallowed. "echo '_make_newline_'; echo '===READY==='; exec /bin/sh", @@ -112,7 +112,7 @@ function SSHConnection.new(url) }) end) self.term_id = term_id - vim.api.nvim_chan_send(term_id, string.format("ssh %s\r\n", url.host)) + vim.api.nvim_chan_send(term_id, string.format('ssh %s\r\n', url.host)) util.hack_around_termopen_autocmd(mode) -- If it takes more than 2 seconds to connect, pop open the terminal @@ -125,7 +125,7 @@ function SSHConnection.new(url) local jid = vim.fn.jobstart(command, { pty = true, -- This is require for interactivity on_stdout = function(j, output) - pcall(vim.api.nvim_chan_send, self.term_id, table.concat(output, "\r\n")) + pcall(vim.api.nvim_chan_send, self.term_id, table.concat(output, '\r\n')) ---@diagnostic disable-next-line: invisible local new_i_start = output_extend(self._stdout, output) self:_handle_output(new_i_start) @@ -134,12 +134,12 @@ function SSHConnection.new(url) pcall( vim.api.nvim_chan_send, self.term_id, - string.format("\r\n[Process exited %d]\r\n", code) + string.format('\r\n[Process exited %d]\r\n', code) ) -- Defer to allow the deferred terminal output handling to kick in first vim.defer_fn(function() if code == 0 then - self:_set_connection_error("SSH connection terminated gracefully") + self:_set_connection_error('SSH connection terminated gracefully') else self:_set_connection_error( 'Unknown SSH error\nTo see more, run :lua require("oil.adapters.ssh").open_terminal()' @@ -156,23 +156,23 @@ function SSHConnection.new(url) else self.jid = jid end - self:run("id -u", function(err, lines) + self:run('id -u', function(err, lines) if err then - vim.notify(string.format("Error fetching ssh connection user: %s", err), vim.log.levels.WARN) + vim.notify(string.format('Error fetching ssh connection user: %s', err), vim.log.levels.WARN) else assert(lines) - self.meta.user = vim.trim(table.concat(lines, "")) + self.meta.user = vim.trim(table.concat(lines, '')) end end) - self:run("id -G", function(err, lines) + self:run('id -G', function(err, lines) if err then vim.notify( - string.format("Error fetching ssh connection user groups: %s", err), + string.format('Error fetching ssh connection user groups: %s', err), vim.log.levels.WARN ) else assert(lines) - self.meta.groups = vim.split(table.concat(lines, ""), "%s+", { trimempty = true }) + self.meta.groups = vim.split(table.concat(lines, ''), '%s+', { trimempty = true }) end end) @@ -197,7 +197,7 @@ function SSHConnection:_handle_output(start_i) if not self.connected then for i = start_i, #self._stdout - 1 do local line = self._stdout[i] - if line == "===READY===" then + if line == '===READY===' then if self.term_winid then if vim.api.nvim_win_is_valid(self.term_winid) then vim.api.nvim_win_close(self.term_winid, true) @@ -215,7 +215,7 @@ function SSHConnection:_handle_output(start_i) for i = start_i, #self._stdout - 1 do ---@type string local line = self._stdout[i] - if line:match("^===BEGIN===%s*$") then + if line:match('^===BEGIN===%s*$') then self._stdout = util.tbl_slice(self._stdout, i + 1) self:_handle_output(1) return @@ -223,15 +223,15 @@ function SSHConnection:_handle_output(start_i) -- We can't be as strict with the matching (^$) because since we're using a pty the stdout and -- stderr can be interleaved. If the command had an error, the stderr may interfere with a -- clean print of the done line. - local exit_code = line:match("===DONE%((%d+)%)===") + local exit_code = line:match('===DONE%((%d+)%)===') if exit_code then local output = util.tbl_slice(self._stdout, 1, i - 1) local cb = self.commands[1].cb self._stdout = util.tbl_slice(self._stdout, i + 1) - if exit_code == "0" then + if exit_code == '0' then cb(nil, output) else - cb(exit_code .. ": " .. table.concat(output, "\n"), output) + cb(exit_code .. ': ' .. table.concat(output, '\n'), output) end table.remove(self.commands, 1) self:_handle_output(1) @@ -244,16 +244,17 @@ function SSHConnection:_handle_output(start_i) local function check_last_line() local last_lines = get_last_lines(self.term_bufnr, 1) local last_line = last_lines[1] - if last_line:match("^Are you sure you want to continue connecting") then + if last_line:match('^Are you sure you want to continue connecting') then self:open_terminal() - elseif last_line:match("Password:%s*$") then + -- selene: allow(if_same_then_else) + elseif last_line:match('Password:%s*$') then self:open_terminal() - elseif last_line:match(": Permission denied %(.+%)%.") then - self:_set_connection_error(last_line:match(": (Permission denied %(.+%).)")) - elseif last_line:match("^ssh: .*Connection refused%s*$") then - self:_set_connection_error("Connection refused") - elseif last_line:match("^Connection to .+ closed by remote host.%s*$") then - self:_set_connection_error("Connection closed by remote host") + elseif last_line:match(': Permission denied %(.+%)%.') then + self:_set_connection_error(last_line:match(': (Permission denied %(.+%).)')) + elseif last_line:match('^ssh: .*Connection refused%s*$') then + self:_set_connection_error('Connection refused') + elseif last_line:match('^Connection to .+ closed by remote host.%s*$') then + self:_set_connection_error('Connection closed by remote host') end end -- We have to defer this so the terminal buffer has time to update @@ -273,12 +274,12 @@ function SSHConnection:open_terminal() local row = math.floor((total_height - height) / 2) local col = math.floor((vim.o.columns - width) / 2) self.term_winid = vim.api.nvim_open_win(self.term_bufnr, true, { - relative = "editor", + relative = 'editor', width = width, height = height, row = row, col = col, - style = "minimal", + style = 'minimal', border = config.ssh.border, }) vim.cmd.startinsert() diff --git a/lua/oil/adapters/ssh/sshfs.lua b/lua/oil/adapters/ssh/sshfs.lua index 0dcc169..7d250f2 100644 --- a/lua/oil/adapters/ssh/sshfs.lua +++ b/lua/oil/adapters/ssh/sshfs.lua @@ -1,8 +1,8 @@ -local SSHConnection = require("oil.adapters.ssh.connection") -local cache = require("oil.cache") -local constants = require("oil.constants") -local permissions = require("oil.adapters.files.permissions") -local util = require("oil.util") +local SSHConnection = require('oil.adapters.ssh.connection') +local cache = require('oil.cache') +local constants = require('oil.constants') +local permissions = require('oil.adapters.files.permissions') +local util = require('oil.util') ---@class (exact) oil.sshFs ---@field new fun(url: oil.sshUrl): oil.sshFs @@ -13,13 +13,13 @@ local FIELD_TYPE = constants.FIELD_TYPE local FIELD_META = constants.FIELD_META local typechar_map = { - l = "link", - d = "directory", - p = "fifo", - s = "socket", - ["-"] = "file", - c = "file", -- character special file - b = "file", -- block special file + l = 'link', + d = 'directory', + p = 'fifo', + s = 'socket', + ['-'] = 'file', + c = 'file', -- character special file + b = 'file', -- block special file } ---@param line string ---@return string Name of entry @@ -27,11 +27,11 @@ local typechar_map = { ---@return table Metadata for entry local function parse_ls_line(line) local typechar, perms, refcount, user, group, rem = - line:match("^(.)(%S+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(.*)$") + line:match('^(.)(%S+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(.*)$') if not typechar then error(string.format("Could not parse '%s'", line)) end - local type = typechar_map[typechar] or "file" + local type = typechar_map[typechar] or 'file' local meta = { user = user, @@ -40,26 +40,26 @@ local function parse_ls_line(line) refcount = tonumber(refcount), } local name, size, date, major, minor - if typechar == "c" or typechar == "b" then - major, minor, date, name = rem:match("^(%d+)%s*,%s*(%d+)%s+(%S+%s+%d+%s+%d%d:?%d%d)%s+(.*)") + if typechar == 'c' or typechar == 'b' then + major, minor, date, name = rem:match('^(%d+)%s*,%s*(%d+)%s+(%S+%s+%d+%s+%d%d:?%d%d)%s+(.*)') if name == nil then major, minor, date, name = - rem:match("^(%d+)%s*,%s*(%d+)%s+(%d+%-%d+%-%d+%s+%d%d:?%d%d)%s+(.*)") + rem:match('^(%d+)%s*,%s*(%d+)%s+(%d+%-%d+%-%d+%s+%d%d:?%d%d)%s+(.*)') end meta.major = tonumber(major) meta.minor = tonumber(minor) else - size, date, name = rem:match("^(%d+)%s+(%S+%s+%d+%s+%d%d:?%d%d)%s+(.*)") + size, date, name = rem:match('^(%d+)%s+(%S+%s+%d+%s+%d%d:?%d%d)%s+(.*)') if name == nil then - size, date, name = rem:match("^(%d+)%s+(%d+%-%d+%-%d+%s+%d%d:?%d%d)%s+(.*)") + size, date, name = rem:match('^(%d+)%s+(%d+%-%d+%-%d+%s+%d%d:?%d%d)%s+(.*)') end meta.size = tonumber(size) end meta.iso_modified_date = date - if type == "link" then + if type == 'link' then local link - name, link = unpack(vim.split(name, " -> ", { plain = true })) - if vim.endswith(link, "/") then + name, link = unpack(vim.split(name, ' -> ', { plain = true })) + if vim.endswith(link, '/') then link = link:sub(1, #link - 1) end meta.link = link @@ -94,7 +94,7 @@ end ---@param callback fun(err: nil|string) function SSHFS:chmod(value, path, callback) local octal = permissions.mode_to_octal_str(value) - self.conn:run(string.format("chmod %s %s", octal, shellescape(path)), callback) + self.conn:run(string.format('chmod %s %s', octal, shellescape(path)), callback) end function SSHFS:open_terminal() @@ -114,24 +114,24 @@ function SSHFS:realpath(path, callback) return callback(err) end assert(lines) - local abspath = table.concat(lines, "") + local abspath = table.concat(lines, '') -- If the path was "." then the abspath might be /path/to/., so we need to trim that final '.' - if vim.endswith(abspath, ".") then + if vim.endswith(abspath, '.') then abspath = abspath:sub(1, #abspath - 1) end self.conn:run( - string.format("LC_ALL=C ls -land --color=never %s", shellescape(abspath)), + string.format('LC_ALL=C ls -land --color=never %s', shellescape(abspath)), function(ls_err, ls_lines) local type if ls_err then -- If the file doesn't exist, treat it like a not-yet-existing directory - type = "directory" + type = 'directory' else assert(ls_lines) local _ _, type = parse_ls_line(ls_lines[1]) end - if type == "directory" then + if type == 'directory' then abspath = util.addslash(abspath) end callback(nil, abspath) @@ -146,13 +146,13 @@ local dir_meta = {} ---@param path string ---@param callback fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) function SSHFS:list_dir(url, path, callback) - local path_postfix = "" - if path ~= "" then - path_postfix = string.format(" %s", shellescape(path)) + local path_postfix = '' + if path ~= '' then + path_postfix = string.format(' %s', shellescape(path)) end - self.conn:run("LC_ALL=C ls -lan --color=never" .. path_postfix, function(err, lines) + self.conn:run('LC_ALL=C ls -lan --color=never' .. path_postfix, function(err, lines) if err then - if err:match("No such file or directory%s*$") then + if err:match('No such file or directory%s*$') then -- If the directory doesn't exist, treat the list as a success. We will be able to traverse -- and edit a not-yet-existing directory. return callback() @@ -165,12 +165,12 @@ function SSHFS:list_dir(url, path, callback) local entries = {} local cache_entries = {} for _, line in ipairs(lines) do - if line ~= "" and not line:match("^total") then + if line ~= '' and not line:match('^total') then local name, type, meta = parse_ls_line(line) - if name == "." then + if name == '.' then dir_meta[url] = meta - elseif name ~= ".." then - if type == "link" then + elseif name ~= '..' then + if type == 'link' then any_links = true end local cache_entry = cache.create_entry(url, name, type) @@ -184,19 +184,19 @@ function SSHFS:list_dir(url, path, callback) -- If there were any soft links, then we need to run another ls command with -L so that we can -- resolve the type of the link target self.conn:run( - "LC_ALL=C ls -naLl --color=never" .. path_postfix .. " 2> /dev/null", + 'LC_ALL=C ls -naLl --color=never' .. path_postfix .. ' 2> /dev/null', function(link_err, link_lines) -- Ignore exit code 1. That just means one of the links could not be resolved. - if link_err and not link_err:match("^1:") then + if link_err and not link_err:match('^1:') then return callback(link_err) end assert(link_lines) for _, line in ipairs(link_lines) do - if line ~= "" and not line:match("^total") then + if line ~= '' and not line:match('^total') then local ok, name, type, meta = pcall(parse_ls_line, line) - if ok and name ~= "." and name ~= ".." then + if ok and name ~= '.' and name ~= '..' then local cache_entry = entries[name] - if cache_entry[FIELD_TYPE] == "link" then + if cache_entry[FIELD_TYPE] == 'link' then cache_entry[FIELD_META].link_stat = { type = type, size = meta.size, @@ -217,40 +217,40 @@ end ---@param path string ---@param callback fun(err: nil|string) function SSHFS:mkdir(path, callback) - self.conn:run(string.format("mkdir -p %s", shellescape(path)), callback) + self.conn:run(string.format('mkdir -p %s', shellescape(path)), callback) end ---@param path string ---@param callback fun(err: nil|string) function SSHFS:touch(path, callback) - self.conn:run(string.format("touch %s", shellescape(path)), callback) + self.conn:run(string.format('touch %s', shellescape(path)), callback) end ---@param path string ---@param link string ---@param callback fun(err: nil|string) function SSHFS:mklink(path, link, callback) - self.conn:run(string.format("ln -s %s %s", shellescape(link), shellescape(path)), callback) + self.conn:run(string.format('ln -s %s %s', shellescape(link), shellescape(path)), callback) end ---@param path string ---@param callback fun(err: nil|string) function SSHFS:rm(path, callback) - self.conn:run(string.format("rm -rf %s", shellescape(path)), callback) + self.conn:run(string.format('rm -rf %s', shellescape(path)), callback) end ---@param src string ---@param dest string ---@param callback fun(err: nil|string) function SSHFS:mv(src, dest, callback) - self.conn:run(string.format("mv %s %s", shellescape(src), shellescape(dest)), callback) + self.conn:run(string.format('mv %s %s', shellescape(src), shellescape(dest)), callback) end ---@param src string ---@param dest string ---@param callback fun(err: nil|string) function SSHFS:cp(src, dest, callback) - self.conn:run(string.format("cp -r %s %s", shellescape(src), shellescape(dest)), callback) + self.conn:run(string.format('cp -r %s %s', shellescape(src), shellescape(dest)), callback) end function SSHFS:get_dir_meta(url) diff --git a/lua/oil/adapters/test.lua b/lua/oil/adapters/test.lua index c4176ef..2e80e9a 100644 --- a/lua/oil/adapters/test.lua +++ b/lua/oil/adapters/test.lua @@ -1,5 +1,5 @@ -local cache = require("oil.cache") -local util = require("oil.util") +local cache = require('oil.cache') +local util = require('oil.util') local M = {} ---@param url string @@ -32,24 +32,24 @@ end ---@param entry_type oil.EntryType ---@return oil.InternalEntry M.test_set = function(path, entry_type) - if path == "/" then + if path == '/' then return {} end - local parent = vim.fn.fnamemodify(path, ":h") + local parent = vim.fn.fnamemodify(path, ':h') if parent ~= path then - M.test_set(parent, "directory") + M.test_set(parent, 'directory') end parent = util.addslash(parent) if not dir_listing[parent] then dir_listing[parent] = {} end - local name = vim.fn.fnamemodify(path, ":t") + local name = vim.fn.fnamemodify(path, ':t') local entry = { name = name, entry_type = entry_type, } table.insert(dir_listing[parent], entry) - local parent_url = "oil-test://" .. parent + local parent_url = 'oil-test://' .. parent return cache.create_and_store_entry(parent_url, entry.name, entry.entry_type) end @@ -68,12 +68,12 @@ end ---@param action oil.Action ---@return string M.render_action = function(action) - if action.type == "create" or action.type == "delete" then - return string.format("%s %s", action.type:upper(), action.url) - elseif action.type == "move" or action.type == "copy" then - return string.format(" %s %s -> %s", action.type:upper(), action.src_url, action.dest_url) + if action.type == 'create' or action.type == 'delete' then + return string.format('%s %s', action.type:upper(), action.url) + elseif action.type == 'move' or action.type == 'copy' then + return string.format(' %s %s -> %s', action.type:upper(), action.src_url, action.dest_url) else - error("Bad action type") + error('Bad action type') end end diff --git a/lua/oil/adapters/trash.lua b/lua/oil/adapters/trash.lua index b007074..9ec3e52 100644 --- a/lua/oil/adapters/trash.lua +++ b/lua/oil/adapters/trash.lua @@ -1,9 +1,9 @@ -local fs = require("oil.fs") +local fs = require('oil.fs') if fs.is_mac then - return require("oil.adapters.trash.mac") + return require('oil.adapters.trash.mac') elseif fs.is_windows then - return require("oil.adapters.trash.windows") + return require('oil.adapters.trash.windows') else - return require("oil.adapters.trash.freedesktop") + return require('oil.adapters.trash.freedesktop') end diff --git a/lua/oil/adapters/trash/freedesktop.lua b/lua/oil/adapters/trash/freedesktop.lua index 18b7e4c..1e1d34d 100644 --- a/lua/oil/adapters/trash/freedesktop.lua +++ b/lua/oil/adapters/trash/freedesktop.lua @@ -1,11 +1,11 @@ -- Based on the FreeDesktop.org trash specification -- https://specifications.freedesktop.org/trash/1.0/ -local cache = require("oil.cache") -local config = require("oil.config") -local constants = require("oil.constants") -local files = require("oil.adapters.files") -local fs = require("oil.fs") -local util = require("oil.util") +local cache = require('oil.cache') +local config = require('oil.config') +local constants = require('oil.constants') +local files = require('oil.adapters.files') +local fs = require('oil.fs') +local util = require('oil.util') local uv = vim.uv or vim.loop local FIELD_META = constants.FIELD_META @@ -14,8 +14,8 @@ local M = {} local function ensure_trash_dir(path) local mode = 448 -- 0700 - fs.mkdirp(fs.join(path, "info"), mode) - fs.mkdirp(fs.join(path, "files"), mode) + fs.mkdirp(fs.join(path, 'info'), mode) + fs.mkdirp(fs.join(path, 'files'), mode) end ---Gets the location of the home trash dir, creating it if necessary @@ -23,9 +23,9 @@ end local function get_home_trash_dir() local xdg_home = vim.env.XDG_DATA_HOME if not xdg_home then - xdg_home = fs.join(assert(uv.os_homedir()), ".local", "share") + xdg_home = fs.join(assert(uv.os_homedir()), '.local', 'share') end - local trash_dir = fs.join(xdg_home, "Trash") + local trash_dir = fs.join(xdg_home, 'Trash') ensure_trash_dir(trash_dir) return trash_dir end @@ -43,13 +43,13 @@ end local function get_top_trash_dirs(path) local dirs = {} local dev = (uv.fs_lstat(path) or {}).dev - local top_trash_dirs = vim.fs.find(".Trash", { upward = true, path = path, limit = math.huge }) + local top_trash_dirs = vim.fs.find('.Trash', { upward = true, path = path, limit = math.huge }) for _, top_trash_dir in ipairs(top_trash_dirs) do local stat = uv.fs_lstat(top_trash_dir) if stat and not dev then dev = stat.dev end - if stat and stat.dev == dev and stat.type == "directory" and is_sticky(stat.mode) then + if stat and stat.dev == dev and stat.type == 'directory' and is_sticky(stat.mode) then local trash_dir = fs.join(top_trash_dir, tostring(uv.getuid())) ensure_trash_dir(trash_dir) table.insert(dirs, trash_dir) @@ -58,7 +58,7 @@ local function get_top_trash_dirs(path) -- Also search for the .Trash-$uid top_trash_dirs = vim.fs.find( - string.format(".Trash-%d", uv.getuid()), + string.format('.Trash-%d', uv.getuid()), { upward = true, path = path, limit = math.huge } ) for _, top_trash_dir in ipairs(top_trash_dirs) do @@ -91,14 +91,14 @@ local function get_write_trash_dir(path) return top_trash_dirs[1] end - local parent = vim.fn.fnamemodify(path, ":h") - local next_parent = vim.fn.fnamemodify(parent, ":h") + local parent = vim.fn.fnamemodify(path, ':h') + local next_parent = vim.fn.fnamemodify(parent, ':h') while parent ~= next_parent and uv.fs_lstat(next_parent).dev == dev do parent = next_parent - next_parent = vim.fn.fnamemodify(parent, ":h") + next_parent = vim.fn.fnamemodify(parent, ':h') end - local top_trash = fs.join(parent, string.format(".Trash-%d", uv.getuid())) + local top_trash = fs.join(parent, string.format('.Trash-%d', uv.getuid())) ensure_trash_dir(top_trash) return top_trash end @@ -116,7 +116,7 @@ end M.normalize_url = function(url, callback) local scheme, path = util.parse_url(url) assert(path) - local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":p") + local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ':p') uv.fs_realpath( os_path, vim.schedule_wrap(function(err, new_os_path) @@ -140,10 +140,10 @@ M.get_entry_path = function(url, entry, cb) return end local path = fs.os_to_posix_path(trash_info.trash_file) - if meta.stat.type == "directory" then + if meta.stat.type == 'directory' then path = util.addslash(path) end - cb("oil://" .. path) + cb('oil://' .. path) end ---@class oil.TrashInfo @@ -156,10 +156,10 @@ end ---@param info_file string ---@param cb fun(err?: string, info?: oil.TrashInfo) local function read_trash_info(info_file, cb) - if not vim.endswith(info_file, ".trashinfo") then - return cb("File is not .trashinfo") + if not vim.endswith(info_file, '.trashinfo') then + return cb('File is not .trashinfo') end - uv.fs_open(info_file, "r", 448, function(err, fd) + uv.fs_open(info_file, 'r', 448, function(err, fd) if err then return cb(err) end @@ -182,32 +182,32 @@ local function read_trash_info(info_file, cb) local trash_info = { info_file = info_file, } - local lines = vim.split(content, "\r?\n") - if lines[1] ~= "[Trash Info]" then - return cb("File missing [Trash Info] header") + local lines = vim.split(content, '\r?\n') + if lines[1] ~= '[Trash Info]' then + return cb('File missing [Trash Info] header') end - local trash_base = vim.fn.fnamemodify(info_file, ":h:h") + local trash_base = vim.fn.fnamemodify(info_file, ':h:h') for _, line in ipairs(lines) do - local key, value = unpack(vim.split(line, "=", { plain = true, trimempty = true })) - if key == "Path" and not trash_info.original_path then - if not vim.startswith(value, "/") then + local key, value = unpack(vim.split(line, '=', { plain = true, trimempty = true })) + if key == 'Path' and not trash_info.original_path then + if not vim.startswith(value, '/') then value = fs.join(trash_base, value) end trash_info.original_path = value - elseif key == "DeletionDate" and not trash_info.deletion_date then - trash_info.deletion_date = vim.fn.strptime("%Y-%m-%dT%H:%M:%S", value) + elseif key == 'DeletionDate' and not trash_info.deletion_date then + trash_info.deletion_date = vim.fn.strptime('%Y-%m-%dT%H:%M:%S', value) end end if not trash_info.original_path or not trash_info.deletion_date then - return cb("File missing required fields") + return cb('File missing required fields') end - local basename = vim.fn.fnamemodify(info_file, ":t:r") - trash_info.trash_file = fs.join(trash_base, "files", basename) + local basename = vim.fn.fnamemodify(info_file, ':t:r') + trash_info.trash_file = fs.join(trash_base, 'files', basename) uv.fs_lstat(trash_info.trash_file, function(trash_stat_err, trash_stat) if trash_stat_err then - cb(".trashinfo file points to non-existant file") + cb('.trashinfo file points to non-existant file') else trash_info.stat = trash_stat ---@cast trash_info oil.TrashInfo @@ -244,14 +244,14 @@ M.list = function(url, column_defs, cb) -- The first trash dir is a special case; it is in the home directory and we should only show -- all entries if we are in the top root path "/" if trash_idx == 1 then - show_all_files = path == "/" + show_all_files = path == '/' end - local info_dir = fs.join(trash_dir, "info") + local info_dir = fs.join(trash_dir, 'info') ---@diagnostic disable-next-line: param-type-mismatch, discard-returns uv.fs_opendir(info_dir, function(open_err, fd) if open_err then - if open_err:match("^ENOENT: no such file or directory") then + if open_err:match('^ENOENT: no such file or directory') then -- If the directory doesn't exist, treat the list as a success. We will be able to traverse -- and edit a not-yet-existing directory. return read_next_trash_dir() @@ -286,12 +286,12 @@ M.list = function(url, column_defs, cb) -- files. poll() else - local parent = util.addslash(vim.fn.fnamemodify(info.original_path, ":h")) + local parent = util.addslash(vim.fn.fnamemodify(info.original_path, ':h')) if path == parent or show_all_files then - local name = vim.fn.fnamemodify(info.trash_file, ":t") + local name = vim.fn.fnamemodify(info.trash_file, ':t') ---@diagnostic disable-next-line: undefined-field local cache_entry = cache.create_entry(url, name, info.stat.type) - local display_name = vim.fn.fnamemodify(info.original_path, ":t") + local display_name = vim.fn.fnamemodify(info.original_path, ':t') cache_entry[FIELD_META] = { stat = info.stat, trash_info = info, @@ -302,12 +302,12 @@ M.list = function(url, column_defs, cb) if path ~= parent and (show_all_files or fs.is_subpath(path, parent)) then local name = parent:sub(path:len() + 1) local next_par = vim.fs.dirname(name) - while next_par ~= "." do + while next_par ~= '.' do name = next_par next_par = vim.fs.dirname(name) end ---@diagnostic disable-next-line: undefined-field - local cache_entry = cache.create_entry(url, name, "directory") + local cache_entry = cache.create_entry(url, name, 'directory') cache_entry[FIELD_META] = { stat = info.stat, @@ -348,7 +348,7 @@ local file_columns = {} local current_year -- Make sure we run this import-time effect in the main loop (mostly for tests) vim.schedule(function() - current_year = vim.fn.strftime("%Y") + current_year = vim.fn.strftime('%Y') end) file_columns.mtime = { @@ -368,11 +368,11 @@ file_columns.mtime = { if fmt then ret = vim.fn.strftime(fmt, time) else - local year = vim.fn.strftime("%Y", time) + local year = vim.fn.strftime('%Y', time) if year ~= current_year then - ret = vim.fn.strftime("%b %d %Y", time) + ret = vim.fn.strftime('%b %d %Y', time) else - ret = vim.fn.strftime("%b %d %H:%M", time) + ret = vim.fn.strftime('%b %d %H:%M', time) end end return ret @@ -393,11 +393,11 @@ file_columns.mtime = { local fmt = conf and conf.format local pattern if fmt then - pattern = fmt:gsub("%%.", "%%S+") + pattern = fmt:gsub('%%.', '%%S+') else - pattern = "%S+%s+%d+%s+%d%d:?%d%d" + pattern = '%S+%s+%d+%s+%d%d:?%d%d' end - return line:match("^(" .. pattern .. ")%s+(.+)$") + return line:match('^(' .. pattern .. ')%s+(.+)$') end, } @@ -407,25 +407,26 @@ M.get_column = function(name) return file_columns[name] end -M.supported_cross_adapter_actions = { files = "move" } +M.supported_cross_adapter_actions = { files = 'move' } ---@param action oil.Action ---@return boolean M.filter_action = function(action) - if action.type == "create" then + if action.type == 'create' then return false - elseif action.type == "delete" then + elseif action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) local meta = entry[FIELD_META] return meta ~= nil and meta.trash_info ~= nil - elseif action.type == "move" then + elseif action.type == 'move' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - return src_adapter.name == "files" or dest_adapter.name == "files" - elseif action.type == "copy" then + return src_adapter.name == 'files' or dest_adapter.name == 'files' + -- selene: allow(if_same_then_else) + elseif action.type == 'copy' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - return src_adapter.name == "files" or dest_adapter.name == "files" + return src_adapter.name == 'files' or dest_adapter.name == 'files' else error(string.format("Bad action type '%s'", action.type)) end @@ -434,7 +435,7 @@ end ---@param err oil.ParseError ---@return boolean M.filter_error = function(err) - if err.message == "Duplicate filename" then + if err.message == 'Duplicate filename' then return false end return true @@ -443,44 +444,44 @@ end ---@param action oil.Action ---@return string M.render_action = function(action) - if action.type == "delete" then + if action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) local meta = entry[FIELD_META] ---@type oil.TrashInfo local trash_info = assert(meta).trash_info local short_path = fs.shorten_path(trash_info.original_path) - return string.format(" PURGE %s", short_path) - elseif action.type == "move" then + return string.format(' PURGE %s', short_path) + elseif action.type == 'move' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then local _, path = util.parse_url(action.src_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format(" TRASH %s", short_path) - elseif dest_adapter.name == "files" then + return string.format(' TRASH %s', short_path) + elseif dest_adapter.name == 'files' then local _, path = util.parse_url(action.dest_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format("RESTORE %s", short_path) + return string.format('RESTORE %s', short_path) else - error("Must be moving files into or out of trash") + error('Must be moving files into or out of trash') end - elseif action.type == "copy" then + elseif action.type == 'copy' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then local _, path = util.parse_url(action.src_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format(" COPY %s -> TRASH", short_path) - elseif dest_adapter.name == "files" then + return string.format(' COPY %s -> TRASH', short_path) + elseif dest_adapter.name == 'files' then local _, path = util.parse_url(action.dest_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format("RESTORE %s", short_path) + return string.format('RESTORE %s', short_path) else - error("Must be copying files into or out of trash") + error('Must be copying files into or out of trash') end else error(string.format("Bad action type '%s'", action.type)) @@ -490,7 +491,7 @@ end ---@param trash_info oil.TrashInfo ---@param cb fun(err?: string) local function purge(trash_info, cb) - fs.recursive_delete("file", trash_info.info_file, function(err) + fs.recursive_delete('file', trash_info.info_file, function(err) if err then return cb(err) end @@ -505,15 +506,15 @@ end local function write_info_file(path, info_path, cb) uv.fs_open( info_path, - "w", + 'w', 448, vim.schedule_wrap(function(err, fd) if err then return cb(err) end assert(fd) - local deletion_date = vim.fn.strftime("%Y-%m-%dT%H:%M:%S") - local contents = string.format("[Trash Info]\nPath=%s\nDeletionDate=%s", path, deletion_date) + local deletion_date = vim.fn.strftime('%Y-%m-%dT%H:%M:%S') + local contents = string.format('[Trash Info]\nPath=%s\nDeletionDate=%s', path, deletion_date) uv.fs_write(fd, contents, function(write_err) uv.fs_close(fd, function(close_err) cb(write_err or close_err) @@ -529,9 +530,9 @@ local function create_trash_info(path, cb) local trash_dir = get_write_trash_dir(path) local basename = vim.fs.basename(path) local now = os.time() - local name = string.format("%s-%d.%d", basename, now, math.random(100000, 999999)) - local dest_path = fs.join(trash_dir, "files", name) - local dest_info = fs.join(trash_dir, "info", name .. ".trashinfo") + local name = string.format('%s-%d.%d', basename, now, math.random(100000, 999999)) + local dest_path = fs.join(trash_dir, 'files', name) + local dest_info = fs.join(trash_dir, 'info', name .. '.trashinfo') uv.fs_lstat(path, function(err, stat) if err then return cb(err) @@ -557,19 +558,19 @@ end ---@param action oil.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) - if action.type == "delete" then + if action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) local meta = entry[FIELD_META] ---@type oil.TrashInfo local trash_info = assert(meta).trash_info purge(trash_info, cb) - elseif action.type == "move" then + elseif action.type == 'move' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then local _, path = util.parse_url(action.src_url) M.delete_to_trash(assert(path), cb) - elseif dest_adapter.name == "files" then + elseif dest_adapter.name == 'files' then -- Restore local _, dest_path = util.parse_url(action.dest_url) assert(dest_path) @@ -584,23 +585,23 @@ M.perform_action = function(action, cb) uv.fs_unlink(trash_info.info_file, cb) end) else - error("Must be moving files into or out of trash") + error('Must be moving files into or out of trash') end - elseif action.type == "copy" then + elseif action.type == 'copy' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then local _, path = util.parse_url(action.src_url) assert(path) create_trash_info(path, function(err, trash_info) if err then cb(err) else - local stat_type = trash_info.stat.type or "unknown" + local stat_type = trash_info.stat.type or 'unknown' fs.recursive_copy(stat_type, path, trash_info.trash_file, vim.schedule_wrap(cb)) end end) - elseif dest_adapter.name == "files" then + elseif dest_adapter.name == 'files' then -- Restore local _, dest_path = util.parse_url(action.dest_url) assert(dest_path) @@ -610,10 +611,10 @@ M.perform_action = function(action, cb) local trash_info = assert(meta).trash_info fs.recursive_copy(action.entry_type, trash_info.trash_file, dest_path, cb) else - error("Must be moving files into or out of trash") + error('Must be moving files into or out of trash') end else - cb(string.format("Bad action type: %s", action.type)) + cb(string.format('Bad action type: %s', action.type)) end end @@ -624,7 +625,7 @@ M.delete_to_trash = function(path, cb) if err then cb(err) else - local stat_type = trash_info.stat.type or "unknown" + local stat_type = trash_info.stat.type or 'unknown' fs.recursive_move(stat_type, path, trash_info.trash_file, vim.schedule_wrap(cb)) end end) diff --git a/lua/oil/adapters/trash/mac.lua b/lua/oil/adapters/trash/mac.lua index 54d68a3..e1c052d 100644 --- a/lua/oil/adapters/trash/mac.lua +++ b/lua/oil/adapters/trash/mac.lua @@ -1,8 +1,8 @@ -local cache = require("oil.cache") -local config = require("oil.config") -local files = require("oil.adapters.files") -local fs = require("oil.fs") -local util = require("oil.util") +local cache = require('oil.cache') +local config = require('oil.config') +local files = require('oil.adapters.files') +local fs = require('oil.fs') +local util = require('oil.util') local uv = vim.uv or vim.loop @@ -15,7 +15,7 @@ end ---Gets the location of the home trash dir, creating it if necessary ---@return string local function get_trash_dir() - local trash_dir = fs.join(assert(uv.os_homedir()), ".Trash") + local trash_dir = fs.join(assert(uv.os_homedir()), '.Trash') touch_dir(trash_dir) return trash_dir end @@ -25,7 +25,7 @@ end M.normalize_url = function(url, callback) local scheme, path = util.parse_url(url) assert(path) - callback(scheme .. "/") + callback(scheme .. '/') end ---@param url string @@ -34,8 +34,8 @@ end M.get_entry_path = function(url, entry, cb) local trash_dir = get_trash_dir() local path = fs.join(trash_dir, entry.name) - if entry.type == "directory" then - path = "oil://" .. path + if entry.type == 'directory' then + path = 'oil://' .. path end cb(path) end @@ -51,7 +51,7 @@ M.list = function(url, column_defs, cb) ---@diagnostic disable-next-line: param-type-mismatch, discard-returns uv.fs_opendir(trash_dir, function(open_err, fd) if open_err then - if open_err:match("^ENOENT: no such file or directory") then + if open_err:match('^ENOENT: no such file or directory') then -- If the directory doesn't exist, treat the list as a success. We will be able to traverse -- and edit a not-yet-existing directory. return cb() @@ -111,35 +111,35 @@ M.get_column = function(name) return nil end -M.supported_cross_adapter_actions = { files = "move" } +M.supported_cross_adapter_actions = { files = 'move' } ---@param action oil.Action ---@return string M.render_action = function(action) - if action.type == "create" then - return string.format("CREATE %s", action.url) - elseif action.type == "delete" then - return string.format(" PURGE %s", action.url) - elseif action.type == "move" then + if action.type == 'create' then + return string.format('CREATE %s', action.url) + elseif action.type == 'delete' then + return string.format(' PURGE %s', action.url) + elseif action.type == 'move' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then local _, path = util.parse_url(action.src_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format(" TRASH %s", short_path) - elseif dest_adapter.name == "files" then + return string.format(' TRASH %s', short_path) + elseif dest_adapter.name == 'files' then local _, path = util.parse_url(action.dest_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format("RESTORE %s", short_path) + return string.format('RESTORE %s', short_path) else - return string.format(" %s %s -> %s", action.type:upper(), action.src_url, action.dest_url) + return string.format(' %s %s -> %s', action.type:upper(), action.src_url, action.dest_url) end - elseif action.type == "copy" then - return string.format(" %s %s -> %s", action.type:upper(), action.src_url, action.dest_url) + elseif action.type == 'copy' then + return string.format(' %s %s -> %s', action.type:upper(), action.src_url, action.dest_url) else - error("Bad action type") + error('Bad action type') end end @@ -147,20 +147,20 @@ end ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) local trash_dir = get_trash_dir() - if action.type == "create" then + if action.type == 'create' then local _, path = util.parse_url(action.url) assert(path) path = trash_dir .. path - if action.entry_type == "directory" then + if action.entry_type == 'directory' then uv.fs_mkdir(path, 493, function(err) -- Ignore if the directory already exists - if not err or err:match("^EEXIST:") then + if not err or err:match('^EEXIST:') then cb() else cb(err) end end) -- 0755 - elseif action.entry_type == "link" and action.link then + elseif action.entry_type == 'link' and action.link then local flags = nil local target = fs.posix_to_os_path(action.link) ---@diagnostic disable-next-line: param-type-mismatch @@ -168,33 +168,33 @@ M.perform_action = function(action, cb) else fs.touch(path, config.new_file_mode, cb) end - elseif action.type == "delete" then + elseif action.type == 'delete' then local _, path = util.parse_url(action.url) assert(path) local fullpath = trash_dir .. path fs.recursive_delete(action.entry_type, fullpath, cb) - elseif action.type == "move" or action.type == "copy" then + elseif action.type == 'move' or action.type == 'copy' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) local _, src_path = util.parse_url(action.src_url) local _, dest_path = util.parse_url(action.dest_url) assert(src_path and dest_path) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then dest_path = trash_dir .. dest_path - elseif dest_adapter.name == "files" then + elseif dest_adapter.name == 'files' then src_path = trash_dir .. src_path else dest_path = trash_dir .. dest_path src_path = trash_dir .. src_path end - if action.type == "move" then + if action.type == 'move' then fs.recursive_move(action.entry_type, src_path, dest_path, cb) else fs.recursive_copy(action.entry_type, src_path, dest_path, cb) end else - cb(string.format("Bad action type: %s", action.type)) + cb(string.format('Bad action type: %s', action.type)) end end @@ -212,8 +212,8 @@ M.delete_to_trash = function(path, cb) end assert(src_stat) if uv.fs_lstat(dest) then - local date_str = vim.fn.strftime(" %Y-%m-%dT%H:%M:%S") - local name_pieces = vim.split(basename, ".", { plain = true }) + local date_str = vim.fn.strftime(' %Y-%m-%dT%H:%M:%S') + local name_pieces = vim.split(basename, '.', { plain = true }) if #name_pieces > 1 then table.insert(name_pieces, #name_pieces - 1, date_str) basename = table.concat(name_pieces) diff --git a/lua/oil/adapters/trash/windows.lua b/lua/oil/adapters/trash/windows.lua index f7634e1..c761f82 100644 --- a/lua/oil/adapters/trash/windows.lua +++ b/lua/oil/adapters/trash/windows.lua @@ -1,11 +1,11 @@ -local util = require("oil.util") +local util = require('oil.util') local uv = vim.uv or vim.loop -local cache = require("oil.cache") -local config = require("oil.config") -local constants = require("oil.constants") -local files = require("oil.adapters.files") -local fs = require("oil.fs") -local powershell_trash = require("oil.adapters.trash.windows.powershell-trash") +local cache = require('oil.cache') +local config = require('oil.config') +local constants = require('oil.constants') +local files = require('oil.adapters.files') +local fs = require('oil.fs') +local powershell_trash = require('oil.adapters.trash.windows.powershell-trash') local FIELD_META = constants.FIELD_META local FIELD_TYPE = constants.FIELD_TYPE @@ -15,22 +15,22 @@ local M = {} ---@return string local function get_trash_dir() local cwd = assert(vim.fn.getcwd()) - local trash_dir = cwd:sub(1, 3) .. "$Recycle.Bin" + local trash_dir = cwd:sub(1, 3) .. '$Recycle.Bin' if vim.fn.isdirectory(trash_dir) == 1 then return trash_dir end - trash_dir = "C:\\$Recycle.Bin" + trash_dir = 'C:\\$Recycle.Bin' if vim.fn.isdirectory(trash_dir) == 1 then return trash_dir end - error("No trash found") + error('No trash found') end ---@param path string ---@return string local win_addslash = function(path) - if not vim.endswith(path, "\\") then - return path .. "\\" + if not vim.endswith(path, '\\') then + return path .. '\\' else return path end @@ -61,7 +61,7 @@ M.list = function(url, column_defs, cb) local raw_displayed_entries = vim.tbl_filter( ---@param entry {IsFolder: boolean, DeletionDate: integer, Name: string, Path: string, OriginalPath: string} function(entry) - local parent = win_addslash(assert(vim.fn.fnamemodify(entry.OriginalPath, ":h"))) + local parent = win_addslash(assert(vim.fn.fnamemodify(entry.OriginalPath, ':h'))) local is_in_path = path == parent local is_subpath = fs.is_subpath(path, parent) return is_in_path or is_subpath or show_all_files @@ -72,27 +72,27 @@ M.list = function(url, column_defs, cb) ---@param entry {IsFolder: boolean, DeletionDate: integer, Name: string, Path: string, OriginalPath: string} ---@return {[1]:nil, [2]:string, [3]:string, [4]:{stat: uv_fs_t, trash_info: oil.WindowsTrashInfo, display_name: string}} function(entry) - local parent = win_addslash(assert(vim.fn.fnamemodify(entry.OriginalPath, ":h"))) + local parent = win_addslash(assert(vim.fn.fnamemodify(entry.OriginalPath, ':h'))) --- @type oil.InternalEntry local cache_entry if path == parent or show_all_files then - local deleted_file_tail = assert(vim.fn.fnamemodify(entry.Path, ":t")) - local deleted_file_head = assert(vim.fn.fnamemodify(entry.Path, ":h")) + local deleted_file_tail = assert(vim.fn.fnamemodify(entry.Path, ':t')) + local deleted_file_head = assert(vim.fn.fnamemodify(entry.Path, ':h')) local info_file_head = deleted_file_head --- @type string? local info_file cache_entry = - cache.create_entry(url, deleted_file_tail, entry.IsFolder and "directory" or "file") + cache.create_entry(url, deleted_file_tail, entry.IsFolder and 'directory' or 'file') -- info_file on windows has the following format: $I<6 char hash>. -- the hash is the same for the deleted file and the info file -- so, we take the hash (and extension) from the deleted file -- -- see https://superuser.com/questions/368890/how-does-the-recycle-bin-in-windows-work/1736690#1736690 - local info_file_tail = deleted_file_tail:match("^%$R(.*)$") --[[@as string?]] + local info_file_tail = deleted_file_tail:match('^%$R(.*)$') --[[@as string?]] if info_file_tail then - info_file_tail = "$I" .. info_file_tail - info_file = info_file_head .. "\\" .. info_file_tail + info_file_tail = '$I' .. info_file_tail + info_file = info_file_head .. '\\' .. info_file_tail end cache_entry[FIELD_META] = { stat = nil, @@ -109,10 +109,10 @@ M.list = function(url, column_defs, cb) if path ~= parent and (show_all_files or fs.is_subpath(path, parent)) then local name = parent:sub(path:len() + 1) local next_par = vim.fs.dirname(name) - while next_par ~= "." do + while next_par ~= '.' do name = next_par next_par = vim.fs.dirname(name) - cache_entry = cache.create_entry(url, name, "directory") + cache_entry = cache.create_entry(url, name, 'directory') cache_entry[FIELD_META] = {} end @@ -132,7 +132,7 @@ end local current_year -- Make sure we run this import-time effect in the main loop (mostly for tests) vim.schedule(function() - current_year = vim.fn.strftime("%Y") + current_year = vim.fn.strftime('%Y') end) local file_columns = {} @@ -153,11 +153,11 @@ file_columns.mtime = { if fmt then ret = vim.fn.strftime(fmt, time) else - local year = vim.fn.strftime("%Y", time) + local year = vim.fn.strftime('%Y', time) if year ~= current_year then - ret = vim.fn.strftime("%b %d %Y", time) + ret = vim.fn.strftime('%b %d %Y', time) else - ret = vim.fn.strftime("%b %d %H:%M", time) + ret = vim.fn.strftime('%b %d %H:%M', time) end end return ret @@ -178,11 +178,11 @@ file_columns.mtime = { local fmt = conf and conf.format local pattern if fmt then - pattern = fmt:gsub("%%.", "%%S+") + pattern = fmt:gsub('%%.', '%%S+') else - pattern = "%S+%s+%d+%s+%d%d:?%d%d" + pattern = '%S+%s+%d+%s+%d%d:?%d%d' end - return line:match("^(" .. pattern .. ")%s+(.+)$") + return line:match('^(' .. pattern .. ')%s+(.+)$') end, } @@ -195,20 +195,21 @@ end ---@param action oil.Action ---@return boolean M.filter_action = function(action) - if action.type == "create" then + if action.type == 'create' then return false - elseif action.type == "delete" then + elseif action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) local meta = entry[FIELD_META] return meta ~= nil and meta.trash_info ~= nil - elseif action.type == "move" then + elseif action.type == 'move' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - return src_adapter.name == "files" or dest_adapter.name == "files" - elseif action.type == "copy" then + return src_adapter.name == 'files' or dest_adapter.name == 'files' + -- selene: allow(if_same_then_else) + elseif action.type == 'copy' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - return src_adapter.name == "files" or dest_adapter.name == "files" + return src_adapter.name == 'files' or dest_adapter.name == 'files' else error(string.format("Bad action type '%s'", action.type)) end @@ -219,7 +220,7 @@ end M.normalize_url = function(url, callback) local scheme, path = util.parse_url(url) assert(path) - local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":p") + local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ':p') assert(os_path) uv.fs_realpath( os_path, @@ -244,16 +245,16 @@ M.get_entry_path = function(url, entry, cb) end local path = fs.os_to_posix_path(trash_info.trash_file) - if entry.type == "directory" then + if entry.type == 'directory' then path = win_addslash(path) end - cb("oil://" .. path) + cb('oil://' .. path) end ---@param err oil.ParseError ---@return boolean M.filter_error = function(err) - if err.message == "Duplicate filename" then + if err.message == 'Duplicate filename' then return false end return true @@ -262,44 +263,44 @@ end ---@param action oil.Action ---@return string M.render_action = function(action) - if action.type == "delete" then + if action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) local meta = entry[FIELD_META] ---@type oil.WindowsTrashInfo local trash_info = assert(meta).trash_info local short_path = fs.shorten_path(trash_info.original_path) - return string.format(" PURGE %s", short_path) - elseif action.type == "move" then + return string.format(' PURGE %s', short_path) + elseif action.type == 'move' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then local _, path = util.parse_url(action.src_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format(" TRASH %s", short_path) - elseif dest_adapter.name == "files" then + return string.format(' TRASH %s', short_path) + elseif dest_adapter.name == 'files' then local _, path = util.parse_url(action.dest_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format("RESTORE %s", short_path) + return string.format('RESTORE %s', short_path) else - error("Must be moving files into or out of trash") + error('Must be moving files into or out of trash') end - elseif action.type == "copy" then + elseif action.type == 'copy' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then local _, path = util.parse_url(action.src_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format(" COPY %s -> TRASH", short_path) - elseif dest_adapter.name == "files" then + return string.format(' COPY %s -> TRASH', short_path) + elseif dest_adapter.name == 'files' then local _, path = util.parse_url(action.dest_url) assert(path) local short_path = files.to_short_os_path(path, action.entry_type) - return string.format("RESTORE %s", short_path) + return string.format('RESTORE %s', short_path) else - error("Must be copying files into or out of trash") + error('Must be copying files into or out of trash') end else error(string.format("Bad action type '%s'", action.type)) @@ -309,11 +310,11 @@ end ---@param trash_info oil.WindowsTrashInfo ---@param cb fun(err?: string, raw_entries: oil.WindowsRawEntry[]?) local purge = function(trash_info, cb) - fs.recursive_delete("file", trash_info.info_file, function(err) + fs.recursive_delete('file', trash_info.info_file, function(err) if err then return cb(err) end - fs.recursive_delete("file", trash_info.trash_file, cb) + fs.recursive_delete('file', trash_info.trash_file, cb) end) end @@ -321,7 +322,7 @@ end ---@param type string ---@param cb fun(err?: string, trash_info?: oil.TrashInfo) local function create_trash_info_and_copy(path, type, cb) - local temp_path = path .. "temp" + local temp_path = path .. 'temp' -- create a temporary copy on the same location fs.recursive_copy( type, @@ -346,19 +347,19 @@ end ---@param action oil.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) - if action.type == "delete" then + if action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) local meta = entry[FIELD_META] --[[@as {stat: uv_fs_t, trash_info: oil.WindowsTrashInfo, display_name: string}]] local trash_info = meta and meta.trash_info purge(trash_info, cb) - elseif action.type == "move" then + elseif action.type == 'move' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then local _, path = util.parse_url(action.src_url) M.delete_to_trash(assert(path), cb) - elseif dest_adapter.name == "files" then + elseif dest_adapter.name == 'files' then -- Restore local _, dest_path = util.parse_url(action.dest_url) assert(dest_path) @@ -373,16 +374,16 @@ M.perform_action = function(action, cb) uv.fs_unlink(trash_info.info_file, cb) end) end - elseif action.type == "copy" then + elseif action.type == 'copy' then local src_adapter = assert(config.get_adapter_by_scheme(action.src_url)) local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) - if src_adapter.name == "files" then + if src_adapter.name == 'files' then local _, path = util.parse_url(action.src_url) assert(path) path = fs.posix_to_os_path(path) local entry = assert(cache.get_entry_by_url(action.src_url)) create_trash_info_and_copy(path, entry[FIELD_TYPE], cb) - elseif dest_adapter.name == "files" then + elseif dest_adapter.name == 'files' then -- Restore local _, dest_path = util.parse_url(action.dest_url) assert(dest_path) @@ -392,14 +393,14 @@ M.perform_action = function(action, cb) local trash_info = meta and meta.trash_info fs.recursive_copy(action.entry_type, trash_info.trash_file, dest_path, cb) else - error("Must be moving files into or out of trash") + error('Must be moving files into or out of trash') end else - cb(string.format("Bad action type: %s", action.type)) + cb(string.format('Bad action type: %s', action.type)) end end -M.supported_cross_adapter_actions = { files = "move" } +M.supported_cross_adapter_actions = { files = 'move' } ---@param path string ---@param cb fun(err?: string) diff --git a/lua/oil/adapters/trash/windows/powershell-connection.lua b/lua/oil/adapters/trash/windows/powershell-connection.lua index 332defb..d897fe8 100644 --- a/lua/oil/adapters/trash/windows/powershell-connection.lua +++ b/lua/oil/adapters/trash/windows/powershell-connection.lua @@ -41,23 +41,23 @@ function PowershellConnection:_init(init_command) -- 65001 is the UTF-8 codepage -- powershell needs to be launched with the UTF-8 codepage to use it for both stdin and stdout local jid = vim.fn.jobstart({ - "cmd", - "/c", + 'cmd', + '/c', '"chcp 65001 && powershell -NoProfile -NoLogo -ExecutionPolicy Bypass -NoExit -Command -"', }, { ---@param data string[] on_stdout = function(_, data) for _, fragment in ipairs(data) do - if fragment:find("===DONE%((%a+)%)===") then + if fragment:find('===DONE%((%a+)%)===') then self.is_reading_data = false - local output = table.concat(self.stdout, "") + local output = table.concat(self.stdout, '') local cb = self.commands[1].cb table.remove(self.commands, 1) - local success = fragment:match("===DONE%((%a+)%)===") - if success == "True" then + local success = fragment:match('===DONE%((%a+)%)===') + if success == 'True' then cb(nil, output) - elseif success == "False" then - cb(success .. ": " .. output, output) + elseif success == 'False' then + cb(success .. ': ' .. output, output) end self.stdout = {} self:_consume() diff --git a/lua/oil/adapters/trash/windows/powershell-trash.lua b/lua/oil/adapters/trash/windows/powershell-trash.lua index d050bb0..edc9ee6 100644 --- a/lua/oil/adapters/trash/windows/powershell-trash.lua +++ b/lua/oil/adapters/trash/windows/powershell-trash.lua @@ -1,5 +1,5 @@ -- A wrapper around trash operations using windows powershell -local Powershell = require("oil.adapters.trash.windows.powershell-connection") +local Powershell = require('oil.adapters.trash.windows.powershell-connection') ---@class oil.WindowsRawEntry ---@field IsFolder boolean diff --git a/lua/oil/cache.lua b/lua/oil/cache.lua index ef5597c..800c97a 100644 --- a/lua/oil/cache.lua +++ b/lua/oil/cache.lua @@ -1,5 +1,5 @@ -local constants = require("oil.constants") -local util = require("oil.util") +local constants = require('oil.constants') +local util = require('oil.util') local M = {} local FIELD_ID = constants.FIELD_ID @@ -28,7 +28,7 @@ local _cached_id_fmt M.format_id = function(id) if not _cached_id_fmt then local id_str_length = math.max(3, 1 + math.floor(math.log10(next_id))) - _cached_id_fmt = "/%0" .. string.format("%d", id_str_length) .. "d" + _cached_id_fmt = '/%0' .. string.format('%d', id_str_length) .. 'd' end return _cached_id_fmt:format(id) end @@ -125,8 +125,8 @@ end M.get_entry_by_url = function(url) local scheme, path = util.parse_url(url) assert(path) - local parent_url = scheme .. vim.fn.fnamemodify(path, ":h") - local basename = vim.fn.fnamemodify(path, ":t") + local parent_url = scheme .. vim.fn.fnamemodify(path, ':h') + local basename = vim.fn.fnamemodify(path, ':t') return M.list_url(parent_url)[basename] end @@ -135,7 +135,7 @@ end M.get_parent_url = function(id) local url = parent_url_by_id[id] if not url then - error(string.format("Entry %d missing parent url", id)) + error(string.format('Entry %d missing parent url', id)) end return url end @@ -149,32 +149,32 @@ end ---@param action oil.Action M.perform_action = function(action) - if action.type == "create" then + if action.type == 'create' then local scheme, path = util.parse_url(action.url) assert(path) - local parent_url = util.addslash(scheme .. vim.fn.fnamemodify(path, ":h")) - local name = vim.fn.fnamemodify(path, ":t") + local parent_url = util.addslash(scheme .. vim.fn.fnamemodify(path, ':h')) + local name = vim.fn.fnamemodify(path, ':t') M.create_and_store_entry(parent_url, name, action.entry_type) - elseif action.type == "delete" then + elseif action.type == 'delete' then local scheme, path = util.parse_url(action.url) assert(path) - local parent_url = util.addslash(scheme .. vim.fn.fnamemodify(path, ":h")) - local name = vim.fn.fnamemodify(path, ":t") + local parent_url = util.addslash(scheme .. vim.fn.fnamemodify(path, ':h')) + local name = vim.fn.fnamemodify(path, ':t') local entry = url_directory[parent_url][name] url_directory[parent_url][name] = nil entries_by_id[entry[FIELD_ID]] = nil parent_url_by_id[entry[FIELD_ID]] = nil - elseif action.type == "move" then + elseif action.type == 'move' then local src_scheme, src_path = util.parse_url(action.src_url) assert(src_path) - local src_parent_url = util.addslash(src_scheme .. vim.fn.fnamemodify(src_path, ":h")) - local src_name = vim.fn.fnamemodify(src_path, ":t") + local src_parent_url = util.addslash(src_scheme .. vim.fn.fnamemodify(src_path, ':h')) + local src_name = vim.fn.fnamemodify(src_path, ':t') local entry = url_directory[src_parent_url][src_name] local dest_scheme, dest_path = util.parse_url(action.dest_url) assert(dest_path) - local dest_parent_url = util.addslash(dest_scheme .. vim.fn.fnamemodify(dest_path, ":h")) - local dest_name = vim.fn.fnamemodify(dest_path, ":t") + local dest_parent_url = util.addslash(dest_scheme .. vim.fn.fnamemodify(dest_path, ':h')) + local dest_name = vim.fn.fnamemodify(dest_path, ':t') url_directory[src_parent_url][src_name] = nil local dest_parent = url_directory[dest_parent_url] @@ -188,13 +188,14 @@ M.perform_action = function(action) parent_url_by_id[entry[FIELD_ID]] = dest_parent_url entry[FIELD_NAME] = dest_name util.update_moved_buffers(action.entry_type, action.src_url, action.dest_url) - elseif action.type == "copy" then + elseif action.type == 'copy' then local scheme, path = util.parse_url(action.dest_url) assert(path) - local parent_url = util.addslash(scheme .. vim.fn.fnamemodify(path, ":h")) - local name = vim.fn.fnamemodify(path, ":t") + local parent_url = util.addslash(scheme .. vim.fn.fnamemodify(path, ':h')) + local name = vim.fn.fnamemodify(path, ':t') M.create_and_store_entry(parent_url, name, action.entry_type) - elseif action.type == "change" then + -- selene: allow(empty_if) + elseif action.type == 'change' then -- Cache doesn't need to update else ---@diagnostic disable-next-line: undefined-field diff --git a/lua/oil/clipboard.lua b/lua/oil/clipboard.lua index 04498f5..84df407 100644 --- a/lua/oil/clipboard.lua +++ b/lua/oil/clipboard.lua @@ -1,11 +1,11 @@ -local cache = require("oil.cache") -local columns = require("oil.columns") -local config = require("oil.config") -local fs = require("oil.fs") -local oil = require("oil") -local parser = require("oil.mutator.parser") -local util = require("oil.util") -local view = require("oil.view") +local cache = require('oil.cache') +local columns = require('oil.columns') +local config = require('oil.config') +local fs = require('oil.fs') +local oil = require('oil') +local parser = require('oil.mutator.parser') +local util = require('oil.util') +local view = require('oil.view') local M = {} @@ -16,10 +16,10 @@ local function get_linux_session_type() return end xdg_session_type = xdg_session_type:lower() - if xdg_session_type:find("x11") then - return "x11" - elseif xdg_session_type:find("wayland") then - return "wayland" + if xdg_session_type:find('x11') then + return 'x11' + elseif xdg_session_type:find('wayland') then + return 'wayland' else return nil end @@ -29,9 +29,9 @@ end local function is_linux_desktop_gnome() local cur_desktop = vim.env.XDG_CURRENT_DESKTOP local session_desktop = vim.env.XDG_SESSION_DESKTOP - local idx = session_desktop and session_desktop:lower():find("gnome") - or cur_desktop and cur_desktop:lower():find("gnome") - return idx ~= nil or cur_desktop == "X-Cinnamon" or cur_desktop == "XFCE" + local idx = session_desktop and session_desktop:lower():find('gnome') + or cur_desktop and cur_desktop:lower():find('gnome') + return idx ~= nil or cur_desktop == 'X-Cinnamon' or cur_desktop == 'XFCE' end ---@param winid integer @@ -55,7 +55,7 @@ end ---@param entry oil.InternalEntry local function remove_entry_from_parent_buffer(parent_url, entry) local bufnr = vim.fn.bufadd(parent_url) - assert(vim.api.nvim_buf_is_loaded(bufnr), "Expected parent buffer to be loaded during paste") + assert(vim.api.nvim_buf_is_loaded(bufnr), 'Expected parent buffer to be loaded during paste') local adapter = assert(util.get_adapter(bufnr)) local column_defs = columns.get_supported_columns(adapter) local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) @@ -77,7 +77,7 @@ end ---@param delete_original? boolean local function paste_paths(paths, delete_original) local bufnr = vim.api.nvim_get_current_buf() - local scheme = "oil://" + local scheme = 'oil://' local adapter = assert(config.get_adapter_by_scheme(scheme)) local column_defs = columns.get_supported_columns(scheme) local winid = vim.api.nvim_get_current_win() @@ -88,7 +88,7 @@ local function paste_paths(paths, delete_original) -- Handle as many paths synchronously as possible for _, path in ipairs(paths) do -- Trim the trailing slash off directories - if vim.endswith(path, "/") then + if vim.endswith(path, '/') then path = path:sub(1, -2) end @@ -114,7 +114,7 @@ local function paste_paths(paths, delete_original) local cursor = vim.api.nvim_win_get_cursor(winid) local complete_loading = util.cb_collect(#vim.tbl_keys(parent_urls), function(err) if err then - vim.notify(string.format("Error loading parent directory: %s", err), vim.log.levels.ERROR) + vim.notify(string.format('Error loading parent directory: %s', err), vim.log.levels.ERROR) else -- Something in this process moves the cursor to the top of the window, so have to restore it vim.api.nvim_win_set_cursor(winid, cursor) @@ -149,8 +149,8 @@ end ---@return integer end local function range_from_selection() -- [bufnum, lnum, col, off]; both row and column 1-indexed - local start = vim.fn.getpos("v") - local end_ = vim.fn.getpos(".") + local start = vim.fn.getpos('v') + local end_ = vim.fn.getpos('.') local start_row = start[2] local end_row = end_[2] @@ -164,16 +164,16 @@ end M.copy_to_system_clipboard = function() local dir = oil.get_current_dir() if not dir then - vim.notify("System clipboard only works for local files", vim.log.levels.ERROR) + vim.notify('System clipboard only works for local files', vim.log.levels.ERROR) return end local entries = {} local mode = vim.api.nvim_get_mode().mode - if mode == "v" or mode == "V" then + if mode == 'v' or mode == 'V' then if fs.is_mac then vim.notify( - "Copying multiple paths to clipboard is not supported on mac", + 'Copying multiple paths to clipboard is not supported on mac', vim.log.levels.ERROR ) return @@ -184,7 +184,7 @@ M.copy_to_system_clipboard = function() end -- leave visual mode - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("", true, false, true), "n", true) + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'n', true) else table.insert(entries, oil.get_cursor_entry()) end @@ -193,7 +193,7 @@ M.copy_to_system_clipboard = function() entries = vim.tbl_values(entries) if #entries == 0 then - vim.notify("Could not find local file under cursor", vim.log.levels.WARN) + vim.notify('Could not find local file under cursor', vim.log.levels.WARN) return end local paths = {} @@ -204,38 +204,38 @@ M.copy_to_system_clipboard = function() local stdin if fs.is_mac then cmd = { - "osascript", - "-e", - "on run args", - "-e", - "set the clipboard to POSIX file (first item of args)", - "-e", - "end run", + 'osascript', + '-e', + 'on run args', + '-e', + 'set the clipboard to POSIX file (first item of args)', + '-e', + 'end run', paths[1], } elseif fs.is_linux then local xdg_session_type = get_linux_session_type() - if xdg_session_type == "x11" then - vim.list_extend(cmd, { "xclip", "-i", "-selection", "clipboard" }) - elseif xdg_session_type == "wayland" then - table.insert(cmd, "wl-copy") + if xdg_session_type == 'x11' then + vim.list_extend(cmd, { 'xclip', '-i', '-selection', 'clipboard' }) + elseif xdg_session_type == 'wayland' then + table.insert(cmd, 'wl-copy') else - vim.notify("System clipboard not supported, check $XDG_SESSION_TYPE", vim.log.levels.ERROR) + vim.notify('System clipboard not supported, check $XDG_SESSION_TYPE', vim.log.levels.ERROR) return end local urls = {} for _, path in ipairs(paths) do - table.insert(urls, "file://" .. path) + table.insert(urls, 'file://' .. path) end if is_linux_desktop_gnome() then - stdin = string.format("copy\n%s\0", table.concat(urls, "\n")) - vim.list_extend(cmd, { "-t", "x-special/gnome-copied-files" }) + stdin = string.format('copy\n%s\0', table.concat(urls, '\n')) + vim.list_extend(cmd, { '-t', 'x-special/gnome-copied-files' }) else - stdin = table.concat(urls, "\n") .. "\n" - vim.list_extend(cmd, { "-t", "text/uri-list" }) + stdin = table.concat(urls, '\n') .. '\n' + vim.list_extend(cmd, { '-t', 'text/uri-list' }) end else - vim.notify("System clipboard not supported on Windows", vim.log.levels.ERROR) + vim.notify('System clipboard not supported on Windows', vim.log.levels.ERROR) return end @@ -243,11 +243,11 @@ M.copy_to_system_clipboard = function() vim.notify(string.format("Could not find executable '%s'", cmd[1]), vim.log.levels.ERROR) return end - local stderr = "" + local stderr = '' local jid = vim.fn.jobstart(cmd, { stderr_buffered = true, on_stderr = function(_, data) - stderr = table.concat(data, "\n") + stderr = table.concat(data, '\n') end, on_exit = function(j, exit_code) if exit_code ~= 0 then @@ -259,15 +259,15 @@ M.copy_to_system_clipboard = function() if #paths == 1 then vim.notify(string.format("Copied '%s' to system clipboard", paths[1])) else - vim.notify(string.format("Copied %d files to system clipboard", #paths)) + vim.notify(string.format('Copied %d files to system clipboard', #paths)) end end end, }) - assert(jid > 0, "Failed to start job") + assert(jid > 0, 'Failed to start job') if stdin then vim.api.nvim_chan_send(jid, stdin) - vim.fn.chanclose(jid, "stdin") + vim.fn.chanclose(jid, 'stdin') end end @@ -276,7 +276,7 @@ end local function handle_paste_output_mac(lines) local ret = {} for _, line in ipairs(lines) do - if not line:match("^%s*$") then + if not line:match('^%s*$') then table.insert(ret, line) end end @@ -288,7 +288,7 @@ end local function handle_paste_output_linux(lines) local ret = {} for _, line in ipairs(lines) do - local path = line:match("^file://(.+)$") + local path = line:match('^file://(.+)$') if path then table.insert(ret, util.url_unescape(path)) end @@ -306,37 +306,37 @@ M.paste_from_system_clipboard = function(delete_original) local handle_paste_output if fs.is_mac then cmd = { - "osascript", - "-e", - "on run", - "-e", - "POSIX path of (the clipboard as «class furl»)", - "-e", - "end run", + 'osascript', + '-e', + 'on run', + '-e', + 'POSIX path of (the clipboard as «class furl»)', + '-e', + 'end run', } handle_paste_output = handle_paste_output_mac elseif fs.is_linux then local xdg_session_type = get_linux_session_type() - if xdg_session_type == "x11" then - vim.list_extend(cmd, { "xclip", "-o", "-selection", "clipboard" }) - elseif xdg_session_type == "wayland" then - table.insert(cmd, "wl-paste") + if xdg_session_type == 'x11' then + vim.list_extend(cmd, { 'xclip', '-o', '-selection', 'clipboard' }) + elseif xdg_session_type == 'wayland' then + table.insert(cmd, 'wl-paste') else - vim.notify("System clipboard not supported, check $XDG_SESSION_TYPE", vim.log.levels.ERROR) + vim.notify('System clipboard not supported, check $XDG_SESSION_TYPE', vim.log.levels.ERROR) return end if is_linux_desktop_gnome() then - vim.list_extend(cmd, { "-t", "x-special/gnome-copied-files" }) + vim.list_extend(cmd, { '-t', 'x-special/gnome-copied-files' }) else - vim.list_extend(cmd, { "-t", "text/uri-list" }) + vim.list_extend(cmd, { '-t', 'text/uri-list' }) end handle_paste_output = handle_paste_output_linux else - vim.notify("System clipboard not supported on Windows", vim.log.levels.ERROR) + vim.notify('System clipboard not supported on Windows', vim.log.levels.ERROR) return end local paths - local stderr = "" + local stderr = '' if vim.fn.executable(cmd[1]) == 0 then vim.notify(string.format("Could not find executable '%s'", cmd[1]), vim.log.levels.ERROR) return @@ -345,26 +345,26 @@ M.paste_from_system_clipboard = function(delete_original) stdout_buffered = true, stderr_buffered = true, on_stdout = function(j, data) - local lines = vim.split(table.concat(data, "\n"), "\r?\n") + local lines = vim.split(table.concat(data, '\n'), '\r?\n') paths = handle_paste_output(lines) end, on_stderr = function(_, data) - stderr = table.concat(data, "\n") + stderr = table.concat(data, '\n') end, on_exit = function(j, exit_code) if exit_code ~= 0 or not paths then vim.notify( - string.format("Error pasting from system clipboard: %s", stderr), + string.format('Error pasting from system clipboard: %s', stderr), vim.log.levels.ERROR ) elseif #paths == 0 then - vim.notify("No valid files found in system clipboard", vim.log.levels.WARN) + vim.notify('No valid files found in system clipboard', vim.log.levels.WARN) else paste_paths(paths, delete_original) end end, }) - assert(jid > 0, "Failed to start job") + assert(jid > 0, 'Failed to start job') end return M diff --git a/lua/oil/columns.lua b/lua/oil/columns.lua index 6d76674..ef95fdd 100644 --- a/lua/oil/columns.lua +++ b/lua/oil/columns.lua @@ -1,6 +1,6 @@ -local config = require("oil.config") -local constants = require("oil.constants") -local util = require("oil.util") +local config = require('oil.config') +local constants = require('oil.constants') +local util = require('oil.util') local M = {} local FIELD_NAME = constants.FIELD_NAME @@ -38,7 +38,7 @@ end ---@return oil.ColumnSpec[] M.get_supported_columns = function(adapter_or_scheme) local adapter - if type(adapter_or_scheme) == "string" then + if type(adapter_or_scheme) == 'string' then adapter = config.get_adapter_by_scheme(adapter_or_scheme) else adapter = adapter_or_scheme @@ -53,7 +53,7 @@ M.get_supported_columns = function(adapter_or_scheme) return ret end -local EMPTY = { "-", "OilEmpty" } +local EMPTY = { '-', 'OilEmpty' } M.EMPTY = EMPTY @@ -71,17 +71,17 @@ M.render_col = function(adapter, col_def, entry, bufnr) end local chunk = column.render(entry, conf, bufnr) - if type(chunk) == "table" then - if chunk[1]:match("^%s*$") then + if type(chunk) == 'table' then + if chunk[1]:match('^%s*$') then return EMPTY end else - if not chunk or chunk:match("^%s*$") then + if not chunk or chunk:match('^%s*$') then return EMPTY end if conf and conf.highlight then local highlight = conf.highlight - if type(highlight) == "function" then + if type(highlight) == 'function' then highlight = conf.highlight(chunk) end return { chunk, highlight } @@ -98,13 +98,13 @@ end M.parse_col = function(adapter, line, col_def) local name, conf = util.split_config(col_def) -- If rendering failed, there will just be a "-" - local empty_col, rem = line:match("^%s*(-%s+)(.*)$") + local empty_col, rem = line:match('^%s*(-%s+)(.*)$') if empty_col then return nil, rem end local column = M.get_column(adapter, name) if column then - return column.parse(line:gsub("^%s+", ""), conf) + return column.parse(line:gsub('^%s+', ''), conf) end end @@ -128,12 +128,12 @@ end M.render_change_action = function(adapter, action) local column = M.get_column(adapter, action.column) if not column then - error(string.format("Received change action for nonexistant column %s", action.column)) + error(string.format('Received change action for nonexistant column %s', action.column)) end if column.render_action then return column.render_action(action) else - return string.format("CHANGE %s %s = %s", action.url, action.column, action.value) + return string.format('CHANGE %s %s = %s', action.url, action.column, action.value) end end @@ -144,7 +144,7 @@ M.perform_change_action = function(adapter, action, callback) local column = M.get_column(adapter, action.column) if not column then return callback( - string.format("Received change action for nonexistant column %s", action.column) + string.format('Received change action for nonexistant column %s', action.column) ) end column.perform_action(action, callback) @@ -152,12 +152,12 @@ end local icon_provider = util.get_icon_provider() if icon_provider then - M.register("icon", { + M.register('icon', { render = function(entry, conf, bufnr) local field_type = entry[FIELD_TYPE] local name = entry[FIELD_NAME] local meta = entry[FIELD_META] - if field_type == "link" and meta then + if field_type == 'link' and meta then if meta.link then name = meta.link end @@ -170,11 +170,11 @@ if icon_provider then end local ft = nil - if conf and conf.use_slow_filetype_detection and field_type == "file" then + if conf and conf.use_slow_filetype_detection and field_type == 'file' then local bufname = vim.api.nvim_buf_get_name(bufnr) local _, path = util.parse_url(bufname) if path then - local lines = vim.fn.readfile(path .. name, "", 16) + local lines = vim.fn.readfile(path .. name, '', 16) if lines and #lines > 0 then ft = vim.filetype.match({ filename = name, contents = lines }) end @@ -183,10 +183,10 @@ if icon_provider then local icon, hl = icon_provider(field_type, name, conf, ft) if not conf or conf.add_padding ~= false then - icon = icon .. " " + icon = icon .. ' ' end if conf and conf.highlight then - if type(conf.highlight) == "function" then + if type(conf.highlight) == 'function' then hl = conf.highlight(icon) else hl = conf.highlight @@ -196,29 +196,29 @@ if icon_provider then end, parse = function(line, conf) - return line:match("^(%S+)%s+(.*)$") + return line:match('^(%S+)%s+(.*)$') end, }) end local default_type_icons = { - directory = "dir", - socket = "sock", + directory = 'dir', + socket = 'sock', } ---@param entry oil.InternalEntry ---@return boolean local function is_entry_directory(entry) local type = entry[FIELD_TYPE] - if type == "directory" then + if type == 'directory' then return true - elseif type == "link" then + elseif type == 'link' then local meta = entry[FIELD_META] - return (meta and meta.link_stat and meta.link_stat.type == "directory") == true + return (meta and meta.link_stat and meta.link_stat.type == 'directory') == true else return false end end -M.register("type", { +M.register('type', { render = function(entry, conf) local entry_type = entry[FIELD_TYPE] if conf and conf.icons then @@ -229,7 +229,7 @@ M.register("type", { end, parse = function(line, conf) - return line:match("^(%S+)%s+(.*)$") + return line:match('^(%S+)%s+(.*)$') end, get_sort_value = function(entry) @@ -242,22 +242,22 @@ M.register("type", { }) local function adjust_number(int) - return string.format("%03d%s", #int, int) + return string.format('%03d%s', #int, int) end -M.register("name", { +M.register('name', { render = function(entry, conf) - error("Do not use the name column. It is for sorting only") + error('Do not use the name column. It is for sorting only') end, parse = function(line, conf) - error("Do not use the name column. It is for sorting only") + error('Do not use the name column. It is for sorting only') end, create_sort_value_factory = function(num_entries) if config.view_options.natural_order == false - or (config.view_options.natural_order == "fast" and num_entries > 5000) + or (config.view_options.natural_order == 'fast' and num_entries > 5000) then if config.view_options.case_insensitive then return function(entry) @@ -272,7 +272,7 @@ M.register("name", { local memo = {} return function(entry) if memo[entry] == nil then - local name = entry[FIELD_NAME]:gsub("0*(%d+)", adjust_number) + local name = entry[FIELD_NAME]:gsub('0*(%d+)', adjust_number) if config.view_options.case_insensitive then name = name:lower() end diff --git a/lua/oil/config.lua b/lua/oil/config.lua index 3734bc0..7383920 100644 --- a/lua/oil/config.lua +++ b/lua/oil/config.lua @@ -5,7 +5,7 @@ local default_config = { -- Id is automatically added at the beginning, and name at the end -- See :help oil-columns columns = { - "icon", + 'icon', -- "permissions", -- "size", -- "mtime", @@ -13,18 +13,18 @@ local default_config = { -- Buffer-local options to use for oil buffers buf_options = { buflisted = false, - bufhidden = "hide", + bufhidden = 'hide', }, -- Window-local options to use for oil buffers win_options = { wrap = false, - signcolumn = "no", + signcolumn = 'no', cursorcolumn = false, - foldcolumn = "0", + foldcolumn = '0', spell = false, list = false, conceallevel = 3, - concealcursor = "nvic", + concealcursor = 'nvic', }, -- Send deleted files to the trash instead of permanently deleting them (:help oil-trash) delete_to_trash = false, @@ -48,7 +48,7 @@ local default_config = { }, -- Constrain the cursor to the editable parts of the oil buffer -- Set to `false` to disable, or "name" to keep it on the file names - constrain_cursor = "editable", + constrain_cursor = 'editable', -- Set to true to watch the filesystem for changes and reload oil watch_for_changes = false, -- Keymaps in oil buffer. Can be any value that `vim.keymap.set` accepts OR a table of keymap @@ -58,22 +58,22 @@ local default_config = { -- Set to `false` to remove a keymap -- See :help oil-actions for a list of all available actions keymaps = { - ["g?"] = { "actions.show_help", mode = "n" }, - [""] = "actions.select", - [""] = { "actions.select", opts = { vertical = true } }, - [""] = { "actions.select", opts = { horizontal = true } }, - [""] = { "actions.select", opts = { tab = true } }, - [""] = "actions.preview", - [""] = { "actions.close", mode = "n" }, - [""] = "actions.refresh", - ["-"] = { "actions.parent", mode = "n" }, - ["_"] = { "actions.open_cwd", mode = "n" }, - ["`"] = { "actions.cd", mode = "n" }, - ["g~"] = { "actions.cd", opts = { scope = "tab" }, mode = "n" }, - ["gs"] = { "actions.change_sort", mode = "n" }, - ["gx"] = "actions.open_external", - ["g."] = { "actions.toggle_hidden", mode = "n" }, - ["g\\"] = { "actions.toggle_trash", mode = "n" }, + ['g?'] = { 'actions.show_help', mode = 'n' }, + [''] = 'actions.select', + [''] = { 'actions.select', opts = { vertical = true } }, + [''] = { 'actions.select', opts = { horizontal = true } }, + [''] = { 'actions.select', opts = { tab = true } }, + [''] = 'actions.preview', + [''] = { 'actions.close', mode = 'n' }, + [''] = 'actions.refresh', + ['-'] = { 'actions.parent', mode = 'n' }, + ['_'] = { 'actions.open_cwd', mode = 'n' }, + ['`'] = { 'actions.cd', mode = 'n' }, + ['g~'] = { 'actions.cd', opts = { scope = 'tab' }, mode = 'n' }, + ['gs'] = { 'actions.change_sort', mode = 'n' }, + ['gx'] = 'actions.open_external', + ['g.'] = { 'actions.toggle_hidden', mode = 'n' }, + ['g\\'] = { 'actions.toggle_trash', mode = 'n' }, }, -- Set to false to disable all of the above keymaps use_default_keymaps = true, @@ -82,7 +82,7 @@ local default_config = { show_hidden = false, -- This function defines what is considered a "hidden" file is_hidden_file = function(name, bufnr) - local m = name:match("^%.") + local m = name:match('^%.') return m ~= nil end, -- This function defines what will never be shown, even when `show_hidden` is set @@ -91,14 +91,14 @@ local default_config = { end, -- Sort file names with numbers in a more intuitive order for humans. -- Can be "fast", true, or false. "fast" will turn it off for large directories. - natural_order = "fast", + natural_order = 'fast', -- Sort file and directory names case insensitive case_insensitive = false, sort = { -- sort order can be "asc" or "desc" -- see :help oil-columns to see which columns are sortable - { "type", "asc" }, - { "name", "asc" }, + { 'type', 'asc' }, + { 'name', 'asc' }, }, -- Customize the highlight group for the file name highlight_filename = function(entry, is_hidden, is_link_target, is_link_orphan) @@ -138,7 +138,7 @@ local default_config = { -- optionally override the oil buffers window title with custom function: fun(winid: integer): string get_win_title = nil, -- preview_split: Split direction: "auto", "left", "right", "above", "below". - preview_split = "auto", + preview_split = 'auto', -- This is the config that will be passed to nvim_open_win. -- Change values here to customize the layout override = function(conf) @@ -150,7 +150,7 @@ local default_config = { -- Whether the preview window is automatically updated when the cursor is moved update_on_cursor_moved = true, -- How to open the preview window "load"|"scratch"|"fast_scratch" - preview_method = "fast_scratch", + preview_method = 'fast_scratch', -- A function that returns true to disable preview on a file e.g. to avoid lag disable_preview = function(filename) return false @@ -190,7 +190,7 @@ local default_config = { min_height = { 5, 0.1 }, height = nil, border = nil, - minimized_border = "none", + minimized_border = 'none', win_options = { winblend = 0, }, @@ -211,12 +211,12 @@ local default_config = { -- not "oil-s3://" on older neovim versions, since it doesn't open buffers correctly with a number -- in the name -local oil_s3_string = vim.fn.has("nvim-0.12") == 1 and "oil-s3://" or "oil-sss://" +local oil_s3_string = vim.fn.has('nvim-0.12') == 1 and 'oil-s3://' or 'oil-sss://' default_config.adapters = { - ["oil://"] = "files", - ["oil-ssh://"] = "ssh", - [oil_s3_string] = "s3", - ["oil-trash://"] = "trash", + ['oil://'] = 'files', + ['oil-ssh://'] = 'ssh', + [oil_s3_string] = 's3', + ['oil-trash://'] = 'trash', } default_config.adapter_aliases = {} -- We want the function in the default config for documentation generation, but if we nil it out @@ -408,7 +408,7 @@ local M = {} M.setup = function(opts) opts = opts or vim.g.oil or {} - local new_conf = vim.tbl_deep_extend("keep", opts, default_config) + local new_conf = vim.tbl_deep_extend('keep', opts, default_config) if not new_conf.use_default_keymaps then new_conf.keymaps = opts.keymaps or {} elseif opts.keymaps then @@ -429,19 +429,19 @@ M.setup = function(opts) end -- Backwards compatibility for old versions that don't support winborder - if vim.fn.has("nvim-0.11") == 0 then - new_conf = vim.tbl_deep_extend("keep", new_conf, { - float = { border = "rounded" }, - confirmation = { border = "rounded" }, - progress = { border = "rounded" }, - ssh = { border = "rounded" }, - keymaps_help = { border = "rounded" }, + if vim.fn.has('nvim-0.11') == 0 then + new_conf = vim.tbl_deep_extend('keep', new_conf, { + float = { border = 'rounded' }, + confirmation = { border = 'rounded' }, + progress = { border = 'rounded' }, + ssh = { border = 'rounded' }, + keymaps_help = { border = 'rounded' }, }) end -- Backwards compatibility. We renamed the 'preview' window config to be called 'confirmation'. if opts.preview and not opts.confirmation then - new_conf.confirmation = vim.tbl_deep_extend("keep", opts.preview, default_config.confirmation) + new_conf.confirmation = vim.tbl_deep_extend('keep', opts.preview, default_config.confirmation) end -- Backwards compatibility. We renamed the 'preview' config to 'preview_win' if opts.preview and opts.preview.update_on_cursor_moved ~= nil then @@ -452,7 +452,7 @@ M.setup = function(opts) new_conf.lsp_file_methods.autosave_changes = new_conf.lsp_rename_autosave new_conf.lsp_rename_autosave = nil vim.notify_once( - "oil config value lsp_rename_autosave has moved to lsp_file_methods.autosave_changes.\nCompatibility will be removed on 2024-09-01.", + 'oil config value lsp_rename_autosave has moved to lsp_file_methods.autosave_changes.\nCompatibility will be removed on 2024-09-01.', vim.log.levels.WARN ) end @@ -479,10 +479,10 @@ M.get_adapter_by_scheme = function(scheme) if not scheme then return nil end - if not vim.endswith(scheme, "://") then - local pieces = vim.split(scheme, "://", { plain = true }) + if not vim.endswith(scheme, '://') then + local pieces = vim.split(scheme, '://', { plain = true }) if #pieces <= 2 then - scheme = pieces[1] .. "://" + scheme = pieces[1] .. '://' else error(string.format("Malformed url: '%s'", scheme)) end @@ -494,7 +494,7 @@ M.get_adapter_by_scheme = function(scheme) return nil end local ok - ok, adapter = pcall(require, string.format("oil.adapters.%s", name)) + ok, adapter = pcall(require, string.format('oil.adapters.%s', name)) if ok then adapter.name = name M._adapter_by_scheme[scheme] = adapter diff --git a/lua/oil/fs.lua b/lua/oil/fs.lua index 80fb6d4..6cb084c 100644 --- a/lua/oil/fs.lua +++ b/lua/oil/fs.lua @@ -1,17 +1,17 @@ -local log = require("oil.log") +local log = require('oil.log') local M = {} local uv = vim.uv or vim.loop ---@type boolean -M.is_windows = uv.os_uname().version:match("Windows") +M.is_windows = uv.os_uname().version:match('Windows') -M.is_mac = uv.os_uname().sysname == "Darwin" +M.is_mac = uv.os_uname().sysname == 'Darwin' M.is_linux = not M.is_windows and not M.is_mac ---@type string -M.sep = M.is_windows and "\\" or "/" +M.sep = M.is_windows and '\\' or '/' ---@param ... string M.join = function(...) @@ -23,15 +23,15 @@ end ---@return boolean M.is_absolute = function(dir) if M.is_windows then - return dir:match("^%a:\\") + return dir:match('^%a:\\') else - return vim.startswith(dir, "/") + return vim.startswith(dir, '/') end end M.abspath = function(path) if not M.is_absolute(path) then - path = vim.fn.fnamemodify(path, ":p") + path = vim.fn.fnamemodify(path, ':p') end return path end @@ -40,11 +40,11 @@ end ---@param mode? integer File mode in decimal (default 420 = 0644) ---@param cb fun(err: nil|string) M.touch = function(path, mode, cb) - if type(mode) == "function" then + if type(mode) == 'function' then cb = mode mode = 420 end - uv.fs_open(path, "a", mode or 420, function(err, fd) + uv.fs_open(path, 'a', mode or 420, function(err, fd) if err then cb(err) else @@ -59,12 +59,12 @@ end ---@param candidate string ---@return boolean M.is_subpath = function(root, candidate) - if candidate == "" then + if candidate == '' then return false end root = vim.fs.normalize(M.abspath(root)) -- Trim trailing "/" from the root - if root:find("/", -1) then + if root:find('/', -1) then root = root:sub(1, -2) end candidate = vim.fs.normalize(M.abspath(candidate)) @@ -80,8 +80,8 @@ M.is_subpath = function(root, candidate) return false end - local candidate_starts_with_sep = candidate:find("/", root:len() + 1, true) == root:len() + 1 - local root_ends_with_sep = root:find("/", root:len(), true) == root:len() + local candidate_starts_with_sep = candidate:find('/', root:len() + 1, true) == root:len() + 1 + local root_ends_with_sep = root:find('/', root:len(), true) == root:len() return candidate_starts_with_sep or root_ends_with_sep end @@ -90,15 +90,15 @@ end ---@return string M.posix_to_os_path = function(path) if M.is_windows then - if vim.startswith(path, "/") then - local drive = path:match("^/(%a+)") + if vim.startswith(path, '/') then + local drive = path:match('^/(%a+)') if not drive then return path end local rem = path:sub(drive:len() + 2) - return string.format("%s:%s", drive, rem:gsub("/", "\\")) + return string.format('%s:%s', drive, rem:gsub('/', '\\')) else - local newpath = path:gsub("/", "\\") + local newpath = path:gsub('/', '\\') return newpath end else @@ -111,10 +111,10 @@ end M.os_to_posix_path = function(path) if M.is_windows then if M.is_absolute(path) then - local drive, rem = path:match("^([^:]+):\\(.*)$") - return string.format("/%s/%s", drive:upper(), rem:gsub("\\", "/")) + local drive, rem = path:match('^([^:]+):\\(.*)$') + return string.format('/%s/%s', drive:upper(), rem:gsub('\\', '/')) else - local newpath = path:gsub("\\", "/") + local newpath = path:gsub('\\', '/') return newpath end else @@ -135,16 +135,16 @@ M.shorten_path = function(path, relative_to) if M.is_subpath(relative_to, path) then local idx = relative_to:len() + 1 -- Trim the dividing slash if it's not included in relative_to - if not vim.endswith(relative_to, "/") and not vim.endswith(relative_to, "\\") then + if not vim.endswith(relative_to, '/') and not vim.endswith(relative_to, '\\') then idx = idx + 1 end relpath = path:sub(idx) - if relpath == "" then - relpath = "." + if relpath == '' then + relpath = '.' end end if M.is_subpath(home_dir, path) then - local homepath = "~" .. path:sub(home_dir:len() + 1) + local homepath = '~' .. path:sub(home_dir:len() + 1) if not relpath or homepath:len() < relpath:len() then return homepath end @@ -156,13 +156,13 @@ end ---@param mode? integer M.mkdirp = function(dir, mode) mode = mode or 493 - local mod = "" + local mod = '' local path = dir while vim.fn.isdirectory(path) == 0 do - mod = mod .. ":h" + mod = mod .. ':h' path = vim.fn.fnamemodify(dir, mod) end - while mod ~= "" do + while mod ~= '' do mod = mod:sub(3) path = vim.fn.fnamemodify(dir, mod) uv.fs_mkdir(path, mode) @@ -209,7 +209,7 @@ end ---@param path string ---@param cb fun(err: nil|string) M.recursive_delete = function(entry_type, path, cb) - if entry_type ~= "directory" then + if entry_type ~= 'directory' then return uv.fs_unlink(path, cb) end ---@diagnostic disable-next-line: param-type-mismatch, discard-returns @@ -271,13 +271,13 @@ local move_undofile = vim.schedule_wrap(function(src_path, dest_path, copy) if copy then uv.fs_copyfile(src_path, dest_path, function(err) if err then - log.warn("Error copying undofile %s: %s", undofile, err) + log.warn('Error copying undofile %s: %s', undofile, err) end end) else uv.fs_rename(undofile, dest_undofile, function(err) if err then - log.warn("Error moving undofile %s: %s", undofile, err) + log.warn('Error moving undofile %s: %s', undofile, err) end end) end @@ -290,7 +290,7 @@ end) ---@param dest_path string ---@param cb fun(err: nil|string) M.recursive_copy = function(entry_type, src_path, dest_path, cb) - if entry_type == "link" then + if entry_type == 'link' then uv.fs_readlink(src_path, function(link_err, link) if link_err then return cb(link_err) @@ -300,7 +300,7 @@ M.recursive_copy = function(entry_type, src_path, dest_path, cb) end) return end - if entry_type ~= "directory" then + if entry_type ~= 'directory' then uv.fs_copyfile(src_path, dest_path, { excl = true }, cb) move_undofile(src_path, dest_path, true) return @@ -374,7 +374,7 @@ M.recursive_move = function(entry_type, src_path, dest_path, cb) end end) else - if entry_type ~= "directory" then + if entry_type ~= 'directory' then move_undofile(src_path, dest_path, false) end cb() diff --git a/lua/oil/git.lua b/lua/oil/git.lua index ec3b84b..9fab6e4 100644 --- a/lua/oil/git.lua +++ b/lua/oil/git.lua @@ -1,12 +1,12 @@ -- integration with git operations -local fs = require("oil.fs") +local fs = require('oil.fs') local M = {} ---@param path string ---@return string|nil M.get_root = function(path) - local git_dir = vim.fs.find(".git", { upward = true, path = path })[1] + local git_dir = vim.fs.find('.git', { upward = true, path = path })[1] if git_dir then return vim.fs.dirname(git_dir) else @@ -22,16 +22,16 @@ M.add = function(path, cb) return cb() end - local stderr = "" - local jid = vim.fn.jobstart({ "git", "add", path }, { + local stderr = '' + local jid = vim.fn.jobstart({ 'git', 'add', path }, { cwd = root, stderr_buffered = true, on_stderr = function(_, data) - stderr = table.concat(data, "\n") + stderr = table.concat(data, '\n') end, on_exit = function(_, code) if code ~= 0 then - cb("Error in git add: " .. stderr) + cb('Error in git add: ' .. stderr) else cb() end @@ -50,12 +50,12 @@ M.rm = function(path, cb) return cb() end - local stderr = "" - local jid = vim.fn.jobstart({ "git", "rm", "-r", path }, { + local stderr = '' + local jid = vim.fn.jobstart({ 'git', 'rm', '-r', path }, { cwd = root, stderr_buffered = true, on_stderr = function(_, data) - stderr = table.concat(data, "\n") + stderr = table.concat(data, '\n') end, on_exit = function(_, code) if code ~= 0 then @@ -63,7 +63,7 @@ M.rm = function(path, cb) if stderr:match("^fatal: pathspec '.*' did not match any files$") then cb() else - cb("Error in git rm: " .. stderr) + cb('Error in git rm: ' .. stderr) end else cb() @@ -86,23 +86,23 @@ M.mv = function(entry_type, src_path, dest_path, cb) return end - local stderr = "" - local jid = vim.fn.jobstart({ "git", "mv", src_path, dest_path }, { + local stderr = '' + local jid = vim.fn.jobstart({ 'git', 'mv', src_path, dest_path }, { cwd = src_git, stderr_buffered = true, on_stderr = function(_, data) - stderr = table.concat(data, "\n") + stderr = table.concat(data, '\n') end, on_exit = function(_, code) if code ~= 0 then stderr = vim.trim(stderr) if - stderr:match("^fatal: not under version control") - or stderr:match("^fatal: source directory is empty") + stderr:match('^fatal: not under version control') + or stderr:match('^fatal: source directory is empty') then fs.recursive_move(entry_type, src_path, dest_path, cb) else - cb("Error in git mv: " .. stderr) + cb('Error in git mv: ' .. stderr) end else cb() diff --git a/lua/oil/init.lua b/lua/oil/init.lua index 0329afd..d3e6223 100644 --- a/lua/oil/init.lua +++ b/lua/oil/init.lua @@ -35,10 +35,10 @@ local M = {} ---@param lnum integer ---@return nil|oil.Entry M.get_entry_on_line = function(bufnr, lnum) - local columns = require("oil.columns") - local parser = require("oil.mutator.parser") - local util = require("oil.util") - if vim.bo[bufnr].filetype ~= "oil" then + local columns = require('oil.columns') + local parser = require('oil.mutator.parser') + local util = require('oil.util') + if vim.bo[bufnr].filetype ~= 'oil' then return nil end local adapter = util.get_adapter(bufnr) @@ -69,13 +69,13 @@ M.get_entry_on_line = function(bufnr, lnum) -- This is a NEW entry that hasn't been saved yet local name = vim.trim(line) local entry_type - if vim.endswith(name, "/") then + if vim.endswith(name, '/') then name = name:sub(1, name:len() - 1) - entry_type = "directory" + entry_type = 'directory' else - entry_type = "file" + entry_type = 'file' end - if name == "" then + if name == '' then return nil else return { @@ -95,14 +95,14 @@ end ---Discard all changes made to oil buffers M.discard_all_changes = function() - local view = require("oil.view") + local view = require('oil.view') for _, bufnr in ipairs(view.get_all_buffers()) do if vim.bo[bufnr].modified then view.render_buffer_async(bufnr, {}, function(err) if err then vim.notify( string.format( - "Error rendering oil buffer %s: %s", + 'Error rendering oil buffer %s: %s', vim.api.nvim_buf_get_name(bufnr), err ), @@ -117,7 +117,7 @@ end ---Change the display columns for oil ---@param cols oil.ColumnSpec[] M.set_columns = function(cols) - require("oil.view").set_columns(cols) + require('oil.view').set_columns(cols) end ---Change the sort order for oil @@ -125,30 +125,30 @@ end ---@example --- require("oil").set_sort({ { "type", "asc" }, { "size", "desc" } }) M.set_sort = function(sort) - require("oil.view").set_sort(sort) + require('oil.view').set_sort(sort) end ---Change how oil determines if the file is hidden ---@param is_hidden_file fun(filename: string, bufnr: integer, entry: oil.Entry): boolean Return true if the file/dir should be hidden M.set_is_hidden_file = function(is_hidden_file) - require("oil.view").set_is_hidden_file(is_hidden_file) + require('oil.view').set_is_hidden_file(is_hidden_file) end ---Toggle hidden files and directories M.toggle_hidden = function() - require("oil.view").toggle_hidden() + require('oil.view').toggle_hidden() end ---Get the current directory ---@param bufnr? integer ---@return nil|string M.get_current_dir = function(bufnr) - local config = require("oil.config") - local fs = require("oil.fs") - local util = require("oil.util") + local config = require('oil.config') + local fs = require('oil.fs') + local util = require('oil.util') local buf_name = vim.api.nvim_buf_get_name(bufnr or 0) local scheme, path = util.parse_url(buf_name) - if config.adapters[scheme] == "files" then + if config.adapters[scheme] == 'files' then assert(path) return fs.posix_to_os_path(path) end @@ -164,10 +164,10 @@ M.get_url_for_path = function(dir, use_oil_parent) if use_oil_parent == nil then use_oil_parent = true end - local config = require("oil.config") - local fs = require("oil.fs") - local util = require("oil.util") - if vim.bo.filetype == "netrw" and not dir then + local config = require('oil.config') + local fs = require('oil.fs') + local util = require('oil.util') + if vim.bo.filetype == 'netrw' and not dir then dir = vim.b.netrw_curdir end if dir then @@ -175,7 +175,7 @@ M.get_url_for_path = function(dir, use_oil_parent) if scheme then return dir end - local abspath = vim.fn.fnamemodify(dir, ":p") + local abspath = vim.fn.fnamemodify(dir, ':p') local path = fs.os_to_posix_path(abspath) return config.adapter_to_scheme.files .. path else @@ -190,27 +190,27 @@ end ---@return string ---@return nil|string M.get_buffer_parent_url = function(bufname, use_oil_parent) - local config = require("oil.config") - local fs = require("oil.fs") - local pathutil = require("oil.pathutil") - local util = require("oil.util") + local config = require('oil.config') + local fs = require('oil.fs') + local pathutil = require('oil.pathutil') + local util = require('oil.util') local scheme, path = util.parse_url(bufname) if not scheme then local parent, basename scheme = config.adapter_to_scheme.files - if bufname == "" then + if bufname == '' then parent = fs.os_to_posix_path(vim.fn.getcwd()) else - parent = fs.os_to_posix_path(vim.fn.fnamemodify(bufname, ":p:h")) - basename = vim.fn.fnamemodify(bufname, ":t") + parent = fs.os_to_posix_path(vim.fn.fnamemodify(bufname, ':p:h')) + basename = vim.fn.fnamemodify(bufname, ':t') end local parent_url = util.addslash(scheme .. parent) return parent_url, basename else assert(path) - if scheme == "term://" then + if scheme == 'term://' then ---@type string - path = vim.fn.expand(path:match("^(.*)//")) ---@diagnostic disable-line: assign-type-mismatch + path = vim.fn.expand(path:match('^(.*)//')) ---@diagnostic disable-line: assign-type-mismatch return config.adapter_to_scheme.files .. util.addslash(path) end @@ -248,10 +248,10 @@ end ---@param cb? fun() Called after the oil buffer is ready M.open_float = function(dir, opts, cb) opts = opts or {} - local config = require("oil.config") - local layout = require("oil.layout") - local util = require("oil.util") - local view = require("oil.view") + local config = require('oil.config') + local layout = require('oil.layout') + local util = require('oil.util') + local view = require('oil.view') local parent_url, basename = M.get_url_for_path(dir) if basename then @@ -259,7 +259,7 @@ M.open_float = function(dir, opts, cb) end local bufnr = vim.api.nvim_create_buf(false, true) - vim.bo[bufnr].bufhidden = "wipe" + vim.bo[bufnr].bufhidden = 'wipe' local win_opts = layout.get_fullscreen_win_opts() local original_winid = vim.api.nvim_get_current_win() @@ -267,16 +267,16 @@ M.open_float = function(dir, opts, cb) vim.w[winid].is_oil_win = true vim.w[winid].oil_original_win = original_winid for k, v in pairs(config.float.win_options) do - vim.api.nvim_set_option_value(k, v, { scope = "local", win = winid }) + vim.api.nvim_set_option_value(k, v, { scope = 'local', win = winid }) end local autocmds = {} table.insert( autocmds, - vim.api.nvim_create_autocmd("WinLeave", { - desc = "Close floating oil window", - group = "Oil", + vim.api.nvim_create_autocmd('WinLeave', { + desc = 'Close floating oil window', + group = 'Oil', callback = vim.schedule_wrap(function() - if util.is_floating_win() or vim.fn.win_gettype() == "command" then + if util.is_floating_win() or vim.fn.win_gettype() == 'command' then return end if vim.api.nvim_win_is_valid(winid) then @@ -293,23 +293,23 @@ M.open_float = function(dir, opts, cb) table.insert( autocmds, - vim.api.nvim_create_autocmd("BufWinEnter", { - desc = "Reset local oil window options when buffer changes", - pattern = "*", + vim.api.nvim_create_autocmd('BufWinEnter', { + desc = 'Reset local oil window options when buffer changes', + pattern = '*', callback = function(params) local winbuf = params.buf if not vim.api.nvim_win_is_valid(winid) or vim.api.nvim_win_get_buf(winid) ~= winbuf then return end for k, v in pairs(config.float.win_options) do - vim.api.nvim_set_option_value(k, v, { scope = "local", win = winid }) + vim.api.nvim_set_option_value(k, v, { scope = 'local', win = winid }) end -- Update the floating window title - if vim.fn.has("nvim-0.9") == 1 and config.float.border ~= "none" then + if vim.fn.has('nvim-0.9') == 1 and config.float.border ~= 'none' then local cur_win_opts = vim.api.nvim_win_get_config(winid) vim.api.nvim_win_set_config(winid, { - relative = "editor", + relative = 'editor', row = cur_win_opts.row, col = cur_win_opts.col, width = cur_win_opts.width, @@ -324,7 +324,7 @@ M.open_float = function(dir, opts, cb) vim.cmd.edit({ args = { util.escape_filename(parent_url) }, mods = { keepalt = true } }) -- :edit will set buflisted = true, but we may not want that if config.buf_options.buflisted ~= nil then - vim.api.nvim_set_option_value("buflisted", config.buf_options.buflisted, { buf = 0 }) + vim.api.nvim_set_option_value('buflisted', config.buf_options.buflisted, { buf = 0 }) end util.run_after_load(0, function() @@ -335,7 +335,7 @@ M.open_float = function(dir, opts, cb) end end) - if vim.fn.has("nvim-0.9") == 0 then + if vim.fn.has('nvim-0.9') == 0 then util.add_title_to_win(winid) end end @@ -358,7 +358,7 @@ end ---@param oil_bufnr? integer local function update_preview_window(oil_bufnr) oil_bufnr = oil_bufnr or 0 - local util = require("oil.util") + local util = require('oil.util') util.run_after_load(oil_bufnr, function() local cursor_entry = M.get_cursor_entry() local preview_win_id = util.get_preview_win() @@ -378,9 +378,9 @@ end ---@param cb? fun() Called after the oil buffer is ready M.open = function(dir, opts, cb) opts = opts or {} - local config = require("oil.config") - local util = require("oil.util") - local view = require("oil.view") + local config = require('oil.config') + local util = require('oil.util') + local view = require('oil.view') local parent_url, basename = M.get_url_for_path(dir) if basename then view.set_last_cursor(parent_url, basename) @@ -388,7 +388,7 @@ M.open = function(dir, opts, cb) vim.cmd.edit({ args = { util.escape_filename(parent_url) }, mods = { keepalt = true } }) -- :edit will set buflisted = true, but we may not want that if config.buf_options.buflisted ~= nil then - vim.api.nvim_set_option_value("buflisted", config.buf_options.buflisted, { buf = 0 }) + vim.api.nvim_set_option_value('buflisted', config.buf_options.buflisted, { buf = 0 }) end util.run_after_load(0, function() @@ -411,8 +411,8 @@ end M.close = function(opts) opts = opts or {} local mode = vim.api.nvim_get_mode().mode - if mode:match("^[vVsS\22\19]") or mode:match("^no") then - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("", true, true, true), "n", false) + if mode:match('^[vVsS\22\19]') or mode:match('^no') then + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, true, true), 'n', false) return end -- If we're in a floating oil window, close it and try to restore focus to the original window @@ -424,7 +424,7 @@ M.close = function(opts) end return end - local ok, bufnr = pcall(vim.api.nvim_win_get_var, 0, "oil_original_buffer") + local ok, bufnr = pcall(vim.api.nvim_win_get_var, 0, 'oil_original_buffer') if ok and vim.api.nvim_buf_is_valid(bufnr) then vim.api.nvim_win_set_buf(0, bufnr) if vim.w.oil_original_view then @@ -459,9 +459,9 @@ end ---@param callback? fun(err: nil|string) Called once the preview window has been opened M.open_preview = function(opts, callback) opts = opts or {} - local config = require("oil.config") - local layout = require("oil.layout") - local util = require("oil.util") + local config = require('oil.config') + local layout = require('oil.layout') + local util = require('oil.util') local function finish(err) if err then @@ -477,9 +477,9 @@ M.open_preview = function(opts, callback) end if not opts.split then if opts.horizontal then - opts.split = vim.o.splitbelow and "belowright" or "aboveleft" + opts.split = vim.o.splitbelow and 'belowright' or 'aboveleft' else - opts.split = vim.o.splitright and "belowright" or "aboveleft" + opts.split = vim.o.splitright and 'belowright' or 'aboveleft' end end @@ -489,11 +489,11 @@ M.open_preview = function(opts, callback) local entry = M.get_cursor_entry() if not entry then - return finish("Could not find entry under cursor") + return finish('Could not find entry under cursor') end local entry_title = entry.name - if entry.type == "directory" then - entry_title = entry_title .. "/" + if entry.type == 'directory' then + entry_title = entry_title .. '/' end if util.is_floating_win() then @@ -502,7 +502,7 @@ M.open_preview = function(opts, callback) layout.split_window(0, config.float.preview_split, config.float.padding) local win_opts_oil = { - relative = "editor", + relative = 'editor', width = root_win_opts.width, height = root_win_opts.height, row = root_win_opts.row, @@ -512,7 +512,7 @@ M.open_preview = function(opts, callback) } vim.api.nvim_win_set_config(0, win_opts_oil) local win_opts = { - relative = "editor", + relative = 'editor', width = preview_win_opts.width, height = preview_win_opts.height, row = preview_win_opts.row, @@ -521,23 +521,23 @@ M.open_preview = function(opts, callback) zindex = 45, focusable = false, noautocmd = true, - style = "minimal", + style = 'minimal', } - if vim.fn.has("nvim-0.9") == 1 then + if vim.fn.has('nvim-0.9') == 1 then win_opts.title = entry_title end preview_win = vim.api.nvim_open_win(bufnr, true, win_opts) - vim.api.nvim_set_option_value("previewwindow", true, { scope = "local", win = preview_win }) - vim.api.nvim_win_set_var(preview_win, "oil_preview", true) + vim.api.nvim_set_option_value('previewwindow', true, { scope = 'local', win = preview_win }) + vim.api.nvim_win_set_var(preview_win, 'oil_preview', true) vim.api.nvim_set_current_win(prev_win) - elseif vim.fn.has("nvim-0.9") == 1 then + elseif vim.fn.has('nvim-0.9') == 1 then vim.api.nvim_win_set_config(preview_win, { title = entry_title }) end end - local cmd = preview_win and "buffer" or "sbuffer" + local cmd = preview_win and 'buffer' or 'sbuffer' local mods = { vertical = opts.vertical, horizontal = opts.horizontal, @@ -549,11 +549,11 @@ M.open_preview = function(opts, callback) -- not get set properly. So we have to switch windows this way instead. local hack_set_win = function(winid) local winnr = vim.api.nvim_win_get_number(winid) - vim.cmd.wincmd({ args = { "w" }, count = winnr }) + vim.cmd.wincmd({ args = { 'w' }, count = winnr }) end util.get_edit_path(bufnr, entry, function(normalized_url) - local mc = package.loaded["multicursor-nvim"] + local mc = package.loaded['multicursor-nvim'] local has_multicursors = mc and mc.hasCursors() local is_visual_mode = util.is_visual_mode() if preview_win then @@ -564,16 +564,16 @@ M.open_preview = function(opts, callback) end end - local entry_is_file = not vim.endswith(normalized_url, "/") + local entry_is_file = not vim.endswith(normalized_url, '/') local filebufnr if entry_is_file then if config.preview_win.disable_preview(normalized_url) then filebufnr = vim.api.nvim_create_buf(false, true) - vim.bo[filebufnr].bufhidden = "wipe" - vim.bo[filebufnr].buftype = "nofile" - util.render_text(filebufnr, "Preview disabled", { winid = preview_win }) + vim.bo[filebufnr].bufhidden = 'wipe' + vim.bo[filebufnr].buftype = 'nofile' + util.render_text(filebufnr, 'Preview disabled', { winid = preview_win }) elseif - config.preview_win.preview_method ~= "load" + config.preview_win.preview_method ~= 'load' and not util.file_matches_bufreadcmd(normalized_url) then filebufnr = @@ -584,7 +584,7 @@ M.open_preview = function(opts, callback) if not filebufnr then filebufnr = vim.fn.bufadd(normalized_url) if entry_is_file and vim.fn.bufloaded(filebufnr) == 0 then - vim.bo[filebufnr].bufhidden = "wipe" + vim.bo[filebufnr].bufhidden = 'wipe' vim.b[filebufnr].oil_preview_buffer = true end end @@ -596,8 +596,8 @@ M.open_preview = function(opts, callback) mods = mods, }) -- Ignore swapfile errors - if not ok and err and not err:match("^Vim:E325:") then - vim.api.nvim_echo({ { err, "Error" } }, true, {}) + if not ok and err and not err:match('^Vim:E325:') then + vim.api.nvim_echo({ { err, 'Error' } }, true, {}) end -- If we called open_preview during an autocmd, then the edit command may not trigger the @@ -606,10 +606,10 @@ M.open_preview = function(opts, callback) M.load_oil_buffer(filebufnr) end - vim.api.nvim_set_option_value("previewwindow", true, { scope = "local", win = 0 }) - vim.api.nvim_win_set_var(0, "oil_preview", true) + vim.api.nvim_set_option_value('previewwindow', true, { scope = 'local', win = 0 }) + vim.api.nvim_win_set_var(0, 'oil_preview', true) for k, v in pairs(config.preview_win.win_options) do - vim.api.nvim_set_option_value(k, v, { scope = "local", win = preview_win }) + vim.api.nvim_set_option_value(k, v, { scope = 'local', win = preview_win }) end vim.w.oil_entry_id = entry.id vim.w.oil_source_win = prev_win @@ -619,7 +619,7 @@ M.open_preview = function(opts, callback) elseif is_visual_mode then hack_set_win(prev_win) -- Restore the visual selection - vim.cmd.normal({ args = { "gv" }, bang = true }) + vim.cmd.normal({ args = { 'gv' }, bang = true }) else vim.api.nvim_set_current_win(prev_win) end @@ -639,12 +639,12 @@ end ---@param opts nil|oil.SelectOpts ---@param callback nil|fun(err: nil|string) Called once all entries have been opened M.select = function(opts, callback) - local cache = require("oil.cache") - local config = require("oil.config") - local constants = require("oil.constants") - local util = require("oil.util") + local cache = require('oil.cache') + local config = require('oil.config') + local constants = require('oil.constants') + local util = require('oil.util') local FIELD_META = constants.FIELD_META - opts = vim.tbl_extend("keep", opts or {}, {}) + opts = vim.tbl_extend('keep', opts or {}, {}) local function finish(err) if err then @@ -656,17 +656,17 @@ M.select = function(opts, callback) end if not opts.split and (opts.horizontal or opts.vertical) then if opts.horizontal then - opts.split = vim.o.splitbelow and "belowright" or "aboveleft" + opts.split = vim.o.splitbelow and 'belowright' or 'aboveleft' else - opts.split = vim.o.splitright and "belowright" or "aboveleft" + opts.split = vim.o.splitright and 'belowright' or 'aboveleft' end end if opts.tab and opts.split then - return finish("Cannot use split=true when tab = true") + return finish('Cannot use split=true when tab = true') end local adapter = util.get_adapter(0) if not adapter then - return finish("Not an oil buffer") + return finish('Not an oil buffer') end local visual_range = util.get_visual_range() @@ -687,7 +687,7 @@ M.select = function(opts, callback) end end if vim.tbl_isempty(entries) then - return finish("Could not find entry under cursor") + return finish('Could not find entry under cursor') end -- Check if any of these entries are moved from their original location @@ -713,7 +713,7 @@ M.select = function(opts, callback) end end if any_moved and config.prompt_save_on_select_new_entry then - local ok, choice = pcall(vim.fn.confirm, "Save changes?", "Yes\nNo", 1) + local ok, choice = pcall(vim.fn.confirm, 'Save changes?', 'Yes\nNo', 1) if not ok then return finish() elseif choice == 1 then @@ -738,7 +738,7 @@ M.select = function(opts, callback) -- entry. This prevents the case of MOVE /foo -> /bar + CREATE /foo. -- If you enter the new /foo, it will show the contents of the old /foo. if not entry.id and cache.list_url(bufname)[entry.name] then - return cb("Please save changes before entering new directory") + return cb('Please save changes before entering new directory') end else -- Close floating window before opening a file @@ -757,7 +757,7 @@ M.select = function(opts, callback) keepalt = false, } local filebufnr = vim.fn.bufadd(normalized_url) - local entry_is_file = not vim.endswith(normalized_url, "/") + local entry_is_file = not vim.endswith(normalized_url, '/') -- The :buffer command doesn't set buflisted=true -- So do that for normal files or for oil dirs if config set buflisted=true @@ -765,13 +765,13 @@ M.select = function(opts, callback) vim.bo[filebufnr].buflisted = true end - local cmd = "buffer" + local cmd = 'buffer' if opts.tab then vim.cmd.tabnew({ mods = mods }) -- Make sure the new buffer from tabnew gets cleaned up - vim.bo.bufhidden = "wipe" + vim.bo.bufhidden = 'wipe' elseif opts.split then - cmd = "sbuffer" + cmd = 'sbuffer' end if opts.handle_buffer_callback ~= nil then opts.handle_buffer_callback(filebufnr) @@ -783,8 +783,8 @@ M.select = function(opts, callback) mods = mods, }) -- Ignore swapfile errors - if not ok and err and not err:match("^Vim:E325:") then - vim.api.nvim_echo({ { err, "Error" } }, true, {}) + if not ok and err and not err:match('^Vim:E325:') then + vim.api.nvim_echo({ { err, 'Error' } }, true, {}) end end @@ -815,21 +815,21 @@ end ---@param bufnr integer ---@return boolean local function maybe_hijack_directory_buffer(bufnr) - local config = require("oil.config") - local fs = require("oil.fs") - local util = require("oil.util") + local config = require('oil.config') + local fs = require('oil.fs') + local util = require('oil.util') if not config.default_file_explorer then return false end local bufname = vim.api.nvim_buf_get_name(bufnr) - if bufname == "" then + if bufname == '' then return false end if util.parse_url(bufname) or vim.fn.isdirectory(bufname) == 0 then return false end local new_name = util.addslash( - config.adapter_to_scheme.files .. fs.os_to_posix_path(vim.fn.fnamemodify(bufname, ":p")) + config.adapter_to_scheme.files .. fs.os_to_posix_path(vim.fn.fnamemodify(bufname, ':p')) ) local replaced = util.rename_buffer(bufnr, new_name) return not replaced @@ -839,149 +839,149 @@ end M._get_highlights = function() return { { - name = "OilEmpty", - link = "Comment", - desc = "Empty column values", + name = 'OilEmpty', + link = 'Comment', + desc = 'Empty column values', }, { - name = "OilHidden", - link = "Comment", - desc = "Hidden entry in an oil buffer", + name = 'OilHidden', + link = 'Comment', + desc = 'Hidden entry in an oil buffer', }, { - name = "OilDir", - link = "Directory", - desc = "Directory names in an oil buffer", + name = 'OilDir', + link = 'Directory', + desc = 'Directory names in an oil buffer', }, { - name = "OilDirHidden", - link = "OilHidden", - desc = "Hidden directory names in an oil buffer", + name = 'OilDirHidden', + link = 'OilHidden', + desc = 'Hidden directory names in an oil buffer', }, { - name = "OilDirIcon", - link = "OilDir", - desc = "Icon for directories", + name = 'OilDirIcon', + link = 'OilDir', + desc = 'Icon for directories', }, { - name = "OilFileIcon", + name = 'OilFileIcon', link = nil, - desc = "Icon for files", + desc = 'Icon for files', }, { - name = "OilSocket", - link = "Keyword", - desc = "Socket files in an oil buffer", + name = 'OilSocket', + link = 'Keyword', + desc = 'Socket files in an oil buffer', }, { - name = "OilSocketHidden", - link = "OilHidden", - desc = "Hidden socket files in an oil buffer", + name = 'OilSocketHidden', + link = 'OilHidden', + desc = 'Hidden socket files in an oil buffer', }, { - name = "OilLink", + name = 'OilLink', link = nil, - desc = "Soft links in an oil buffer", + desc = 'Soft links in an oil buffer', }, { - name = "OilOrphanLink", + name = 'OilOrphanLink', link = nil, - desc = "Orphaned soft links in an oil buffer", + desc = 'Orphaned soft links in an oil buffer', }, { - name = "OilLinkHidden", - link = "OilHidden", - desc = "Hidden soft links in an oil buffer", + name = 'OilLinkHidden', + link = 'OilHidden', + desc = 'Hidden soft links in an oil buffer', }, { - name = "OilOrphanLinkHidden", - link = "OilLinkHidden", - desc = "Hidden orphaned soft links in an oil buffer", + name = 'OilOrphanLinkHidden', + link = 'OilLinkHidden', + desc = 'Hidden orphaned soft links in an oil buffer', }, { - name = "OilLinkTarget", - link = "Comment", - desc = "The target of a soft link", + name = 'OilLinkTarget', + link = 'Comment', + desc = 'The target of a soft link', }, { - name = "OilOrphanLinkTarget", - link = "DiagnosticError", - desc = "The target of an orphaned soft link", + name = 'OilOrphanLinkTarget', + link = 'DiagnosticError', + desc = 'The target of an orphaned soft link', }, { - name = "OilLinkTargetHidden", - link = "OilHidden", - desc = "The target of a hidden soft link", + name = 'OilLinkTargetHidden', + link = 'OilHidden', + desc = 'The target of a hidden soft link', }, { - name = "OilOrphanLinkTargetHidden", - link = "OilOrphanLinkTarget", - desc = "The target of an hidden orphaned soft link", + name = 'OilOrphanLinkTargetHidden', + link = 'OilOrphanLinkTarget', + desc = 'The target of an hidden orphaned soft link', }, { - name = "OilFile", + name = 'OilFile', link = nil, - desc = "Normal files in an oil buffer", + desc = 'Normal files in an oil buffer', }, { - name = "OilFileHidden", - link = "OilHidden", - desc = "Hidden normal files in an oil buffer", + name = 'OilFileHidden', + link = 'OilHidden', + desc = 'Hidden normal files in an oil buffer', }, { - name = "OilExecutable", - link = "DiagnosticOk", - desc = "Executable files in an oil buffer", + name = 'OilExecutable', + link = 'DiagnosticOk', + desc = 'Executable files in an oil buffer', }, { - name = "OilExecutableHidden", - link = "OilHidden", - desc = "Hidden executable files in an oil buffer", + name = 'OilExecutableHidden', + link = 'OilHidden', + desc = 'Hidden executable files in an oil buffer', }, { - name = "OilCreate", - link = "DiagnosticInfo", - desc = "Create action in the oil preview window", + name = 'OilCreate', + link = 'DiagnosticInfo', + desc = 'Create action in the oil preview window', }, { - name = "OilDelete", - link = "DiagnosticError", - desc = "Delete action in the oil preview window", + name = 'OilDelete', + link = 'DiagnosticError', + desc = 'Delete action in the oil preview window', }, { - name = "OilMove", - link = "DiagnosticWarn", - desc = "Move action in the oil preview window", + name = 'OilMove', + link = 'DiagnosticWarn', + desc = 'Move action in the oil preview window', }, { - name = "OilCopy", - link = "DiagnosticHint", - desc = "Copy action in the oil preview window", + name = 'OilCopy', + link = 'DiagnosticHint', + desc = 'Copy action in the oil preview window', }, { - name = "OilChange", - link = "Special", - desc = "Change action in the oil preview window", + name = 'OilChange', + link = 'Special', + desc = 'Change action in the oil preview window', }, { - name = "OilRestore", - link = "OilCreate", - desc = "Restore (from the trash) action in the oil preview window", + name = 'OilRestore', + link = 'OilCreate', + desc = 'Restore (from the trash) action in the oil preview window', }, { - name = "OilPurge", - link = "OilDelete", - desc = "Purge (Permanently delete a file from trash) action in the oil preview window", + name = 'OilPurge', + link = 'OilDelete', + desc = 'Purge (Permanently delete a file from trash) action in the oil preview window', }, { - name = "OilTrash", - link = "OilDelete", - desc = "Trash (delete a file to trash) action in the oil preview window", + name = 'OilTrash', + link = 'OilDelete', + desc = 'Trash (delete a file to trash) action in the oil preview window', }, { - name = "OilTrashSourcePath", - link = "Comment", - desc = "Virtual text that shows the original path of file in the trash", + name = 'OilTrashSourcePath', + link = 'Comment', + desc = 'Virtual text that shows the original path of file in the trash', }, } end @@ -995,14 +995,14 @@ local function set_colors() -- TODO can remove this call once we drop support for Neovim 0.8. FloatTitle was introduced as a -- built-in highlight group in 0.9, and we can start to rely on colorschemes setting it. ---@diagnostic disable-next-line: deprecated - if vim.fn.has("nvim-0.9") == 0 and not pcall(vim.api.nvim_get_hl_by_name, "FloatTitle", true) then + if vim.fn.has('nvim-0.9') == 0 and not pcall(vim.api.nvim_get_hl_by_name, 'FloatTitle', true) then ---@diagnostic disable-next-line: deprecated - local border = vim.api.nvim_get_hl_by_name("FloatBorder", true) + local border = vim.api.nvim_get_hl_by_name('FloatBorder', true) ---@diagnostic disable-next-line: deprecated - local normal = vim.api.nvim_get_hl_by_name("Normal", true) + local normal = vim.api.nvim_get_hl_by_name('Normal', true) vim.api.nvim_set_hl( 0, - "FloatTitle", + 'FloatTitle', { fg = normal.foreground, bg = border.background or normal.background } ) end @@ -1018,35 +1018,35 @@ M.save = function(opts, cb) opts = opts or {} if not cb then cb = function(err) - if err and err ~= "Canceled" then + if err and err ~= 'Canceled' then vim.notify(err, vim.log.levels.ERROR) end end end - local mutator = require("oil.mutator") + local mutator = require('oil.mutator') mutator.try_write_changes(opts.confirm, cb) end local function restore_alt_buf() - if vim.bo.filetype == "oil" then - require("oil.view").set_win_options() - vim.api.nvim_win_set_var(0, "oil_did_enter", true) + if vim.bo.filetype == 'oil' then + require('oil.view').set_win_options() + vim.api.nvim_win_set_var(0, 'oil_did_enter', true) elseif vim.w.oil_did_enter then - vim.api.nvim_win_del_var(0, "oil_did_enter") + vim.api.nvim_win_del_var(0, 'oil_did_enter') -- We are entering a non-oil buffer *after* having been in an oil buffer - local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, "oil_original_buffer") + local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, 'oil_original_buffer') if has_orig and vim.api.nvim_buf_is_valid(orig_buffer) then if vim.api.nvim_get_current_buf() ~= orig_buffer then -- If we are editing a new file after navigating around oil, set the alternate buffer -- to be the last buffer we were in before opening oil - vim.fn.setreg("#", orig_buffer) + vim.fn.setreg('#', orig_buffer) else -- If we are editing the same buffer that we started oil from, set the alternate to be -- what it was before we opened oil local has_orig_alt, alt_buffer = - pcall(vim.api.nvim_win_get_var, 0, "oil_original_alternate") + pcall(vim.api.nvim_win_get_var, 0, 'oil_original_alternate') if has_orig_alt and vim.api.nvim_buf_is_valid(alt_buffer) then - vim.fn.setreg("#", alt_buffer) + vim.fn.setreg('#', alt_buffer) end end end @@ -1056,11 +1056,11 @@ end ---@private ---@param bufnr integer M.load_oil_buffer = function(bufnr) - local config = require("oil.config") - local keymap_util = require("oil.keymap_util") - local loading = require("oil.loading") - local util = require("oil.util") - local view = require("oil.view") + local config = require('oil.config') + local keymap_util = require('oil.keymap_util') + local loading = require('oil.loading') + local util = require('oil.util') + local view = require('oil.view') local bufname = vim.api.nvim_buf_get_name(bufnr) local scheme, path = util.parse_url(bufname) if config.adapter_aliases[scheme] then @@ -1076,13 +1076,13 @@ M.load_oil_buffer = function(bufnr) local adapter = assert(config.get_adapter_by_scheme(scheme)) - if vim.endswith(bufname, "/") then + if vim.endswith(bufname, '/') then -- This is a small quality-of-life thing. If the buffer name ends with a `/`, we know it's a -- directory, and can set the filetype early. This is helpful for adapters with a lot of latency -- (e.g. ssh) because it will set up the filetype keybinds at the *beginning* of the loading -- process. - vim.bo[bufnr].filetype = "oil" - vim.bo[bufnr].buftype = "acwrite" + vim.bo[bufnr].filetype = 'oil' + vim.bo[bufnr].buftype = 'acwrite' keymap_util.set_keymaps(config.keymaps, bufnr) end loading.set_loading(bufnr, true) @@ -1109,19 +1109,19 @@ M.load_oil_buffer = function(bufnr) local new_scheme = util.parse_url(new_url) if not new_scheme then loading.set_loading(bufnr, false) - vim.cmd.doautocmd({ args = { "BufReadPre", new_url }, mods = { emsg_silent = true } }) - vim.cmd.doautocmd({ args = { "BufReadPost", new_url }, mods = { emsg_silent = true } }) + vim.cmd.doautocmd({ args = { 'BufReadPre', new_url }, mods = { emsg_silent = true } }) + vim.cmd.doautocmd({ args = { 'BufReadPost', new_url }, mods = { emsg_silent = true } }) return end bufname = new_url end - if vim.endswith(bufname, "/") then - vim.cmd.doautocmd({ args = { "BufReadPre", bufname }, mods = { emsg_silent = true } }) + if vim.endswith(bufname, '/') then + vim.cmd.doautocmd({ args = { 'BufReadPre', bufname }, mods = { emsg_silent = true } }) view.initialize(bufnr) - vim.cmd.doautocmd({ args = { "BufReadPost", bufname }, mods = { emsg_silent = true } }) + vim.cmd.doautocmd({ args = { 'BufReadPost', bufname }, mods = { emsg_silent = true } }) else - vim.bo[bufnr].buftype = "acwrite" + vim.bo[bufnr].buftype = 'acwrite' adapter.read_file(bufnr) end restore_alt_buf() @@ -1132,7 +1132,7 @@ M.load_oil_buffer = function(bufnr) end local function close_preview_window_if_not_in_oil() - local util = require("oil.util") + local util = require('oil.util') local preview_win_id = util.get_preview_win() if not preview_win_id or not vim.w[preview_win_id].oil_entry_id then return @@ -1154,13 +1154,13 @@ local _on_key_ns = 0 ---Initialize oil ---@param opts oil.setupOpts|nil M.setup = function(opts) - local Ringbuf = require("oil.ringbuf") - local config = require("oil.config") + local Ringbuf = require('oil.ringbuf') + local config = require('oil.config') config.setup(opts) set_colors() local callback = function(args) - local util = require("oil.util") + local util = require('oil.util') if args.smods.tab > 0 then vim.cmd.tabnew() end @@ -1170,23 +1170,23 @@ M.setup = function(opts) local i = 1 while i <= #args.fargs do local v = args.fargs[i] - if v == "--float" then + if v == '--float' then float = true table.remove(args.fargs, i) - elseif v == "--trash" then + elseif v == '--trash' then trash = true table.remove(args.fargs, i) - elseif v == "--preview" then + elseif v == '--preview' then -- In the future we may want to support specifying options for the preview window (e.g. -- vertical/horizontal), but if you want that level of control maybe just use the API preview = true table.remove(args.fargs, i) - elseif v == "--progress" then - local mutator = require("oil.mutator") + elseif v == '--progress' then + local mutator = require('oil.mutator') if mutator.is_mutating() then mutator.show_progress() else - vim.notify("No mutation in progress", vim.log.levels.WARN) + vim.notify('No mutation in progress', vim.log.levels.WARN) end return else @@ -1194,7 +1194,7 @@ M.setup = function(opts) end end - if not float and (args.smods.vertical or args.smods.horizontal or args.smods.split ~= "") then + if not float and (args.smods.vertical or args.smods.horizontal or args.smods.split ~= '') then local range = args.count > 0 and { args.count } or nil local cmdargs = { mods = { split = args.smods.split }, range = range } if args.smods.vertical then @@ -1204,13 +1204,13 @@ M.setup = function(opts) end end - local method = float and "open_float" or "open" + local method = float and 'open_float' or 'open' local path = args.fargs[1] local open_opts = {} if trash then local url = M.get_url_for_path(path, false) local _, new_path = util.parse_url(url) - path = "oil-trash://" .. new_path + path = 'oil-trash://' .. new_path end if preview then open_opts.preview = {} @@ -1218,32 +1218,32 @@ M.setup = function(opts) M[method](path, open_opts) end vim.api.nvim_create_user_command( - "Oil", + 'Oil', callback, - { desc = "Open oil file browser on a directory", nargs = "*", complete = "dir", count = true } + { desc = 'Open oil file browser on a directory', nargs = '*', complete = 'dir', count = true } ) - local aug = vim.api.nvim_create_augroup("Oil", {}) + local aug = vim.api.nvim_create_augroup('Oil', {}) if config.default_file_explorer then vim.g.loaded_netrw = 1 vim.g.loaded_netrwPlugin = 1 -- If netrw was already loaded, clear this augroup - if vim.fn.exists("#FileExplorer") then - vim.api.nvim_create_augroup("FileExplorer", { clear = true }) + if vim.fn.exists('#FileExplorer') then + vim.api.nvim_create_augroup('FileExplorer', { clear = true }) end end local patterns = {} local filetype_patterns = {} for scheme in pairs(config.adapters) do - table.insert(patterns, scheme .. "*") - filetype_patterns[scheme .. ".*"] = { "oil", { priority = 10 } } + table.insert(patterns, scheme .. '*') + filetype_patterns[scheme .. '.*'] = { 'oil', { priority = 10 } } end for scheme in pairs(config.adapter_aliases) do - table.insert(patterns, scheme .. "*") - filetype_patterns[scheme .. ".*"] = { "oil", { priority = 10 } } + table.insert(patterns, scheme .. '*') + filetype_patterns[scheme .. '.*'] = { 'oil', { priority = 10 } } end - local scheme_pattern = table.concat(patterns, ",") + local scheme_pattern = table.concat(patterns, ',') -- We need to add these patterns to the filetype matcher so the filetype doesn't get overridden -- by other patterns. See https://github.com/stevearc/oil.nvim/issues/47 vim.filetype.add({ @@ -1256,13 +1256,13 @@ M.setup = function(opts) keybuf:push(char) end, _on_key_ns) end - vim.api.nvim_create_autocmd("ColorScheme", { - desc = "Set default oil highlights", + vim.api.nvim_create_autocmd('ColorScheme', { + desc = 'Set default oil highlights', group = aug, - pattern = "*", + pattern = '*', callback = set_colors, }) - vim.api.nvim_create_autocmd("BufReadCmd", { + vim.api.nvim_create_autocmd('BufReadCmd', { group = aug, pattern = scheme_pattern, nested = true, @@ -1270,7 +1270,7 @@ M.setup = function(opts) M.load_oil_buffer(params.buf) end, }) - vim.api.nvim_create_autocmd("BufWriteCmd", { + vim.api.nvim_create_autocmd('BufWriteCmd', { group = aug, pattern = scheme_pattern, nested = true, @@ -1278,18 +1278,18 @@ M.setup = function(opts) local last_keys = keybuf:as_str() local winid = vim.api.nvim_get_current_win() -- If the user issued a :wq or similar, we should quit after saving - local quit_after_save = vim.endswith(last_keys, ":wq\r") - or vim.endswith(last_keys, ":x\r") - or vim.endswith(last_keys, "ZZ") - local quit_all = vim.endswith(last_keys, ":wqa\r") - or vim.endswith(last_keys, ":wqal\r") - or vim.endswith(last_keys, ":wqall\r") + local quit_after_save = vim.endswith(last_keys, ':wq\r') + or vim.endswith(last_keys, ':x\r') + or vim.endswith(last_keys, 'ZZ') + local quit_all = vim.endswith(last_keys, ':wqa\r') + or vim.endswith(last_keys, ':wqal\r') + or vim.endswith(last_keys, ':wqall\r') local bufname = vim.api.nvim_buf_get_name(params.buf) - if vim.endswith(bufname, "/") then - vim.cmd.doautocmd({ args = { "BufWritePre", params.file }, mods = { silent = true } }) + if vim.endswith(bufname, '/') then + vim.cmd.doautocmd({ args = { 'BufWritePre', params.file }, mods = { silent = true } }) M.save(nil, function(err) if err then - if err ~= "Canceled" then + if err ~= 'Canceled' then vim.notify(err, vim.log.levels.ERROR) end elseif winid == vim.api.nvim_get_current_win() then @@ -1300,46 +1300,46 @@ M.setup = function(opts) end end end) - vim.cmd.doautocmd({ args = { "BufWritePost", params.file }, mods = { silent = true } }) + vim.cmd.doautocmd({ args = { 'BufWritePost', params.file }, mods = { silent = true } }) else local adapter = assert(config.get_adapter_by_scheme(bufname)) adapter.write_file(params.buf) end end, }) - vim.api.nvim_create_autocmd("BufLeave", { - desc = "Save alternate buffer for later", + vim.api.nvim_create_autocmd('BufLeave', { + desc = 'Save alternate buffer for later', group = aug, - pattern = "*", + pattern = '*', callback = function() - local util = require("oil.util") + local util = require('oil.util') if not util.is_oil_bufnr(0) then vim.w.oil_original_buffer = vim.api.nvim_get_current_buf() vim.w.oil_original_view = vim.fn.winsaveview() ---@diagnostic disable-next-line: param-type-mismatch - vim.w.oil_original_alternate = vim.fn.bufnr("#") + vim.w.oil_original_alternate = vim.fn.bufnr('#') end end, }) - vim.api.nvim_create_autocmd("BufEnter", { - desc = "Set/unset oil window options and restore alternate buffer", + vim.api.nvim_create_autocmd('BufEnter', { + desc = 'Set/unset oil window options and restore alternate buffer', group = aug, - pattern = "*", + pattern = '*', callback = function() - local util = require("oil.util") + local util = require('oil.util') local bufname = vim.api.nvim_buf_get_name(0) local scheme = util.parse_url(bufname) local is_oil_buf = scheme and config.adapters[scheme] -- We want to filter out oil buffers that are not directories (i.e. ssh files) - local is_oil_dir_or_unknown = (vim.bo.filetype == "oil" or vim.bo.filetype == "") + local is_oil_dir_or_unknown = (vim.bo.filetype == 'oil' or vim.bo.filetype == '') if is_oil_buf and is_oil_dir_or_unknown then - local view = require("oil.view") + local view = require('oil.view') view.maybe_set_cursor() -- While we are in an oil buffer, set the alternate file to the buffer we were in prior to -- opening oil - local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, "oil_original_buffer") + local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, 'oil_original_buffer') if has_orig and vim.api.nvim_buf_is_valid(orig_buffer) then - vim.fn.setreg("#", orig_buffer) + vim.fn.setreg('#', orig_buffer) end view.set_win_options() vim.w.oil_did_enter = true @@ -1354,39 +1354,39 @@ M.setup = function(opts) end, }) - vim.api.nvim_create_autocmd({ "BufWinEnter", "WinNew", "WinEnter" }, { - desc = "Reset bufhidden when entering a preview buffer", + vim.api.nvim_create_autocmd({ 'BufWinEnter', 'WinNew', 'WinEnter' }, { + desc = 'Reset bufhidden when entering a preview buffer', group = aug, - pattern = "*", + pattern = '*', callback = function() -- If we have entered a "preview" buffer in a non-preview window, reset bufhidden if vim.b.oil_preview_buffer and not vim.wo.previewwindow then - vim.bo.bufhidden = vim.api.nvim_get_option_value("bufhidden", { scope = "global" }) + vim.bo.bufhidden = vim.api.nvim_get_option_value('bufhidden', { scope = 'global' }) vim.b.oil_preview_buffer = nil end end, }) if not config.silence_scp_warning then - vim.api.nvim_create_autocmd("BufNew", { - desc = "Warn about scp:// usage", + vim.api.nvim_create_autocmd('BufNew', { + desc = 'Warn about scp:// usage', group = aug, - pattern = "scp://*", + pattern = 'scp://*', once = true, callback = function() vim.notify( - "If you are trying to browse using Oil, use oil-ssh:// instead of scp://\nSet `silence_scp_warning = true` in oil.setup() to disable this message.\nSee https://github.com/stevearc/oil.nvim/issues/27 for more information.", + 'If you are trying to browse using Oil, use oil-ssh:// instead of scp://\nSet `silence_scp_warning = true` in oil.setup() to disable this message.\nSee https://github.com/stevearc/oil.nvim/issues/27 for more information.', vim.log.levels.WARN ) end, }) end - vim.api.nvim_create_autocmd("WinNew", { - desc = "Restore window options when splitting an oil window", + vim.api.nvim_create_autocmd('WinNew', { + desc = 'Restore window options when splitting an oil window', group = aug, - pattern = "*", + pattern = '*', nested = true, callback = function(params) - local util = require("oil.util") + local util = require('oil.util') if not util.is_oil_bufnr(params.buf) or vim.w.oil_did_enter then return end @@ -1405,7 +1405,7 @@ M.setup = function(opts) end if not parent_win then vim.notify( - "Oil split could not find parent window. Please try to replicate whatever you just did and report a bug on github", + 'Oil split could not find parent window. Please try to replicate whatever you just did and report a bug on github', vim.log.levels.WARN ) return @@ -1420,15 +1420,15 @@ M.setup = function(opts) }) -- mksession doesn't save oil buffers in a useful way. We have to manually load them after a -- session finishes loading. See https://github.com/stevearc/oil.nvim/issues/29 - vim.api.nvim_create_autocmd("SessionLoadPost", { - desc = "Load oil buffers after a session is loaded", + vim.api.nvim_create_autocmd('SessionLoadPost', { + desc = 'Load oil buffers after a session is loaded', group = aug, - pattern = "*", + pattern = '*', callback = function(params) if vim.g.SessionLoad ~= 1 then return end - local util = require("oil.util") + local util = require('oil.util') local scheme = util.parse_url(params.file) if config.adapters[scheme] and vim.api.nvim_buf_line_count(params.buf) == 1 then M.load_oil_buffer(params.buf) @@ -1437,10 +1437,10 @@ M.setup = function(opts) }) if config.default_file_explorer then - vim.api.nvim_create_autocmd("BufAdd", { - desc = "Detect directory buffer and open oil file browser", + vim.api.nvim_create_autocmd('BufAdd', { + desc = 'Detect directory buffer and open oil file browser', group = aug, - pattern = "*", + pattern = '*', nested = true, callback = function(params) maybe_hijack_directory_buffer(params.buf) diff --git a/lua/oil/keymap_util.lua b/lua/oil/keymap_util.lua index 8c58738..8d62c93 100644 --- a/lua/oil/keymap_util.lua +++ b/lua/oil/keymap_util.lua @@ -1,7 +1,7 @@ -local actions = require("oil.actions") -local config = require("oil.config") -local layout = require("oil.layout") -local util = require("oil.util") +local actions = require('oil.actions') +local config = require('oil.config') +local layout = require('oil.layout') +local util = require('oil.util') local M = {} ---@param rhs string|table|fun() @@ -9,14 +9,14 @@ local M = {} ---@return table opts ---@return string|nil mode local function resolve(rhs) - if type(rhs) == "string" and vim.startswith(rhs, "actions.") then - local action_name = vim.split(rhs, ".", { plain = true })[2] + if type(rhs) == 'string' and vim.startswith(rhs, 'actions.') then + local action_name = vim.split(rhs, '.', { plain = true })[2] local action = actions[action_name] if not action then - vim.notify("[oil.nvim] Unknown action name: " .. action_name, vim.log.levels.ERROR) + vim.notify('[oil.nvim] Unknown action name: ' .. action_name, vim.log.levels.ERROR) end return resolve(action) - elseif type(rhs) == "table" then + elseif type(rhs) == 'table' then local opts = vim.deepcopy(rhs) -- We support passing in a `callback` key, or using the 1 index as the rhs of the keymap local callback, parent_opts = resolve(opts.callback or opts[1]) @@ -25,17 +25,17 @@ local function resolve(rhs) if parent_opts.desc and not opts.desc then if opts.opts then opts.desc = - string.format("%s %s", parent_opts.desc, vim.inspect(opts.opts):gsub("%s+", " ")) + string.format('%s %s', parent_opts.desc, vim.inspect(opts.opts):gsub('%s+', ' ')) else opts.desc = parent_opts.desc end end local mode = opts.mode - if type(rhs.callback) == "string" then + if type(rhs.callback) == 'string' then local action_opts, action_mode callback, action_opts, action_mode = resolve(rhs.callback) - opts = vim.tbl_extend("keep", opts, action_opts) + opts = vim.tbl_extend('keep', opts, action_opts) mode = mode or action_mode end @@ -46,7 +46,7 @@ local function resolve(rhs) opts.deprecated = nil opts.parameters = nil - if opts.opts and type(callback) == "function" then + if opts.opts and type(callback) == 'function' then local callback_args = opts.opts opts.opts = nil local orig_callback = callback @@ -68,7 +68,7 @@ M.set_keymaps = function(keymaps, bufnr) for k, v in pairs(keymaps) do local rhs, opts, mode = resolve(v) if rhs then - vim.keymap.set(mode or "", k, rhs, vim.tbl_extend("keep", { buffer = bufnr }, opts)) + vim.keymap.set(mode or '', k, rhs, vim.tbl_extend('keep', { buffer = bufnr }, opts)) end end end @@ -95,9 +95,9 @@ M.show_help = function(keymaps) local all_lhs = lhs_to_all_lhs[k] if all_lhs then local _, opts = resolve(rhs) - local keystr = table.concat(all_lhs, "/") + local keystr = table.concat(all_lhs, '/') max_lhs = math.max(max_lhs, vim.api.nvim_strwidth(keystr)) - table.insert(keymap_entries, { str = keystr, all_lhs = all_lhs, desc = opts.desc or "" }) + table.insert(keymap_entries, { str = keystr, all_lhs = all_lhs, desc = opts.desc or '' }) end end table.sort(keymap_entries, function(a, b) @@ -108,20 +108,20 @@ M.show_help = function(keymaps) local highlights = {} local max_line = 1 for _, entry in ipairs(keymap_entries) do - local line = string.format(" %s %s", util.pad_align(entry.str, max_lhs, "left"), entry.desc) + local line = string.format(' %s %s', util.pad_align(entry.str, max_lhs, 'left'), entry.desc) max_line = math.max(max_line, vim.api.nvim_strwidth(line)) table.insert(lines, line) local start = 1 for _, key in ipairs(entry.all_lhs) do local keywidth = vim.api.nvim_strwidth(key) - table.insert(highlights, { "Special", #lines, start, start + keywidth }) + table.insert(highlights, { 'Special', #lines, start, start + keywidth }) start = start + keywidth + 1 end end local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, lines) - local ns = vim.api.nvim_create_namespace("Oil") + local ns = vim.api.nvim_create_namespace('Oil') for _, hl in ipairs(highlights) do local hl_group, lnum, start_col, end_col = unpack(hl) vim.api.nvim_buf_set_extmark(bufnr, ns, lnum - 1, start_col, { @@ -129,21 +129,21 @@ M.show_help = function(keymaps) hl_group = hl_group, }) end - vim.keymap.set("n", "q", "close", { buffer = bufnr }) - vim.keymap.set("n", "", "close", { buffer = bufnr }) + vim.keymap.set('n', 'q', 'close', { buffer = bufnr }) + vim.keymap.set('n', '', 'close', { buffer = bufnr }) vim.bo[bufnr].modifiable = false - vim.bo[bufnr].bufhidden = "wipe" + vim.bo[bufnr].bufhidden = 'wipe' local editor_width = vim.o.columns local editor_height = layout.get_editor_height() local winid = vim.api.nvim_open_win(bufnr, true, { - relative = "editor", + relative = 'editor', row = math.max(0, (editor_height - #lines) / 2), col = math.max(0, (editor_width - max_line - 1) / 2), width = math.min(editor_width, max_line + 1), height = math.min(editor_height, #lines), zindex = 150, - style = "minimal", + style = 'minimal', border = config.keymaps_help.border, }) local function close() @@ -151,13 +151,13 @@ M.show_help = function(keymaps) vim.api.nvim_win_close(winid, true) end end - vim.api.nvim_create_autocmd("BufLeave", { + vim.api.nvim_create_autocmd('BufLeave', { callback = close, once = true, nested = true, buffer = bufnr, }) - vim.api.nvim_create_autocmd("WinLeave", { + vim.api.nvim_create_autocmd('WinLeave', { callback = close, once = true, nested = true, diff --git a/lua/oil/layout.lua b/lua/oil/layout.lua index 6d4563d..0f32fcd 100644 --- a/lua/oil/layout.lua +++ b/lua/oil/layout.lua @@ -43,7 +43,7 @@ local function calc_list(values, max_value, aggregator, limit) local ret = limit if not max_value or not values then return nil - elseif type(values) == "table" then + elseif type(values) == 'table' then for _, v in ipairs(values) do ret = aggregator(ret, calc_float(v, max_value)) end @@ -106,12 +106,12 @@ end ---@return vim.api.keyset.win_config M.get_fullscreen_win_opts = function() - local config = require("oil.config") + local config = require('oil.config') local total_width = M.get_editor_width() local total_height = M.get_editor_height() local width = total_width - 2 * config.float.padding - if config.float.border ~= "none" then + if config.float.border ~= 'none' then width = width - 2 -- The border consumes 1 col on each side end if config.float.max_width > 0 then @@ -127,7 +127,7 @@ M.get_fullscreen_win_opts = function() local col = math.floor((total_width - width) / 2) - 1 -- adjust for border width local win_opts = { - relative = "editor", + relative = 'editor', width = width, height = height, row = row, @@ -144,8 +144,8 @@ end ---@return oil.WinLayout root_dim New dimensions of the original window ---@return oil.WinLayout new_dim New dimensions of the new window M.split_window = function(winid, direction, gap) - if direction == "auto" then - direction = vim.o.splitright and "right" or "left" + if direction == 'auto' then + direction = vim.o.splitright and 'right' or 'left' end local float_config = vim.api.nvim_win_get_config(winid) @@ -156,14 +156,14 @@ M.split_window = function(winid, direction, gap) col = float_config.col, row = float_config.row, } - if vim.fn.has("nvim-0.10") == 0 then + if vim.fn.has('nvim-0.10') == 0 then -- read https://github.com/neovim/neovim/issues/24430 for more infos. dim_root.col = float_config.col[vim.val_idx] dim_root.row = float_config.row[vim.val_idx] end local dim_new = vim.deepcopy(dim_root) - if direction == "left" or direction == "right" then + if direction == 'left' or direction == 'right' then dim_new.width = math.floor(float_config.width / 2) - math.ceil(gap / 2) dim_root.width = dim_new.width else @@ -171,13 +171,13 @@ M.split_window = function(winid, direction, gap) dim_root.height = dim_new.height end - if direction == "left" then + if direction == 'left' then dim_root.col = dim_root.col + dim_root.width + gap - elseif direction == "right" then + elseif direction == 'right' then dim_new.col = dim_new.col + dim_new.width + gap - elseif direction == "above" then + elseif direction == 'above' then dim_root.row = dim_root.row + dim_root.height + gap - elseif direction == "below" then + elseif direction == 'below' then dim_new.row = dim_new.row + dim_new.height + gap end diff --git a/lua/oil/loading.lua b/lua/oil/loading.lua index 6e575c5..633af6e 100644 --- a/lua/oil/loading.lua +++ b/lua/oil/loading.lua @@ -1,4 +1,4 @@ -local util = require("oil.util") +local util = require('oil.util') local M = {} local timers = {} @@ -12,14 +12,14 @@ M.is_loading = function(bufnr) end local spinners = { - dots = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" }, + dots = { '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' }, } ---@param name_or_frames string|string[] ---@return fun(): string M.get_iter = function(name_or_frames) local frames - if type(name_or_frames) == "string" then + if type(name_or_frames) == 'string' then frames = spinners[name_or_frames] if not frames then error(string.format("Unrecognized spinner: '%s'", name_or_frames)) @@ -35,26 +35,26 @@ M.get_iter = function(name_or_frames) end M.get_bar_iter = function(opts) - opts = vim.tbl_deep_extend("keep", opts or {}, { + opts = vim.tbl_deep_extend('keep', opts or {}, { bar_size = 3, width = 20, }) local i = 0 return function() - local chars = { "[" } + local chars = { '[' } for _ = 1, opts.width - 2 do - table.insert(chars, " ") + table.insert(chars, ' ') end - table.insert(chars, "]") + table.insert(chars, ']') for j = i - opts.bar_size, i do if j > 1 and j < opts.width then - chars[j] = "=" + chars[j] = '=' end end i = (i + 1) % (opts.width + opts.bar_size) - return table.concat(chars, "") + return table.concat(chars, '') end end @@ -75,7 +75,7 @@ M.set_loading = function(bufnr, is_loading) return end local lines = - { util.pad_align("Loading", math.floor(width / 2) - 3, "right"), bar_iter() } + { util.pad_align('Loading', math.floor(width / 2) - 3, 'right'), bar_iter() } util.render_text(bufnr, lines) end) ) diff --git a/lua/oil/log.lua b/lua/oil/log.lua index 28a4f9c..a16394b 100644 --- a/lua/oil/log.lua +++ b/lua/oil/log.lua @@ -11,14 +11,14 @@ Log.level = vim.log.levels.WARN ---@return string Log.get_logfile = function() - local fs = require("oil.fs") + local fs = require('oil.fs') - local ok, stdpath = pcall(vim.fn.stdpath, "log") + local ok, stdpath = pcall(vim.fn.stdpath, 'log') if not ok then - stdpath = vim.fn.stdpath("cache") + stdpath = vim.fn.stdpath('cache') end - assert(type(stdpath) == "string") - return fs.join(stdpath, "oil.log") + assert(type(stdpath) == 'string') + return fs.join(stdpath, 'oil.log') end ---@param level integer @@ -29,19 +29,19 @@ local function format(level, msg, ...) local args = vim.F.pack_len(...) for i = 1, args.n do local v = args[i] - if type(v) == "table" then + if type(v) == 'table' then args[i] = vim.inspect(v) elseif v == nil then - args[i] = "nil" + args[i] = 'nil' end end local ok, text = pcall(string.format, msg, vim.F.unpack_len(args)) -- TODO figure out how to get formatted time inside luv callback -- local timestr = vim.fn.strftime("%Y-%m-%d %H:%M:%S") - local timestr = "" + local timestr = '' if ok then local str_level = levels_reverse[level] - return string.format("%s[%s] %s", timestr, str_level, text) + return string.format('%s[%s] %s', timestr, str_level, text) else return string.format( "%s[ERROR] error formatting log line: '%s' args %s", @@ -67,22 +67,22 @@ local function initialize() local stat = uv.fs_stat(filepath) if stat and stat.size > 10 * 1024 * 1024 then - local backup = filepath .. ".1" + local backup = filepath .. '.1' uv.fs_unlink(backup) uv.fs_rename(filepath, backup) end local parent = vim.fs.dirname(filepath) - require("oil.fs").mkdirp(parent) + require('oil.fs').mkdirp(parent) - local logfile, openerr = io.open(filepath, "a+") + local logfile, openerr = io.open(filepath, 'a+') if not logfile then - local err_msg = string.format("Failed to open oil.nvim log file: %s", openerr) + local err_msg = string.format('Failed to open oil.nvim log file: %s', openerr) vim.notify(err_msg, vim.log.levels.ERROR) else write = function(line) logfile:write(line) - logfile:write("\n") + logfile:write('\n') logfile:flush() end end diff --git a/lua/oil/lsp/helpers.lua b/lua/oil/lsp/helpers.lua index 45264dc..cadeca1 100644 --- a/lua/oil/lsp/helpers.lua +++ b/lua/oil/lsp/helpers.lua @@ -1,7 +1,7 @@ -local config = require("oil.config") -local fs = require("oil.fs") -local util = require("oil.util") -local workspace = require("oil.lsp.workspace") +local config = require('oil.config') +local fs = require('oil.fs') +local util = require('oil.util') +local workspace = require('oil.lsp.workspace') local M = {} @@ -12,7 +12,7 @@ M.will_perform_file_operations = function(actions) local creates = {} local deletes = {} for _, action in ipairs(actions) do - if action.type == "move" then + if action.type == 'move' then local src_scheme, src_path = util.parse_url(action.src_url) assert(src_path) local src_adapter = assert(config.get_adapter_by_scheme(src_scheme)) @@ -20,32 +20,32 @@ M.will_perform_file_operations = function(actions) local dest_adapter = assert(config.get_adapter_by_scheme(dest_scheme)) src_path = fs.posix_to_os_path(src_path) dest_path = fs.posix_to_os_path(assert(dest_path)) - if src_adapter.name == "files" and dest_adapter.name == "files" then + if src_adapter.name == 'files' and dest_adapter.name == 'files' then moves[src_path] = dest_path - elseif src_adapter.name == "files" then + elseif src_adapter.name == 'files' then table.insert(deletes, src_path) - elseif dest_adapter.name == "files" then + elseif dest_adapter.name == 'files' then table.insert(creates, src_path) end - elseif action.type == "create" then + elseif action.type == 'create' then local scheme, path = util.parse_url(action.url) path = fs.posix_to_os_path(assert(path)) local adapter = assert(config.get_adapter_by_scheme(scheme)) - if adapter.name == "files" then + if adapter.name == 'files' then table.insert(creates, path) end - elseif action.type == "delete" then + elseif action.type == 'delete' then local scheme, path = util.parse_url(action.url) path = fs.posix_to_os_path(assert(path)) local adapter = assert(config.get_adapter_by_scheme(scheme)) - if adapter.name == "files" then + if adapter.name == 'files' then table.insert(deletes, path) end - elseif action.type == "copy" then + elseif action.type == 'copy' then local scheme, path = util.parse_url(action.dest_url) path = fs.posix_to_os_path(assert(path)) local adapter = assert(config.get_adapter_by_scheme(scheme)) - if adapter.name == "files" then + if adapter.name == 'files' then table.insert(creates, path) end end @@ -84,7 +84,7 @@ M.will_perform_file_operations = function(actions) accum(workspace.will_rename_files(moves, { timeout_ms = timeout_ms })) if final_err then vim.notify( - string.format("[lsp] file operation error: %s", vim.inspect(final_err)), + string.format('[lsp] file operation error: %s', vim.inspect(final_err)), vim.log.levels.WARN ) end @@ -102,7 +102,7 @@ M.will_perform_file_operations = function(actions) local bufnr = vim.uri_to_bufnr(uri) local was_open = buf_was_modified[bufnr] ~= nil local was_modified = buf_was_modified[bufnr] - local should_save = autosave == true or (autosave == "unmodified" and not was_modified) + local should_save = autosave == true or (autosave == 'unmodified' and not was_modified) -- Autosave changed buffers if they were not modified before if should_save then vim.api.nvim_buf_call(bufnr, function() diff --git a/lua/oil/lsp/workspace.lua b/lua/oil/lsp/workspace.lua index 8e48276..a0e26bb 100644 --- a/lua/oil/lsp/workspace.lua +++ b/lua/oil/lsp/workspace.lua @@ -1,13 +1,13 @@ -local fs = require("oil.fs") -local ms = require("vim.lsp.protocol").Methods -if vim.fn.has("nvim-0.10") == 0 then +local fs = require('oil.fs') +local ms = require('vim.lsp.protocol').Methods +if vim.fn.has('nvim-0.10') == 0 then ms = { - workspace_willCreateFiles = "workspace/willCreateFiles", - workspace_didCreateFiles = "workspace/didCreateFiles", - workspace_willDeleteFiles = "workspace/willDeleteFiles", - workspace_didDeleteFiles = "workspace/didDeleteFiles", - workspace_willRenameFiles = "workspace/willRenameFiles", - workspace_didRenameFiles = "workspace/didRenameFiles", + workspace_willCreateFiles = 'workspace/willCreateFiles', + workspace_didCreateFiles = 'workspace/didCreateFiles', + workspace_willDeleteFiles = 'workspace/willDeleteFiles', + workspace_didDeleteFiles = 'workspace/didDeleteFiles', + workspace_willRenameFiles = 'workspace/willRenameFiles', + workspace_didRenameFiles = 'workspace/didRenameFiles', } end @@ -16,7 +16,7 @@ local M = {} ---@param method string ---@return vim.lsp.Client[] local function get_clients(method) - if vim.fn.has("nvim-0.10") == 1 then + if vim.fn.has('nvim-0.10') == 1 then return vim.lsp.get_clients({ method = method }) else ---@diagnostic disable-next-line: deprecated @@ -32,7 +32,7 @@ end ---@return boolean local function match_glob(glob, path) -- nvim-0.10 will have vim.glob.to_lpeg, so this will be a LPeg pattern - if type(glob) ~= "string" then + if type(glob) ~= 'string' then return glob:match(path) ~= nil end @@ -59,7 +59,7 @@ local function get_matching_paths(client, filters, paths) local match_fns = {} for _, filter in ipairs(filters) do - if filter.scheme == nil or filter.scheme == "file" then + if filter.scheme == nil or filter.scheme == 'file' then local pattern = filter.pattern local glob = pattern.glob local ignore_case = pattern.options and pattern.options.ignoreCase @@ -69,32 +69,32 @@ local function get_matching_paths(client, filters, paths) -- Some language servers use forward slashes as path separators on Windows (LuaLS) -- We no longer need this after 0.12: https://github.com/neovim/neovim/commit/322a6d305d088420b23071c227af07b7c1beb41a - if vim.fn.has("nvim-0.12") == 0 and fs.is_windows then - glob = glob:gsub("/", "\\") + if vim.fn.has('nvim-0.12') == 0 and fs.is_windows then + glob = glob:gsub('/', '\\') end ---@type string|vim.lpeg.Pattern local glob_to_match = glob if vim.glob and vim.glob.to_lpeg then - glob = glob:gsub("{(.-)}", function(s) - local patterns = vim.split(s, ",") + glob = glob:gsub('{(.-)}', function(s) + local patterns = vim.split(s, ',') local filtered = {} for _, pat in ipairs(patterns) do - if pat ~= "" then + if pat ~= '' then table.insert(filtered, pat) end end if #filtered == 0 then - return "" + return '' end -- HACK around https://github.com/neovim/neovim/issues/28931 -- find alternations and sort them by length to try to match the longest first - if vim.fn.has("nvim-0.11") == 0 then + if vim.fn.has('nvim-0.11') == 0 then table.sort(filtered, function(a, b) return a:len() > b:len() end) end - return "{" .. table.concat(filtered, ",") .. "}" + return '{' .. table.concat(filtered, ',') .. '}' end) glob_to_match = vim.glob.to_lpeg(glob) @@ -102,7 +102,7 @@ local function get_matching_paths(client, filters, paths) local matches = pattern.matches table.insert(match_fns, function(path) local is_dir = vim.fn.isdirectory(path) == 1 - if matches and ((matches == "file" and is_dir) or (matches == "folder" and not is_dir)) then + if matches and ((matches == 'file' and is_dir) or (matches == 'folder' and not is_dir)) then return false end @@ -163,10 +163,10 @@ local function will_file_operation(method, capability_name, files, options) for _, client in ipairs(clients) do local filters = vim.tbl_get( client.server_capabilities, - "workspace", - "fileOperations", + 'workspace', + 'fileOperations', capability_name, - "filters" + 'filters' ) local matching_files = get_matching_paths(client, filters, files) if matching_files then @@ -178,7 +178,7 @@ local function will_file_operation(method, capability_name, files, options) end, matching_files), } local result, err - if vim.fn.has("nvim-0.11") == 1 then + if vim.fn.has('nvim-0.11') == 1 then result, err = client:request_sync(method, params, options.timeout_ms or 1000, 0) else ---@diagnostic disable-next-line: param-type-mismatch @@ -205,10 +205,10 @@ local function did_file_operation(method, capability_name, files) for _, client in ipairs(clients) do local filters = vim.tbl_get( client.server_capabilities, - "workspace", - "fileOperations", + 'workspace', + 'fileOperations', capability_name, - "filters" + 'filters' ) local matching_files = get_matching_paths(client, filters, files) if matching_files then @@ -219,7 +219,7 @@ local function did_file_operation(method, capability_name, files) } end, matching_files), } - if vim.fn.has("nvim-0.11") == 1 then + if vim.fn.has('nvim-0.11') == 1 then client:notify(method, params) else ---@diagnostic disable-next-line: param-type-mismatch @@ -239,13 +239,13 @@ end ---@return nil|{edit: lsp.WorkspaceEdit, offset_encoding: string}[] ---@return nil|string|lsp.ResponseError err function M.will_create_files(files, options) - return will_file_operation(ms.workspace_willCreateFiles, "willCreate", files, options) + return will_file_operation(ms.workspace_willCreateFiles, 'willCreate', files, options) end --- Notify the server that files were created from within the client. ---@param files string[] The files and folders that will be created function M.did_create_files(files) - did_file_operation(ms.workspace_didCreateFiles, "didCreate", files) + did_file_operation(ms.workspace_didCreateFiles, 'didCreate', files) end --- Notify the server that the client is about to delete files. @@ -258,13 +258,13 @@ end ---@return nil|{edit: lsp.WorkspaceEdit, offset_encoding: string}[] ---@return nil|string|lsp.ResponseError err function M.will_delete_files(files, options) - return will_file_operation(ms.workspace_willDeleteFiles, "willDelete", files, options) + return will_file_operation(ms.workspace_willDeleteFiles, 'willDelete', files, options) end --- Notify the server that files were deleted from within the client. ---@param files string[] The files and folders that were deleted function M.did_delete_files(files) - did_file_operation(ms.workspace_didDeleteFiles, "didDelete", files) + did_file_operation(ms.workspace_didDeleteFiles, 'didDelete', files) end --- Notify the server that the client is about to rename files. @@ -284,10 +284,10 @@ function M.will_rename_files(files, options) for _, client in ipairs(clients) do local filters = vim.tbl_get( client.server_capabilities, - "workspace", - "fileOperations", - "willRename", - "filters" + 'workspace', + 'fileOperations', + 'willRename', + 'filters' ) local matching_files = get_matching_paths(client, filters, vim.tbl_keys(files)) if matching_files then @@ -300,7 +300,7 @@ function M.will_rename_files(files, options) end, matching_files), } local result, err - if vim.fn.has("nvim-0.11") == 1 then + if vim.fn.has('nvim-0.11') == 1 then result, err = client:request_sync(ms.workspace_willRenameFiles, params, options.timeout_ms or 1000, 0) else @@ -327,7 +327,7 @@ function M.did_rename_files(files) local clients = get_clients(ms.workspace_didRenameFiles) for _, client in ipairs(clients) do local filters = - vim.tbl_get(client.server_capabilities, "workspace", "fileOperations", "didRename", "filters") + vim.tbl_get(client.server_capabilities, 'workspace', 'fileOperations', 'didRename', 'filters') local matching_files = get_matching_paths(client, filters, vim.tbl_keys(files)) if matching_files then local params = { @@ -338,7 +338,7 @@ function M.did_rename_files(files) } end, matching_files), } - if vim.fn.has("nvim-0.11") == 1 then + if vim.fn.has('nvim-0.11') == 1 then client:notify(ms.workspace_didRenameFiles, params) else ---@diagnostic disable-next-line: param-type-mismatch diff --git a/lua/oil/mutator/confirmation.lua b/lua/oil/mutator/confirmation.lua index 8bc8020..0aff7a7 100644 --- a/lua/oil/mutator/confirmation.lua +++ b/lua/oil/mutator/confirmation.lua @@ -1,7 +1,7 @@ -local columns = require("oil.columns") -local config = require("oil.config") -local layout = require("oil.layout") -local util = require("oil.util") +local columns = require('oil.columns') +local config = require('oil.config') +local layout = require('oil.layout') +local util = require('oil.util') local M = {} ---@param actions oil.Action[] @@ -12,17 +12,17 @@ local function is_simple_edit(actions) local num_move = 0 for _, action in ipairs(actions) do -- If there are any deletes, it is not a simple edit - if action.type == "delete" then + if action.type == 'delete' then return false - elseif action.type == "create" then + elseif action.type == 'create' then num_create = num_create + 1 - elseif action.type == "copy" then + elseif action.type == 'copy' then num_copy = num_copy + 1 -- Cross-adapter copies are not simple if util.parse_url(action.src_url) ~= util.parse_url(action.dest_url) then return false end - elseif action.type == "move" then + elseif action.type == 'move' then num_move = num_move + 1 -- Cross-adapter moves are not simple if util.parse_url(action.src_url) ~= util.parse_url(action.dest_url) then @@ -46,10 +46,10 @@ end ---@param lines string[] local function render_lines(winid, bufnr, lines) util.render_text(bufnr, lines, { - v_align = "top", - h_align = "left", + v_align = 'top', + h_align = 'left', winid = winid, - actions = { "[Y]es", "[N]o" }, + actions = { '[Y]es', '[N]o' }, }) end @@ -70,48 +70,48 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb) -- Create the buffer local bufnr = vim.api.nvim_create_buf(false, true) - vim.bo[bufnr].bufhidden = "wipe" + vim.bo[bufnr].bufhidden = 'wipe' local lines = {} local max_line_width = 0 for _, action in ipairs(actions) do local adapter = util.get_adapter_for_action(action) local line - if action.type == "change" then + if action.type == 'change' then ---@cast action oil.ChangeAction line = columns.render_change_action(adapter, action) else line = adapter.render_action(action) end -- We can't handle lines with newlines in them - line = line:gsub("\n", "") + line = line:gsub('\n', '') table.insert(lines, line) local line_width = vim.api.nvim_strwidth(line) if line_width > max_line_width then max_line_width = line_width end end - table.insert(lines, "") + table.insert(lines, '') -- Create the floating window local width, height = layout.calculate_dims(max_line_width, #lines + 1, config.confirmation) local ok, winid = pcall(vim.api.nvim_open_win, bufnr, true, { - relative = "editor", + relative = 'editor', width = width, height = height, row = math.floor((layout.get_editor_height() - height) / 2), col = math.floor((layout.get_editor_width() - width) / 2), zindex = 152, -- render on top of the floating window title - style = "minimal", + style = 'minimal', border = config.confirmation.border, }) if not ok then - vim.notify(string.format("Error showing oil preview window: %s", winid), vim.log.levels.ERROR) + vim.notify(string.format('Error showing oil preview window: %s', winid), vim.log.levels.ERROR) cb(false) end - vim.bo[bufnr].filetype = "oil_preview" - vim.bo[bufnr].syntax = "oil_preview" + vim.bo[bufnr].filetype = 'oil_preview' + vim.bo[bufnr].syntax = 'oil_preview' for k, v in pairs(config.confirmation.win_options) do - vim.api.nvim_set_option_value(k, v, { scope = "local", win = winid }) + vim.api.nvim_set_option_value(k, v, { scope = 'local', win = winid }) end render_lines(winid, bufnr, lines) @@ -137,7 +137,7 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb) end cancel = make_callback(false) confirm = make_callback(true) - vim.api.nvim_create_autocmd("BufLeave", { + vim.api.nvim_create_autocmd('BufLeave', { callback = function() cancel() end, @@ -145,7 +145,7 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb) nested = true, buffer = bufnr, }) - vim.api.nvim_create_autocmd("WinLeave", { + vim.api.nvim_create_autocmd('WinLeave', { callback = function() cancel() end, @@ -154,12 +154,12 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb) }) table.insert( autocmds, - vim.api.nvim_create_autocmd("VimResized", { + vim.api.nvim_create_autocmd('VimResized', { callback = function() if vim.api.nvim_win_is_valid(winid) then width, height = layout.calculate_dims(max_line_width, #lines, config.confirmation) vim.api.nvim_win_set_config(winid, { - relative = "editor", + relative = 'editor', width = width, height = height, row = math.floor((layout.get_editor_height() - height) / 2), @@ -173,17 +173,17 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb) ) -- We used to use [C]ancel to cancel, so preserve the old keymap - local cancel_keys = { "n", "N", "c", "C", "q", "", "" } + local cancel_keys = { 'n', 'N', 'c', 'C', 'q', '', '' } for _, cancel_key in ipairs(cancel_keys) do - vim.keymap.set("n", cancel_key, function() + vim.keymap.set('n', cancel_key, function() cancel() end, { buffer = bufnr, nowait = true }) end -- We used to use [O]k to confirm, so preserve the old keymap - local confirm_keys = { "y", "Y", "o", "O" } + local confirm_keys = { 'y', 'Y', 'o', 'O' } for _, confirm_key in ipairs(confirm_keys) do - vim.keymap.set("n", confirm_key, function() + vim.keymap.set('n', confirm_key, function() confirm() end, { buffer = bufnr, nowait = true }) end diff --git a/lua/oil/mutator/init.lua b/lua/oil/mutator/init.lua index f55957d..8e03340 100644 --- a/lua/oil/mutator/init.lua +++ b/lua/oil/mutator/init.lua @@ -1,16 +1,16 @@ -local Progress = require("oil.mutator.progress") -local Trie = require("oil.mutator.trie") -local cache = require("oil.cache") -local columns = require("oil.columns") -local config = require("oil.config") -local confirmation = require("oil.mutator.confirmation") -local constants = require("oil.constants") -local fs = require("oil.fs") -local lsp_helpers = require("oil.lsp.helpers") -local oil = require("oil") -local parser = require("oil.mutator.parser") -local util = require("oil.util") -local view = require("oil.view") +local Progress = require('oil.mutator.progress') +local Trie = require('oil.mutator.trie') +local cache = require('oil.cache') +local columns = require('oil.columns') +local config = require('oil.config') +local confirmation = require('oil.mutator.confirmation') +local constants = require('oil.constants') +local fs = require('oil.fs') +local lsp_helpers = require('oil.lsp.helpers') +local oil = require('oil') +local parser = require('oil.mutator.parser') +local util = require('oil.util') +local view = require('oil.view') local M = {} local FIELD_NAME = constants.FIELD_NAME @@ -73,7 +73,7 @@ M.create_actions_from_diffs = function(all_diffs) local function add_action(action) local adapter = assert(config.get_adapter_by_scheme(action.dest_url or action.url)) if not adapter.filter_action or adapter.filter_action(action) then - if action.type == "create" then + if action.type == 'create' then if seen_creates[action.url] then return else @@ -87,11 +87,11 @@ M.create_actions_from_diffs = function(all_diffs) for bufnr, diffs in pairs(all_diffs) do local adapter = util.get_adapter(bufnr, true) if not adapter then - error("Missing adapter") + error('Missing adapter') end local parent_url = vim.api.nvim_buf_get_name(bufnr) for _, diff in ipairs(diffs) do - if diff.type == "new" then + if diff.type == 'new' then if diff.id then local by_id = diff_by_id[diff.id] ---HACK: set the destination on this diff for use later @@ -100,28 +100,28 @@ M.create_actions_from_diffs = function(all_diffs) table.insert(by_id, diff) else -- Parse nested files like foo/bar/baz - local path_sep = fs.is_windows and "[/\\]" or "/" + local path_sep = fs.is_windows and '[/\\]' or '/' local pieces = vim.split(diff.name, path_sep) - local url = parent_url:gsub("/$", "") + local url = parent_url:gsub('/$', '') for i, v in ipairs(pieces) do local is_last = i == #pieces - local entry_type = is_last and diff.entry_type or "directory" - local alternation = v:match("{([^}]+)}") + local entry_type = is_last and diff.entry_type or 'directory' + local alternation = v:match('{([^}]+)}') if is_last and alternation then -- Parse alternations like foo.{js,test.js} - for _, alt in ipairs(vim.split(alternation, ",")) do - local alt_url = url .. "/" .. v:gsub("{[^}]+}", alt) + for _, alt in ipairs(vim.split(alternation, ',')) do + local alt_url = url .. '/' .. v:gsub('{[^}]+}', alt) add_action({ - type = "create", + type = 'create', url = alt_url, entry_type = entry_type, link = diff.link, }) end else - url = url .. "/" .. v + url = url .. '/' .. v add_action({ - type = "create", + type = 'create', url = url, entry_type = entry_type, link = diff.link, @@ -129,9 +129,9 @@ M.create_actions_from_diffs = function(all_diffs) end end end - elseif diff.type == "change" then + elseif diff.type == 'change' then add_action({ - type = "change", + type = 'change', url = parent_url .. diff.name, entry_type = diff.entry_type, column = diff.column, @@ -151,7 +151,7 @@ M.create_actions_from_diffs = function(all_diffs) for id, diffs in pairs(diff_by_id) do local entry = cache.get_entry_by_id(id) if not entry then - error(string.format("Could not find entry %d", id)) + error(string.format('Could not find entry %d', id)) end ---HACK: access the has_delete field on the list-like table of diffs ---@diagnostic disable-next-line: undefined-field @@ -161,7 +161,7 @@ M.create_actions_from_diffs = function(all_diffs) -- MOVE (+ optional copies) when has both creates and delete for i, diff in ipairs(diffs) do add_action({ - type = i == #diffs and "move" or "copy", + type = i == #diffs and 'move' or 'copy', entry_type = entry[FIELD_TYPE], ---HACK: access the dest field we set above ---@diagnostic disable-next-line: undefined-field @@ -172,7 +172,7 @@ M.create_actions_from_diffs = function(all_diffs) else -- DELETE when no create add_action({ - type = "delete", + type = 'delete', entry_type = entry[FIELD_TYPE], url = cache.get_parent_url(id) .. entry[FIELD_NAME], }) @@ -181,7 +181,7 @@ M.create_actions_from_diffs = function(all_diffs) -- COPY when create but no delete for _, diff in ipairs(diffs) do add_action({ - type = "copy", + type = 'copy', entry_type = entry[FIELD_TYPE], src_url = cache.get_parent_url(id) .. entry[FIELD_NAME], ---HACK: access the dest field we set above @@ -201,9 +201,9 @@ M.enforce_action_order = function(actions) local src_trie = Trie.new() local dest_trie = Trie.new() for _, action in ipairs(actions) do - if action.type == "delete" or action.type == "change" then + if action.type == 'delete' or action.type == 'change' then src_trie:insert_action(action.url, action) - elseif action.type == "create" then + elseif action.type == 'create' then dest_trie:insert_action(action.url, action) else dest_trie:insert_action(action.dest_url, action) @@ -223,18 +223,18 @@ M.enforce_action_order = function(actions) ---@param action oil.Action local function get_deps(action) local ret = {} - if action.type == "delete" then + if action.type == 'delete' then src_trie:accum_children_of(action.url, ret) - elseif action.type == "create" then + elseif action.type == 'create' then -- Finish operating on parents first -- e.g. NEW /a BEFORE NEW /a/b dest_trie:accum_first_parents_of(action.url, ret) -- Process remove path before creating new path -- e.g. DELETE /a BEFORE NEW /a src_trie:accum_actions_at(action.url, ret, function(a) - return a.type == "move" or a.type == "delete" + return a.type == 'move' or a.type == 'delete' end) - elseif action.type == "change" then + elseif action.type == 'change' then -- Finish operating on parents first -- e.g. NEW /a BEFORE CHANGE /a/b dest_trie:accum_first_parents_of(action.url, ret) @@ -244,9 +244,9 @@ M.enforce_action_order = function(actions) -- Finish copy from operations first -- e.g. COPY /a -> /b BEFORE CHANGE /a src_trie:accum_actions_at(action.url, ret, function(entry) - return entry.type == "copy" + return entry.type == 'copy' end) - elseif action.type == "move" then + elseif action.type == 'move' then -- Finish operating on parents first -- e.g. NEW /a BEFORE MOVE /z -> /a/b dest_trie:accum_first_parents_of(action.dest_url, ret) @@ -260,9 +260,9 @@ M.enforce_action_order = function(actions) -- Process remove path before moving to new path -- e.g. MOVE /a -> /b BEFORE MOVE /c -> /a src_trie:accum_actions_at(action.dest_url, ret, function(a) - return a.type == "move" or a.type == "delete" + return a.type == 'move' or a.type == 'delete' end) - elseif action.type == "copy" then + elseif action.type == 'copy' then -- Finish operating on parents first -- e.g. NEW /a BEFORE COPY /z -> /a/b dest_trie:accum_first_parents_of(action.dest_url, ret) @@ -272,7 +272,7 @@ M.enforce_action_order = function(actions) -- Process remove path before copying to new path -- e.g. MOVE /a -> /b BEFORE COPY /c -> /a src_trie:accum_actions_at(action.dest_url, ret, function(a) - return a.type == "move" or a.type == "delete" + return a.type == 'move' or a.type == 'delete' end) end return ret @@ -312,24 +312,24 @@ M.enforce_action_order = function(actions) if selected then to_remove = selected else - if loop_action and loop_action.type == "move" then + if loop_action and loop_action.type == 'move' then -- If this is moving a parent into itself, that's an error if vim.startswith(loop_action.dest_url, loop_action.src_url) then - error("Detected cycle in desired paths") + error('Detected cycle in desired paths') end -- We've detected a move cycle (e.g. MOVE /a -> /b + MOVE /b -> /a) -- Split one of the moves and retry local intermediate_url = - string.format("%s__oil_tmp_%05d", loop_action.src_url, math.random(999999)) + string.format('%s__oil_tmp_%05d', loop_action.src_url, math.random(999999)) local move_1 = { - type = "move", + type = 'move', entry_type = loop_action.entry_type, src_url = loop_action.src_url, dest_url = intermediate_url, } local move_2 = { - type = "move", + type = 'move', entry_type = loop_action.entry_type, src_url = intermediate_url, dest_url = loop_action.dest_url, @@ -340,16 +340,16 @@ M.enforce_action_order = function(actions) dest_trie:insert_action(move_1.dest_url, move_1) src_trie:insert_action(move_1.src_url, move_1) else - error("Detected cycle in desired paths") + error('Detected cycle in desired paths') end end if selected then - if selected.type == "move" or selected.type == "copy" then - if vim.startswith(selected.dest_url, selected.src_url .. "/") then + if selected.type == 'move' or selected.type == 'copy' then + if vim.startswith(selected.dest_url, selected.src_url .. '/') then error( string.format( - "Cannot move or copy parent into itself: %s -> %s", + 'Cannot move or copy parent into itself: %s -> %s', selected.src_url, selected.dest_url ) @@ -360,9 +360,9 @@ M.enforce_action_order = function(actions) end if to_remove then - if to_remove.type == "delete" or to_remove.type == "change" then + if to_remove.type == 'delete' or to_remove.type == 'change' then src_trie:remove_action(to_remove.url, to_remove) - elseif to_remove.type == "create" then + elseif to_remove.type == 'create' then dest_trie:remove_action(to_remove.url, to_remove) else dest_trie:remove_action(to_remove.dest_url, to_remove) @@ -387,8 +387,8 @@ local progress ---@param cb fun(err: nil|string) M.process_actions = function(actions, cb) vim.api.nvim_exec_autocmds( - "User", - { pattern = "OilActionsPre", modeline = false, data = { actions = actions } } + 'User', + { pattern = 'OilActionsPre', modeline = false, data = { actions = actions } } ) local did_complete = nil @@ -398,14 +398,14 @@ M.process_actions = function(actions, cb) -- Convert some cross-adapter moves to a copy + delete for _, action in ipairs(actions) do - if action.type == "move" then + if action.type == 'move' then local _, cross_action = util.get_adapter_for_action(action) -- Only do the conversion if the cross-adapter support is "copy" - if cross_action == "copy" then + if cross_action == 'copy' then ---@diagnostic disable-next-line: assign-type-mismatch - action.type = "copy" + action.type = 'copy' table.insert(actions, { - type = "delete", + type = 'delete', url = action.src_url, entry_type = action.entry_type, }) @@ -421,8 +421,8 @@ M.process_actions = function(actions, cb) progress:close() progress = nil vim.api.nvim_exec_autocmds( - "User", - { pattern = "OilActionsPost", modeline = false, data = { err = err, actions = actions } } + 'User', + { pattern = 'OilActionsPost', modeline = false, data = { err = err, actions = actions } } ) cb(err) end @@ -435,7 +435,7 @@ M.process_actions = function(actions, cb) -- TODO some actions are actually cancelable. -- We should stop them instead of stopping after the current action cancel = function() - finish("Canceled") + finish('Canceled') end, }) end @@ -472,7 +472,7 @@ M.process_actions = function(actions, cb) next_action() end end) - if action.type == "change" then + if action.type == 'change' then ---@cast action oil.ChangeAction columns.perform_change_action(adapter, action, callback) else @@ -502,7 +502,7 @@ M.try_write_changes = function(confirm, cb) cb = function(_err) end end if mutation_in_progress then - cb("Cannot perform mutation when already in progress") + cb('Cannot perform mutation when already in progress') return end local current_buf = vim.api.nvim_get_current_buf() @@ -537,7 +537,7 @@ M.try_write_changes = function(confirm, cb) mutation_in_progress = false end - local ns = vim.api.nvim_create_namespace("Oil") + local ns = vim.api.nvim_create_namespace('Oil') vim.diagnostic.reset(ns) if not vim.tbl_isempty(all_errors) then for bufnr, errors in pairs(all_errors) do @@ -564,7 +564,7 @@ M.try_write_changes = function(confirm, cb) end) end unlock() - cb("Error parsing oil buffers") + cb('Error parsing oil buffers') return end @@ -572,7 +572,7 @@ M.try_write_changes = function(confirm, cb) confirmation.show(actions, confirm, function(proceed) if not proceed then unlock() - cb("Canceled") + cb('Canceled') return end @@ -581,7 +581,7 @@ M.try_write_changes = function(confirm, cb) vim.schedule_wrap(function(err) view.unlock_buffers() if err then - err = string.format("[oil] Error applying actions: %s", err) + err = string.format('[oil] Error applying actions: %s', err) view.rerender_all_oil_buffers(nil, function() cb(err) end) @@ -591,13 +591,13 @@ M.try_write_changes = function(confirm, cb) -- get the entry under the cursor and make sure the cursor stays on it view.set_last_cursor( vim.api.nvim_buf_get_name(0), - vim.split(current_entry.parsed_name or current_entry.name, "/")[1] + vim.split(current_entry.parsed_name or current_entry.name, '/')[1] ) end view.rerender_all_oil_buffers(nil, function(render_err) vim.api.nvim_exec_autocmds( - "User", - { pattern = "OilMutationComplete", modeline = false } + 'User', + { pattern = 'OilMutationComplete', modeline = false } ) cb(render_err) end) diff --git a/lua/oil/mutator/parser.lua b/lua/oil/mutator/parser.lua index e45a629..45f7239 100644 --- a/lua/oil/mutator/parser.lua +++ b/lua/oil/mutator/parser.lua @@ -1,10 +1,10 @@ -local cache = require("oil.cache") -local columns = require("oil.columns") -local config = require("oil.config") -local constants = require("oil.constants") -local fs = require("oil.fs") -local util = require("oil.util") -local view = require("oil.view") +local cache = require('oil.cache') +local columns = require('oil.columns') +local config = require('oil.config') +local constants = require('oil.constants') +local fs = require('oil.fs') +local util = require('oil.util') +local view = require('oil.view') local M = {} local FIELD_ID = constants.FIELD_ID @@ -37,7 +37,7 @@ local FIELD_META = constants.FIELD_META ---@return string ---@return boolean local function parsedir(name) - local isdir = vim.endswith(name, "/") or (fs.is_windows and vim.endswith(name, "\\")) + local isdir = vim.endswith(name, '/') or (fs.is_windows and vim.endswith(name, '\\')) if isdir then name = name:sub(1, name:len() - 1) end @@ -52,8 +52,8 @@ local function compare_link_target(meta, parsed_entry) return false end -- Make sure we trim off any trailing path slashes from both sources - local meta_name = meta.link:gsub("[/\\]$", "") - local parsed_name = parsed_entry.link_target:gsub("[/\\]$", "") + local meta_name = meta.link:gsub('[/\\]$', '') + local parsed_name = parsed_entry.link_target:gsub('[/\\]$', '') return meta_name == parsed_name end @@ -72,9 +72,9 @@ M.parse_line = function(adapter, line, column_defs) local ret = {} local ranges = {} local start = 1 - local value, rem = line:match("^/(%d+) (.+)$") + local value, rem = line:match('^/(%d+) (.+)$') if not value then - return nil, "Malformed ID at start of line" + return nil, 'Malformed ID at start of line' end ranges.id = { start, value:len() + 1 } start = ranges.id[2] + 1 @@ -97,7 +97,7 @@ M.parse_line = function(adapter, line, column_defs) local start_len = string.len(rem) value, rem = columns.parse_col(adapter, assert(rem), def) if not rem then - return nil, string.format("Parsing %s failed", name) + return nil, string.format('Parsing %s failed', name) end ret[name] = value range[2] = range[1] + start_len - string.len(rem) - 1 @@ -108,10 +108,10 @@ M.parse_line = function(adapter, line, column_defs) if name then local isdir name, isdir = parsedir(vim.trim(name)) - if name ~= "" then + if name ~= '' then ret.name = name end - ret._type = isdir and "directory" or "file" + ret._type = isdir and 'directory' or 'file' end local entry = cache.get_entry_by_id(ret.id) ranges.name = { start, start + string.len(rem) - 1 } @@ -122,20 +122,20 @@ M.parse_line = function(adapter, line, column_defs) -- Parse the symlink syntax local meta = entry[FIELD_META] local entry_type = entry[FIELD_TYPE] - if entry_type == "link" and meta and meta.link then - local name_pieces = vim.split(ret.name, " -> ", { plain = true }) + if entry_type == 'link' and meta and meta.link then + local name_pieces = vim.split(ret.name, ' -> ', { plain = true }) if #name_pieces ~= 2 then - ret.name = "" + ret.name = '' return { data = ret, ranges = ranges } end ranges.name = { start, start + string.len(name_pieces[1]) - 1 } ret.name = parsedir(vim.trim(name_pieces[1])) ret.link_target = name_pieces[2] - ret._type = "link" + ret._type = 'link' end -- Try to keep the same file type - if entry_type ~= "directory" and entry_type ~= "file" and ret._type ~= "directory" then + if entry_type ~= 'directory' and entry_type ~= 'file' and ret._type ~= 'directory' then ret._type = entry[FIELD_TYPE] end @@ -187,7 +187,7 @@ M.parse = function(bufnr) name = name:lower() end if seen_names[name] then - table.insert(errors, { message = "Duplicate filename", lnum = i - 1, end_lnum = i, col = 0 }) + table.insert(errors, { message = 'Duplicate filename', lnum = i - 1, end_lnum = i, col = 0 }) else seen_names[name] = true end @@ -197,7 +197,7 @@ M.parse = function(bufnr) -- hack to be compatible with Lua 5.1 -- use return instead of goto (function() - if line:match("^/%d+") then + if line:match('^/%d+') then -- Parse the line for an existing entry local result, err = M.parse_line(adapter, line, column_defs) if not result or err then @@ -217,11 +217,11 @@ M.parse = function(bufnr) local err_message if not parsed_entry.name then - err_message = "No filename found" + err_message = 'No filename found' elseif not entry then - err_message = "Could not find existing entry (was the ID changed?)" - elseif parsed_entry.name:match("/") or parsed_entry.name:match(fs.sep) then - err_message = "Filename cannot contain path separator" + err_message = 'Could not find existing entry (was the ID changed?)' + elseif parsed_entry.name:match('/') or parsed_entry.name:match(fs.sep) then + err_message = 'Filename cannot contain path separator' end if err_message then table.insert(errors, { @@ -237,16 +237,16 @@ M.parse = function(bufnr) check_dupe(parsed_entry.name, i) local meta = entry[FIELD_META] if original_entries[parsed_entry.name] == parsed_entry.id then - if entry[FIELD_TYPE] == "link" and not compare_link_target(meta, parsed_entry) then + if entry[FIELD_TYPE] == 'link' and not compare_link_target(meta, parsed_entry) then table.insert(diffs, { - type = "new", + type = 'new', name = parsed_entry.name, - entry_type = "link", + entry_type = 'link', link = parsed_entry.link_target, }) elseif entry[FIELD_TYPE] ~= parsed_entry._type then table.insert(diffs, { - type = "new", + type = 'new', name = parsed_entry.name, entry_type = parsed_entry._type, }) @@ -255,7 +255,7 @@ M.parse = function(bufnr) end else table.insert(diffs, { - type = "new", + type = 'new', name = parsed_entry.name, entry_type = parsed_entry._type, id = parsed_entry.id, @@ -267,7 +267,7 @@ M.parse = function(bufnr) local col_name = util.split_config(col_def) if columns.compare(adapter, col_name, entry, parsed_entry[col_name]) then table.insert(diffs, { - type = "change", + type = 'change', name = parsed_entry.name, entry_type = entry[FIELD_TYPE], column = col_name, @@ -278,7 +278,7 @@ M.parse = function(bufnr) else -- Parse a new entry local name, isdir = parsedir(vim.trim(line)) - if vim.startswith(name, "/") then + if vim.startswith(name, '/') then table.insert(errors, { message = "Paths cannot start with '/'", lnum = i - 1, @@ -287,17 +287,17 @@ M.parse = function(bufnr) }) return end - if name ~= "" then - local link_pieces = vim.split(name, " -> ", { plain = true }) - local entry_type = isdir and "directory" or "file" + if name ~= '' then + local link_pieces = vim.split(name, ' -> ', { plain = true }) + local entry_type = isdir and 'directory' or 'file' local link if #link_pieces == 2 then - entry_type = "link" + entry_type = 'link' name, link = unpack(link_pieces) end check_dupe(name, i) table.insert(diffs, { - type = "new", + type = 'new', name = name, entry_type = entry_type, link = link, @@ -309,7 +309,7 @@ M.parse = function(bufnr) for name, child_id in pairs(original_entries) do table.insert(diffs, { - type = "delete", + type = 'delete', name = name, id = child_id, }) diff --git a/lua/oil/mutator/progress.lua b/lua/oil/mutator/progress.lua index 057f0a0..81b6b5c 100644 --- a/lua/oil/mutator/progress.lua +++ b/lua/oil/mutator/progress.lua @@ -1,17 +1,17 @@ -local columns = require("oil.columns") -local config = require("oil.config") -local layout = require("oil.layout") -local loading = require("oil.loading") -local util = require("oil.util") +local columns = require('oil.columns') +local config = require('oil.config') +local layout = require('oil.layout') +local loading = require('oil.loading') +local util = require('oil.util') local Progress = {} local FPS = 20 function Progress.new() return setmetatable({ - lines = { "", "" }, - count = "", - spinner = "", + lines = { '', '' }, + count = '', + spinner = '', bufnr = nil, winid = nil, min_bufnr = nil, @@ -40,18 +40,18 @@ function Progress:show(opts) return end local bufnr = vim.api.nvim_create_buf(false, true) - vim.bo[bufnr].bufhidden = "wipe" + vim.bo[bufnr].bufhidden = 'wipe' self.bufnr = bufnr self.cancel = opts.cancel or self.cancel local loading_iter = loading.get_bar_iter() - local spinner = loading.get_iter("dots") + local spinner = loading.get_iter('dots') if not self.timer then self.timer = vim.loop.new_timer() self.timer:start( 0, math.floor(1000 / FPS), vim.schedule_wrap(function() - self.lines[2] = string.format("%s %s", self.count, loading_iter()) + self.lines[2] = string.format('%s %s', self.count, loading_iter()) self.spinner = spinner() self:_render() end) @@ -59,22 +59,22 @@ function Progress:show(opts) end local width, height = layout.calculate_dims(120, 10, config.progress) self.winid = vim.api.nvim_open_win(self.bufnr, true, { - relative = "editor", + relative = 'editor', width = width, height = height, row = math.floor((layout.get_editor_height() - height) / 2), col = math.floor((layout.get_editor_width() - width) / 2), zindex = 152, -- render on top of the floating window title - style = "minimal", + style = 'minimal', border = config.progress.border, }) - vim.bo[self.bufnr].filetype = "oil_progress" + vim.bo[self.bufnr].filetype = 'oil_progress' for k, v in pairs(config.progress.win_options) do - vim.api.nvim_set_option_value(k, v, { scope = "local", win = self.winid }) + vim.api.nvim_set_option_value(k, v, { scope = 'local', win = self.winid }) end table.insert( self.autocmds, - vim.api.nvim_create_autocmd("VimResized", { + vim.api.nvim_create_autocmd('VimResized', { callback = function() self:_reposition() end, @@ -82,7 +82,7 @@ function Progress:show(opts) ) table.insert( self.autocmds, - vim.api.nvim_create_autocmd("WinLeave", { + vim.api.nvim_create_autocmd('WinLeave', { callback = function() self:minimize() end, @@ -94,17 +94,17 @@ function Progress:show(opts) vim.api.nvim_win_close(self.winid, true) end end - vim.keymap.set("n", "c", cancel, { buffer = self.bufnr, nowait = true }) - vim.keymap.set("n", "C", cancel, { buffer = self.bufnr, nowait = true }) - vim.keymap.set("n", "m", minimize, { buffer = self.bufnr, nowait = true }) - vim.keymap.set("n", "M", minimize, { buffer = self.bufnr, nowait = true }) + vim.keymap.set('n', 'c', cancel, { buffer = self.bufnr, nowait = true }) + vim.keymap.set('n', 'C', cancel, { buffer = self.bufnr, nowait = true }) + vim.keymap.set('n', 'm', minimize, { buffer = self.bufnr, nowait = true }) + vim.keymap.set('n', 'M', minimize, { buffer = self.bufnr, nowait = true }) end function Progress:restore() if self.closing then return elseif not self:is_minimized() then - error("Cannot restore progress window: not minimized") + error('Cannot restore progress window: not minimized') end self:_cleanup_minimized_win() self:show() @@ -115,14 +115,14 @@ function Progress:_render() util.render_text( self.bufnr, self.lines, - { winid = self.winid, actions = { "[M]inimize", "[C]ancel" } } + { winid = self.winid, actions = { '[M]inimize', '[C]ancel' } } ) end if self.min_bufnr and vim.api.nvim_buf_is_valid(self.min_bufnr) then util.render_text( self.min_bufnr, - { string.format("%sOil: %s", self.spinner, self.count) }, - { winid = self.min_winid, h_align = "left" } + { string.format('%sOil: %s', self.spinner, self.count) }, + { winid = self.min_winid, h_align = 'left' } ) end end @@ -136,7 +136,7 @@ function Progress:_reposition() end local width, height = layout.calculate_dims(min_width, 10, config.progress) vim.api.nvim_win_set_config(self.winid, { - relative = "editor", + relative = 'editor', width = width, height = height, row = math.floor((layout.get_editor_height() - height) / 2), @@ -174,22 +174,22 @@ function Progress:minimize() end self:_cleanup_main_win() local bufnr = vim.api.nvim_create_buf(false, true) - vim.bo[bufnr].bufhidden = "wipe" + vim.bo[bufnr].bufhidden = 'wipe' local winid = vim.api.nvim_open_win(bufnr, false, { - relative = "editor", + relative = 'editor', width = 16, height = 1, - anchor = "SE", + anchor = 'SE', row = layout.get_editor_height(), col = layout.get_editor_width(), zindex = 152, -- render on top of the floating window title - style = "minimal", + style = 'minimal', border = config.progress.minimized_border, }) self.min_bufnr = bufnr self.min_winid = winid self:_render() - vim.notify_once("Restore progress window with :Oil --progress") + vim.notify_once('Restore progress window with :Oil --progress') end ---@param action oil.Action @@ -198,14 +198,14 @@ end function Progress:set_action(action, idx, total) local adapter = util.get_adapter_for_action(action) local change_line - if action.type == "change" then + if action.type == 'change' then ---@cast action oil.ChangeAction change_line = columns.render_change_action(adapter, action) else change_line = adapter.render_action(action) end self.lines[1] = change_line - self.count = string.format("%d/%d", idx, total) + self.count = string.format('%d/%d', idx, total) self:_reposition() self:_render() end diff --git a/lua/oil/mutator/trie.lua b/lua/oil/mutator/trie.lua index 7bac161..95ab979 100644 --- a/lua/oil/mutator/trie.lua +++ b/lua/oil/mutator/trie.lua @@ -1,4 +1,4 @@ -local util = require("oil.util") +local util = require('oil.util') ---@class (exact) oil.Trie ---@field new fun(): oil.Trie @@ -20,7 +20,7 @@ end function Trie:_url_to_path_pieces(url) local scheme, path = util.parse_url(url) assert(path) - local pieces = vim.split(path, "/") + local pieces = vim.split(path, '/') table.insert(pieces, 1, scheme) return pieces end @@ -75,7 +75,7 @@ function Trie:remove(path_pieces, value) return end end - error("Value not present in trie: " .. vim.inspect(value)) + error('Value not present in trie: ' .. vim.inspect(value)) end ---Add the first action that affects a parent path of the url diff --git a/lua/oil/pathutil.lua b/lua/oil/pathutil.lua index b030389..cfd4d82 100644 --- a/lua/oil/pathutil.lua +++ b/lua/oil/pathutil.lua @@ -3,26 +3,26 @@ local M = {} ---@param path string ---@return string M.parent = function(path) - if path == "/" then - return "/" - elseif path == "" then - return "" - elseif vim.endswith(path, "/") then - return path:match("^(.*/)[^/]*/$") or "" + if path == '/' then + return '/' + elseif path == '' then + return '' + elseif vim.endswith(path, '/') then + return path:match('^(.*/)[^/]*/$') or '' else - return path:match("^(.*/)[^/]*$") or "" + return path:match('^(.*/)[^/]*$') or '' end end ---@param path string ---@return nil|string M.basename = function(path) - if path == "/" or path == "" then + if path == '/' or path == '' then return - elseif vim.endswith(path, "/") then - return path:match("^.*/([^/]*)/$") + elseif vim.endswith(path, '/') then + return path:match('^.*/([^/]*)/$') else - return path:match("^.*/([^/]*)$") + return path:match('^.*/([^/]*)$') end end diff --git a/lua/oil/ringbuf.lua b/lua/oil/ringbuf.lua index 0f09987..66cd912 100644 --- a/lua/oil/ringbuf.lua +++ b/lua/oil/ringbuf.lua @@ -23,11 +23,11 @@ end ---@return string function Ringbuf:as_str() - local postfix = "" + local postfix = '' for i = 1, self.tail, 1 do postfix = postfix .. self.buf[i] end - local prefix = "" + local prefix = '' for i = self.tail + 1, #self.buf, 1 do prefix = prefix .. self.buf[i] end diff --git a/lua/oil/shell.lua b/lua/oil/shell.lua index b04b27b..9439846 100644 --- a/lua/oil/shell.lua +++ b/lua/oil/shell.lua @@ -9,7 +9,7 @@ M.run = function(cmd, opts, callback) local stderr = {} local jid = vim.fn.jobstart( cmd, - vim.tbl_deep_extend("keep", opts, { + vim.tbl_deep_extend('keep', opts, { stdout_buffered = true, stderr_buffered = true, on_stdout = function(j, output) @@ -22,19 +22,19 @@ M.run = function(cmd, opts, callback) if code == 0 then callback(nil, stdout) else - local err = table.concat(stderr, "\n") - if err == "" then - err = "Unknown error" + local err = table.concat(stderr, '\n') + if err == '' then + err = 'Unknown error' end - local cmd_str = type(cmd) == "string" and cmd or table.concat(cmd, " ") + local cmd_str = type(cmd) == 'string' and cmd or table.concat(cmd, ' ') callback(string.format("Error running command '%s'\n%s", cmd_str, err)) end end), }) ) local exe - if type(cmd) == "string" then - exe = vim.split(cmd, "%s+")[1] + if type(cmd) == 'string' then + exe = vim.split(cmd, '%s+')[1] else exe = cmd[1] end diff --git a/lua/oil/util.lua b/lua/oil/util.lua index 37e73cc..d9bca22 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -1,5 +1,5 @@ -local config = require("oil.config") -local constants = require("oil.constants") +local config = require('oil.config') +local constants = require('oil.constants') local M = {} @@ -14,7 +14,7 @@ local FIELD_META = constants.FIELD_META ---@return nil|string ---@return nil|string M.parse_url = function(url) - return url:match("^(.*://)(.*)$") + return url:match('^(.*://)(.*)$') end ---Escapes a filename for use in :edit @@ -26,51 +26,51 @@ M.escape_filename = function(filename) end local _url_escape_to_char = { - ["20"] = " ", - ["22"] = "“", - ["23"] = "#", - ["24"] = "$", - ["25"] = "%", - ["26"] = "&", - ["27"] = "‘", - ["2B"] = "+", - ["2C"] = ",", - ["2F"] = "/", - ["3A"] = ":", - ["3B"] = ";", - ["3C"] = "<", - ["3D"] = "=", - ["3E"] = ">", - ["3F"] = "?", - ["40"] = "@", - ["5B"] = "[", - ["5C"] = "\\", - ["5D"] = "]", - ["5E"] = "^", - ["60"] = "`", - ["7B"] = "{", - ["7C"] = "|", - ["7D"] = "}", - ["7E"] = "~", + ['20'] = ' ', + ['22'] = '“', + ['23'] = '#', + ['24'] = '$', + ['25'] = '%', + ['26'] = '&', + ['27'] = '‘', + ['2B'] = '+', + ['2C'] = ',', + ['2F'] = '/', + ['3A'] = ':', + ['3B'] = ';', + ['3C'] = '<', + ['3D'] = '=', + ['3E'] = '>', + ['3F'] = '?', + ['40'] = '@', + ['5B'] = '[', + ['5C'] = '\\', + ['5D'] = ']', + ['5E'] = '^', + ['60'] = '`', + ['7B'] = '{', + ['7C'] = '|', + ['7D'] = '}', + ['7E'] = '~', } local _char_to_url_escape = {} for k, v in pairs(_url_escape_to_char) do - _char_to_url_escape[v] = "%" .. k + _char_to_url_escape[v] = '%' .. k end -- TODO this uri escape handling is very incomplete ---@param string string ---@return string M.url_escape = function(string) - return (string:gsub(".", _char_to_url_escape)) + return (string:gsub('.', _char_to_url_escape)) end ---@param string string ---@return string M.url_unescape = function(string) return ( - string:gsub("%%([0-9A-Fa-f][0-9A-Fa-f])", function(seq) - return _url_escape_to_char[seq:upper()] or ("%" .. seq) + string:gsub('%%([0-9A-Fa-f][0-9A-Fa-f])', function(seq) + return _url_escape_to_char[seq:upper()] or ('%' .. seq) end) ) end @@ -105,14 +105,14 @@ M.pad_align = function(text, width, align) return text, 0 end - if align == "right" then - return string.rep(" ", total_pad) .. text, total_pad - elseif align == "center" then + if align == 'right' then + return string.rep(' ', total_pad) .. text, total_pad + elseif align == 'center' then local left_pad = math.floor(total_pad / 2) local right_pad = total_pad - left_pad - return string.rep(" ", left_pad) .. text .. string.rep(" ", right_pad), left_pad + return string.rep(' ', left_pad) .. text .. string.rep(' ', right_pad), left_pad else - return text .. string.rep(" ", total_pad), 0 + return text .. string.rep(' ', total_pad), 0 end end @@ -150,7 +150,7 @@ end ---@param dest_buf_name string ---@return boolean True if the buffer was replaced instead of renamed M.rename_buffer = function(src_bufnr, dest_buf_name) - if type(src_bufnr) == "string" then + if type(src_bufnr) == 'string' then src_bufnr = vim.fn.bufadd(src_bufnr) if not vim.api.nvim_buf_is_loaded(src_bufnr) then vim.api.nvim_buf_delete(src_bufnr, {}) @@ -164,7 +164,7 @@ M.rename_buffer = function(src_bufnr, dest_buf_name) -- think that the new buffer conflicts with the file next time it tries to save. if not vim.loop.fs_stat(dest_buf_name) then ---@diagnostic disable-next-line: param-type-mismatch - local altbuf = vim.fn.bufnr("#") + local altbuf = vim.fn.bufnr('#') -- This will fail if the dest buf name already exists local ok = pcall(vim.api.nvim_buf_set_name, src_bufnr, dest_buf_name) if ok then @@ -173,7 +173,7 @@ M.rename_buffer = function(src_bufnr, dest_buf_name) -- where Neovim doesn't allow buffer modifications. pcall(vim.api.nvim_buf_delete, vim.fn.bufadd(bufname), {}) if altbuf and vim.api.nvim_buf_is_valid(altbuf) then - vim.fn.setreg("#", altbuf) + vim.fn.setreg('#', altbuf) end return false @@ -229,6 +229,7 @@ end M.cb_collect = function(count, cb) return function(err) if err then + -- selene: allow(mismatched_arg_count) cb(err) cb = function() end else @@ -243,9 +244,9 @@ end ---@param url string ---@return string[] local function get_possible_buffer_names_from_url(url) - local fs = require("oil.fs") + local fs = require('oil.fs') local scheme, path = M.parse_url(url) - if config.adapters[scheme] == "files" then + if config.adapters[scheme] == 'files' then assert(path) return { fs.posix_to_os_path(path) } end @@ -258,7 +259,7 @@ end M.update_moved_buffers = function(entry_type, src_url, dest_url) local src_buf_names = get_possible_buffer_names_from_url(src_url) local dest_buf_name = get_possible_buffer_names_from_url(dest_url)[1] - if entry_type ~= "directory" then + if entry_type ~= 'directory' then for _, src_buf_name in ipairs(src_buf_names) do M.rename_buffer(src_buf_name, dest_buf_name) end @@ -272,13 +273,13 @@ M.update_moved_buffers = function(entry_type, src_url, dest_url) if vim.startswith(bufname, src_url) then -- Handle oil directory buffers vim.api.nvim_buf_set_name(bufnr, dest_url .. bufname:sub(src_url:len() + 1)) - elseif bufname ~= "" and vim.bo[bufnr].buftype == "" then + elseif bufname ~= '' and vim.bo[bufnr].buftype == '' then -- Handle regular buffers local scheme = M.parse_url(bufname) -- If the buffer is a local file, make sure we're using the absolute path if not scheme then - bufname = vim.fn.fnamemodify(bufname, ":p") + bufname = vim.fn.fnamemodify(bufname, ':p') end for _, src_buf_name in ipairs(src_buf_names) do @@ -296,13 +297,13 @@ end ---@return string ---@return table|nil M.split_config = function(name_or_config) - if type(name_or_config) == "string" then + if type(name_or_config) == 'string' then return name_or_config, nil else - if not name_or_config[1] and name_or_config["1"] then + if not name_or_config[1] and name_or_config['1'] then -- This was likely loaded from json, so the first element got coerced to a string key - name_or_config[1] = name_or_config["1"] - name_or_config["1"] = nil + name_or_config[1] = name_or_config['1'] + name_or_config['1'] = nil end return name_or_config[1], name_or_config end @@ -324,7 +325,7 @@ M.render_table = function(lines, col_width, col_align) local pieces = {} for i, chunk in ipairs(cols) do local text, hl - if type(chunk) == "table" then + if type(chunk) == 'table' then text = chunk[1] hl = chunk[2] else @@ -333,11 +334,11 @@ M.render_table = function(lines, col_width, col_align) local unpadded_len = text:len() local padding - text, padding = M.pad_align(text, col_width[i], col_align[i] or "left") + text, padding = M.pad_align(text, col_width[i], col_align[i] or 'left') table.insert(pieces, text) if hl then - if type(hl) == "table" then + if type(hl) == 'table' then -- hl has the form { [1]: hl_name, [2]: col_start, [3]: col_end }[] -- Notice that col_start and col_end are relative position inside -- that col, so we need to add the offset to them @@ -355,7 +356,7 @@ M.render_table = function(lines, col_width, col_align) end col = col + text:len() + 1 end - table.insert(str_lines, table.concat(pieces, " ")) + table.insert(str_lines, table.concat(pieces, ' ')) end return str_lines, highlights end @@ -363,7 +364,7 @@ end ---@param bufnr integer ---@param highlights any[][] List of highlights {group, lnum, col_start, col_end} M.set_highlights = function(bufnr, highlights) - local ns = vim.api.nvim_create_namespace("Oil") + local ns = vim.api.nvim_create_namespace('Oil') vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) for _, hl in ipairs(highlights) do local group, line, col_start, col_end = unpack(hl) @@ -379,12 +380,12 @@ end ---@param os_slash? boolean use os filesystem slash instead of posix slash ---@return string M.addslash = function(path, os_slash) - local slash = "/" - if os_slash and require("oil.fs").is_windows then - slash = "\\" + local slash = '/' + if os_slash and require('oil.fs').is_windows then + slash = '\\' end - local endslash = path:match(slash .. "$") + local endslash = path:match(slash .. '$') if not endslash then return path .. slash else @@ -395,7 +396,7 @@ end ---@param winid nil|integer ---@return boolean M.is_floating_win = function(winid) - return vim.api.nvim_win_get_config(winid or 0).relative ~= "" + return vim.api.nvim_win_get_config(winid or 0).relative ~= '' end ---Recalculate the window title for the current buffer @@ -410,10 +411,10 @@ M.get_title = function(winid) local title = vim.api.nvim_buf_get_name(src_buf) local scheme, path = M.parse_url(title) - if config.adapters[scheme] == "files" then + if config.adapters[scheme] == 'files' then assert(path) - local fs = require("oil.fs") - title = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":~") + local fs = require('oil.fs') + title = vim.fn.fnamemodify(fs.posix_to_os_path(path), ':~') end return title end @@ -421,7 +422,7 @@ end local winid_map = {} M.add_title_to_win = function(winid, opts) opts = opts or {} - opts.align = opts.align or "left" + opts.align = opts.align or 'left' if not vim.api.nvim_win_is_valid(winid) then return end @@ -438,18 +439,18 @@ M.add_title_to_win = function(winid, opts) else bufnr = vim.api.nvim_create_buf(false, true) local col = 1 - if opts.align == "center" then + if opts.align == 'center' then col = math.floor((vim.api.nvim_win_get_width(winid) - width) / 2) - elseif opts.align == "right" then + elseif opts.align == 'right' then col = vim.api.nvim_win_get_width(winid) - 1 - width - elseif opts.align ~= "left" then + elseif opts.align ~= 'left' then vim.notify( string.format("Unknown oil window title alignment: '%s'", opts.align), vim.log.levels.ERROR ) end title_winid = vim.api.nvim_open_win(bufnr, false, { - relative = "win", + relative = 'win', win = winid, width = width, height = 1, @@ -457,20 +458,20 @@ M.add_title_to_win = function(winid, opts) col = col, focusable = false, zindex = 151, - style = "minimal", + style = 'minimal', noautocmd = true, }) winid_map[winid] = title_winid vim.api.nvim_set_option_value( - "winblend", + 'winblend', vim.wo[winid].winblend, - { scope = "local", win = title_winid } + { scope = 'local', win = title_winid } ) - vim.bo[bufnr].bufhidden = "wipe" + vim.bo[bufnr].bufhidden = 'wipe' - local update_autocmd = vim.api.nvim_create_autocmd("BufWinEnter", { - desc = "Update oil floating window title when buffer changes", - pattern = "*", + local update_autocmd = vim.api.nvim_create_autocmd('BufWinEnter', { + desc = 'Update oil floating window title when buffer changes', + pattern = '*', callback = function(params) local winbuf = params.buf if vim.api.nvim_win_get_buf(winid) ~= winbuf then @@ -479,17 +480,17 @@ M.add_title_to_win = function(winid, opts) local new_title = M.get_title(winid) local new_width = math.min(vim.api.nvim_win_get_width(winid) - 4, 2 + vim.api.nvim_strwidth(new_title)) - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { " " .. new_title .. " " }) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { ' ' .. new_title .. ' ' }) vim.bo[bufnr].modified = false vim.api.nvim_win_set_width(title_winid, new_width) local new_col = 1 - if opts.align == "center" then + if opts.align == 'center' then new_col = math.floor((vim.api.nvim_win_get_width(winid) - new_width) / 2) - elseif opts.align == "right" then + elseif opts.align == 'right' then new_col = vim.api.nvim_win_get_width(winid) - 1 - new_width end vim.api.nvim_win_set_config(title_winid, { - relative = "win", + relative = 'win', win = winid, row = -1, col = new_col, @@ -498,8 +499,8 @@ M.add_title_to_win = function(winid, opts) }) end, }) - vim.api.nvim_create_autocmd("WinClosed", { - desc = "Close oil floating window title when floating window closes", + vim.api.nvim_create_autocmd('WinClosed', { + desc = 'Close oil floating window title when floating window closes', pattern = tostring(winid), callback = function() if title_winid and vim.api.nvim_win_is_valid(title_winid) then @@ -512,12 +513,12 @@ M.add_title_to_win = function(winid, opts) nested = true, }) end - vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { " " .. title .. " " }) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { ' ' .. title .. ' ' }) vim.bo[bufnr].modified = false vim.api.nvim_set_option_value( - "winhighlight", - "Normal:FloatTitle,NormalFloat:FloatTitle", - { scope = "local", win = title_winid } + 'winhighlight', + 'Normal:FloatTitle,NormalFloat:FloatTitle', + { scope = 'local', win = title_winid } ) end @@ -542,7 +543,7 @@ M.get_adapter_for_action = function(action) else error( string.format( - "Cannot copy files from %s -> %s; no cross-adapter transfer method found", + 'Cannot copy files from %s -> %s; no cross-adapter transfer method found', action.src_url, action.dest_url ) @@ -559,12 +560,12 @@ end ---@return string ---@return integer M.h_align = function(str, align, width) - if align == "center" then + if align == 'center' then local padding = math.floor((width - vim.api.nvim_strwidth(str)) / 2) - return string.rep(" ", padding) .. str, padding - elseif align == "right" then + return string.rep(' ', padding) .. str, padding + elseif align == 'right' then local padding = width - vim.api.nvim_strwidth(str) - return string.rep(" ", padding) .. str, padding + return string.rep(' ', padding) .. str, padding else return str, 0 end @@ -578,15 +579,15 @@ end --- actions nil|string[] --- winid nil|integer M.render_text = function(bufnr, text, opts) - opts = vim.tbl_deep_extend("keep", opts or {}, { - h_align = "center", - v_align = "center", + opts = vim.tbl_deep_extend('keep', opts or {}, { + h_align = 'center', + v_align = 'center', }) ---@cast opts -nil if not vim.api.nvim_buf_is_valid(bufnr) then return end - if type(text) == "string" then + if type(text) == 'string' then text = { text } end local height = 40 @@ -608,17 +609,17 @@ M.render_text = function(bufnr, text, opts) local lines = {} -- Add vertical spacing for vertical alignment - if opts.v_align == "center" then + if opts.v_align == 'center' then for _ = 1, (height / 2) - (#text / 2) do - table.insert(lines, "") + table.insert(lines, '') end - elseif opts.v_align == "bottom" then + elseif opts.v_align == 'bottom' then local num_lines = height if opts.actions then num_lines = num_lines - 2 end while #lines + #text < num_lines do - table.insert(lines, "") + table.insert(lines, '') end end @@ -632,12 +633,12 @@ M.render_text = function(bufnr, text, opts) local highlights = {} if opts.actions then while #lines < height - 1 do - table.insert(lines, "") + table.insert(lines, '') end - local last_line, padding = M.h_align(table.concat(opts.actions, " "), "center", width) + local last_line, padding = M.h_align(table.concat(opts.actions, ' '), 'center', width) local col = padding for _, action in ipairs(opts.actions) do - table.insert(highlights, { "Special", #lines, col, col + 3 }) + table.insert(highlights, { 'Special', #lines, col, col + 3 }) col = padding + action:len() + 4 end table.insert(lines, last_line) @@ -656,10 +657,10 @@ end M.run_in_fullscreen_win = function(bufnr, callback) if not bufnr then bufnr = vim.api.nvim_create_buf(false, true) - vim.bo[bufnr].bufhidden = "wipe" + vim.bo[bufnr].bufhidden = 'wipe' end local winid = vim.api.nvim_open_win(bufnr, false, { - relative = "editor", + relative = 'editor', width = vim.o.columns, height = vim.o.lines, row = 0, @@ -667,7 +668,7 @@ M.run_in_fullscreen_win = function(bufnr, callback) noautocmd = true, }) local winnr = vim.api.nvim_win_get_number(winid) - vim.cmd.wincmd({ count = winnr, args = { "w" }, mods = { noautocmd = true } }) + vim.cmd.wincmd({ count = winnr, args = { 'w' }, mods = { noautocmd = true } }) callback() vim.cmd.close({ count = winnr, mods = { noautocmd = true, emsg_silent = true } }) end @@ -676,9 +677,9 @@ end ---@return boolean M.is_oil_bufnr = function(bufnr) local filetype = vim.bo[bufnr].filetype - if filetype == "oil" then + if filetype == 'oil' then return true - elseif filetype ~= "" then + elseif filetype ~= '' then -- If the filetype is set and is NOT "oil", then it's not an oil buffer return false end @@ -693,10 +694,10 @@ M.hack_around_termopen_autocmd = function(prev_mode) vim.defer_fn(function() local new_mode = vim.api.nvim_get_mode().mode if new_mode ~= prev_mode then - if string.find(new_mode, "i") == 1 then - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("", true, true, true), "n", false) - if string.find(prev_mode, "v") == 1 or string.find(prev_mode, "V") == 1 then - vim.cmd.normal({ bang = true, args = { "gv" } }) + if string.find(new_mode, 'i') == 1 then + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, true, true), 'n', false) + if string.find(prev_mode, 'v') == 1 or string.find(prev_mode, 'V') == 1 then + vim.cmd.normal({ bang = true, args = { 'gv' } }) end end end @@ -712,7 +713,7 @@ M.get_preview_win = function(opts) if vim.api.nvim_win_is_valid(winid) and vim.wo[winid].previewwindow - and (opts.include_not_owned or vim.w[winid]["oil_preview"]) + and (opts.include_not_owned or vim.w[winid]['oil_preview']) then return winid end @@ -721,13 +722,13 @@ end ---@return fun() restore Function that restores the cursor M.hide_cursor = function() - vim.api.nvim_set_hl(0, "OilPreviewCursor", { nocombine = true, blend = 100 }) + vim.api.nvim_set_hl(0, 'OilPreviewCursor', { nocombine = true, blend = 100 }) local original_guicursor = vim.go.guicursor - vim.go.guicursor = "a:OilPreviewCursor/OilPreviewCursor" + vim.go.guicursor = 'a:OilPreviewCursor/OilPreviewCursor' return function() -- HACK: see https://github.com/neovim/neovim/issues/21018 - vim.go.guicursor = "a:" + vim.go.guicursor = 'a:' vim.cmd.redrawstatus() vim.go.guicursor = original_guicursor end @@ -762,7 +763,7 @@ end ---@param opts {columns?: string[], no_cache?: boolean} ---@param callback fun(err: nil|string, entries: nil|oil.InternalEntry[]) M.adapter_list_all = function(adapter, url, opts, callback) - local cache = require("oil.cache") + local cache = require('oil.cache') if not opts.no_cache then local entries = cache.list_url(url) if not vim.tbl_isempty(entries) then @@ -790,23 +791,23 @@ end ---based on the provided options. ---@param opts {target?: "qflist"|"loclist", action?: "r"|"a", only_matching_search?: boolean} M.send_to_quickfix = function(opts) - if type(opts) ~= "table" then + if type(opts) ~= 'table' then opts = {} end - local oil = require("oil") + local oil = require('oil') local dir = oil.get_current_dir() - if type(dir) ~= "string" then + if type(dir) ~= 'string' then return end local range = M.get_visual_range() if not range then - range = { start_lnum = 1, end_lnum = vim.fn.line("$") } + range = { start_lnum = 1, end_lnum = vim.fn.line('$') } end local match_all = not opts.only_matching_search local qf_entries = {} for i = range.start_lnum, range.end_lnum do local entry = oil.get_entry_on_line(0, i) - if entry and entry.type == "file" and (match_all or M.is_matching(entry)) then + if entry and entry.type == 'file' and (match_all or M.is_matching(entry)) then local qf_entry = { filename = dir .. entry.name, lnum = 1, @@ -817,26 +818,26 @@ M.send_to_quickfix = function(opts) end end if #qf_entries == 0 then - vim.notify("[oil] No entries found to send to quickfix", vim.log.levels.WARN) + vim.notify('[oil] No entries found to send to quickfix', vim.log.levels.WARN) return end - vim.api.nvim_exec_autocmds("QuickFixCmdPre", {}) - local qf_title = "oil files" - local action = opts.action == "a" and "a" or "r" - if opts.target == "loclist" then + vim.api.nvim_exec_autocmds('QuickFixCmdPre', {}) + local qf_title = 'oil files' + local action = opts.action == 'a' and 'a' or 'r' + if opts.target == 'loclist' then vim.fn.setloclist(0, {}, action, { title = qf_title, items = qf_entries }) vim.cmd.lopen() else vim.fn.setqflist({}, action, { title = qf_title, items = qf_entries }) vim.cmd.copen() end - vim.api.nvim_exec_autocmds("QuickFixCmdPost", {}) + vim.api.nvim_exec_autocmds('QuickFixCmdPost', {}) end ---@return boolean M.is_visual_mode = function() local mode = vim.api.nvim_get_mode().mode - return mode:match("^[vV]") ~= nil + return mode:match('^[vV]') ~= nil end ---Get the current visual selection range. If not in visual mode, return nil. @@ -847,7 +848,7 @@ M.get_visual_range = function() end -- This is the best way to get the visual selection at the moment -- https://github.com/neovim/neovim/pull/13896 - local _, start_lnum, _, _ = unpack(vim.fn.getpos("v")) + local _, start_lnum, _, _ = unpack(vim.fn.getpos('v')) local _, end_lnum, _, _, _ = unpack(vim.fn.getcurpos()) if start_lnum > end_lnum then start_lnum, end_lnum = end_lnum, start_lnum @@ -863,7 +864,7 @@ M.is_matching = function(entry) if search_highlighting_is_off then return true end - local pattern = vim.fn.getreg("/") + local pattern = vim.fn.getreg('/') local position_of_match = vim.fn.match(entry.name, pattern) return position_of_match ~= -1 end @@ -877,8 +878,8 @@ M.run_after_load = function(bufnr, callback) if vim.b[bufnr].oil_ready then callback() else - vim.api.nvim_create_autocmd("User", { - pattern = "OilEnter", + vim.api.nvim_create_autocmd('User', { + pattern = 'OilEnter', callback = function(args) if args.data.buf == bufnr then vim.api.nvim_buf_call(bufnr, callback) @@ -892,12 +893,12 @@ end ---@param entry oil.Entry ---@return boolean M.is_directory = function(entry) - local is_directory = entry.type == "directory" + local is_directory = entry.type == 'directory' or ( - entry.type == "link" + entry.type == 'link' and entry.meta and entry.meta.link_stat - and entry.meta.link_stat.type == "directory" + and entry.meta.link_stat.type == 'directory' ) return is_directory == true end @@ -907,7 +908,7 @@ end ---@param entry oil.Entry ---@param callback fun(normalized_url: string) M.get_edit_path = function(bufnr, entry, callback) - local pathutil = require("oil.pathutil") + local pathutil = require('oil.pathutil') local bufname = vim.api.nvim_buf_get_name(bufnr) local scheme, dir = M.parse_url(bufname) @@ -916,10 +917,10 @@ M.get_edit_path = function(bufnr, entry, callback) local url = scheme .. dir .. entry.name if M.is_directory(entry) then - url = url .. "/" + url = url .. '/' end - if entry.name == ".." then + if entry.name == '..' then callback(scheme .. pathutil.parent(dir)) elseif adapter.get_entry_path then adapter.get_entry_path(url, entry, callback) @@ -932,33 +933,34 @@ end ---@return (oil.IconProvider)? M.get_icon_provider = function() -- prefer mini.icons - local _, mini_icons = pcall(require, "mini.icons") + local _, mini_icons = pcall(require, 'mini.icons') + -- selene: allow(global_usage) ---@diagnostic disable-next-line: undefined-field - if _G.MiniIcons then -- `_G.MiniIcons` is a better check to see if the module is setup + if _G.MiniIcons then return function(type, name, conf, ft) if ft then - return mini_icons.get("filetype", ft) + return mini_icons.get('filetype', ft) end - return mini_icons.get(type == "directory" and "directory" or "file", name) + return mini_icons.get(type == 'directory' and 'directory' or 'file', name) end end -- fallback to `nvim-web-devicons` - local has_devicons, devicons = pcall(require, "nvim-web-devicons") + local has_devicons, devicons = pcall(require, 'nvim-web-devicons') if has_devicons then return function(type, name, conf, ft) - if type == "directory" then - return conf and conf.directory or "", "OilDirIcon" + if type == 'directory' then + return conf and conf.directory or '', 'OilDirIcon' else if ft then local ft_icon, ft_hl = devicons.get_icon_by_filetype(ft) - if ft_icon and ft_icon ~= "" then + if ft_icon and ft_icon ~= '' then return ft_icon, ft_hl end end local icon, hl = devicons.get_icon(name) - hl = hl or "OilFileIcon" - icon = icon or (conf and conf.default_file or "") + hl = hl or 'OilFileIcon' + icon = icon or (conf and conf.default_file or '') return icon, hl end end @@ -975,24 +977,25 @@ M.read_file_to_scratch_buffer = function(path, preview_method) return end - vim.bo[bufnr].bufhidden = "wipe" - vim.bo[bufnr].buftype = "nofile" + vim.bo[bufnr].bufhidden = 'wipe' + vim.bo[bufnr].buftype = 'nofile' local has_lines, read_res - if preview_method == "fast_scratch" then - has_lines, read_res = pcall(vim.fn.readfile, path, "", vim.o.lines) + if preview_method == 'fast_scratch' then + has_lines, read_res = pcall(vim.fn.readfile, path, '', vim.o.lines) else has_lines, read_res = pcall(vim.fn.readfile, path) end - local lines = has_lines and vim.split(table.concat(read_res, "\n"), "\n") or {} + local lines = has_lines and vim.split(table.concat(read_res, '\n'), '\n') or {} local ok = pcall(vim.api.nvim_buf_set_lines, bufnr, 0, -1, false, lines) if not ok then return end local ft = vim.filetype.match({ filename = path, buf = bufnr }) - if ft and ft ~= "" and vim.treesitter.language.get_lang then + if ft and ft ~= '' and vim.treesitter.language.get_lang then local lang = vim.treesitter.language.get_lang(ft) + -- selene: allow(empty_if) if not pcall(vim.treesitter.start, bufnr, lang) then vim.bo[bufnr].syntax = ft else @@ -1000,8 +1003,8 @@ M.read_file_to_scratch_buffer = function(path, preview_method) end -- Replace the scratch buffer with a real buffer if we enter it - vim.api.nvim_create_autocmd("BufEnter", { - desc = "oil.nvim replace scratch buffer with real buffer", + vim.api.nvim_create_autocmd('BufEnter', { + desc = 'oil.nvim replace scratch buffer with real buffer', buffer = bufnr, callback = function() local winid = vim.api.nvim_get_current_win() @@ -1013,7 +1016,7 @@ M.read_file_to_scratch_buffer = function(path, preview_method) -- If we're still in a preview window, make sure this buffer still gets treated as a -- preview if vim.wo.previewwindow then - vim.bo.bufhidden = "wipe" + vim.bo.bufhidden = 'wipe' vim.b.oil_preview_buffer = true end end @@ -1030,7 +1033,7 @@ local _regcache = {} ---@return boolean M.file_matches_bufreadcmd = function(filename) local autocmds = vim.api.nvim_get_autocmds({ - event = "BufReadCmd", + event = 'BufReadCmd', }) for _, au in ipairs(autocmds) do local pat = _regcache[au.pattern] diff --git a/lua/oil/view.lua b/lua/oil/view.lua index bc21dfb..e477009 100644 --- a/lua/oil/view.lua +++ b/lua/oil/view.lua @@ -1,12 +1,12 @@ local uv = vim.uv or vim.loop -local cache = require("oil.cache") -local columns = require("oil.columns") -local config = require("oil.config") -local constants = require("oil.constants") -local fs = require("oil.fs") -local keymap_util = require("oil.keymap_util") -local loading = require("oil.loading") -local util = require("oil.util") +local cache = require('oil.cache') +local columns = require('oil.columns') +local config = require('oil.config') +local constants = require('oil.constants') +local fs = require('oil.fs') +local keymap_util = require('oil.keymap_util') +local loading = require('oil.loading') +local util = require('oil.util') local M = {} local FIELD_ID = constants.FIELD_ID @@ -41,7 +41,7 @@ end ---Set the cursor to the last_cursor_entry if one exists M.maybe_set_cursor = function() - local oil = require("oil") + local oil = require('oil') local bufname = vim.api.nvim_buf_get_name(0) local entry_name = last_cursor_entry[bufname] if not entry_name then @@ -52,7 +52,7 @@ M.maybe_set_cursor = function() local entry = oil.get_entry_on_line(0, lnum) if entry and entry.name == entry_name then local line = vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, true)[1] - local id_str = line:match("^/(%d+)") + local id_str = line:match('^/(%d+)') local col = line:find(entry_name, 1, true) or (id_str:len() + 1) vim.api.nvim_win_set_cursor(0, { lnum, col - 1 }) M.set_last_cursor(bufname, nil) @@ -78,14 +78,14 @@ local function are_any_modified() end local function is_unix_executable(entry) - if entry[FIELD_TYPE] == "directory" then + if entry[FIELD_TYPE] == 'directory' then return false end local meta = entry[FIELD_META] if not meta or not meta.stat then return false end - if meta.stat.type == "directory" then + if meta.stat.type == 'directory' then return false end @@ -98,7 +98,7 @@ end M.toggle_hidden = function() local any_modified = are_any_modified() if any_modified then - vim.notify("Cannot toggle hidden files when you have unsaved changes", vim.log.levels.WARN) + vim.notify('Cannot toggle hidden files when you have unsaved changes', vim.log.levels.WARN) else config.view_options.show_hidden = not config.view_options.show_hidden M.rerender_all_oil_buffers({ refetch = false }) @@ -109,7 +109,7 @@ end M.set_is_hidden_file = function(is_hidden_file) local any_modified = are_any_modified() if any_modified then - vim.notify("Cannot change is_hidden_file when you have unsaved changes", vim.log.levels.WARN) + vim.notify('Cannot change is_hidden_file when you have unsaved changes', vim.log.levels.WARN) else config.view_options.is_hidden_file = is_hidden_file M.rerender_all_oil_buffers({ refetch = false }) @@ -119,7 +119,7 @@ end M.set_columns = function(cols) local any_modified = are_any_modified() if any_modified then - vim.notify("Cannot change columns when you have unsaved changes", vim.log.levels.WARN) + vim.notify('Cannot change columns when you have unsaved changes', vim.log.levels.WARN) else config.columns = cols -- TODO only refetch if we don't have all the necessary data for the columns @@ -130,7 +130,7 @@ end M.set_sort = function(new_sort) local any_modified = are_any_modified() if any_modified then - vim.notify("Cannot change sorting when you have unsaved changes", vim.log.levels.WARN) + vim.notify('Cannot change sorting when you have unsaved changes', vim.log.levels.WARN) else config.view_options.sort = new_sort -- TODO only refetch if we don't have all the necessary data for the columns @@ -207,14 +207,14 @@ M.set_win_options = function() local winid = vim.api.nvim_get_current_win() -- work around https://github.com/neovim/neovim/pull/27422 - vim.api.nvim_set_option_value("foldmethod", "manual", { scope = "local", win = winid }) + vim.api.nvim_set_option_value('foldmethod', 'manual', { scope = 'local', win = winid }) for k, v in pairs(config.win_options) do - vim.api.nvim_set_option_value(k, v, { scope = "local", win = winid }) + vim.api.nvim_set_option_value(k, v, { scope = 'local', win = winid }) end if vim.wo[winid].previewwindow then -- apply preview window options last for k, v in pairs(config.preview_win.win_options) do - vim.api.nvim_set_option_value(k, v, { scope = "local", win = winid }) + vim.api.nvim_set_option_value(k, v, { scope = 'local', win = winid }) end end end @@ -251,7 +251,7 @@ M.delete_hidden_buffers = function() not visible_buffers or not hidden_buffers or not vim.tbl_isempty(visible_buffers) - or vim.fn.win_gettype() == "command" + or vim.fn.win_gettype() == 'command' then return end @@ -283,15 +283,15 @@ end --- @param cur integer[] --- @return integer[] | nil local function calc_constrained_cursor_pos(bufnr, adapter, mode, cur) - local parser = require("oil.mutator.parser") + local parser = require('oil.mutator.parser') local line = vim.api.nvim_buf_get_lines(bufnr, cur[1] - 1, cur[1], true)[1] local column_defs = columns.get_supported_columns(adapter) local result = parser.parse_line(adapter, line, column_defs) if result and result.ranges then local min_col - if mode == "editable" then + if mode == 'editable' then min_col = get_first_mutable_column_col(adapter, result.ranges) - elseif mode == "name" then + elseif mode == 'name' then min_col = result.ranges.name[1] else error(string.format('Unexpected value "%s" for option constrain_cursor', mode)) @@ -318,7 +318,7 @@ local function constrain_cursor(bufnr, mode) return end - local mc = package.loaded["multicursor-nvim"] + local mc = package.loaded['multicursor-nvim'] if mc then mc.onSafeState(function() mc.action(function(ctx) @@ -346,14 +346,14 @@ local function redraw_trash_virtual_text(bufnr) if not vim.api.nvim_buf_is_valid(bufnr) or not vim.api.nvim_buf_is_loaded(bufnr) then return end - local parser = require("oil.mutator.parser") + local parser = require('oil.mutator.parser') local adapter = util.get_adapter(bufnr, true) - if not adapter or adapter.name ~= "trash" then + if not adapter or adapter.name ~= 'trash' then return end local _, buf_path = util.parse_url(vim.api.nvim_buf_get_name(bufnr)) local os_path = fs.posix_to_os_path(assert(buf_path)) - local ns = vim.api.nvim_create_namespace("OilVtext") + local ns = vim.api.nvim_create_namespace('OilVtext') vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) local column_defs = columns.get_supported_columns(adapter) for lnum, line in ipairs(vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)) do @@ -367,8 +367,8 @@ local function redraw_trash_virtual_text(bufnr) vim.api.nvim_buf_set_extmark(bufnr, ns, lnum - 1, 0, { virt_text = { { - "➜ " .. fs.shorten_path(trash_info.original_path, os_path), - "OilTrashSourcePath", + '➜ ' .. fs.shorten_path(trash_info.original_path, os_path), + 'OilTrashSourcePath', }, }, }) @@ -387,13 +387,13 @@ M.initialize = function(bufnr) end vim.api.nvim_clear_autocmds({ buffer = bufnr, - group = "Oil", + group = 'Oil', }) - vim.bo[bufnr].buftype = "acwrite" + vim.bo[bufnr].buftype = 'acwrite' vim.bo[bufnr].readonly = false vim.bo[bufnr].swapfile = false - vim.bo[bufnr].syntax = "oil" - vim.bo[bufnr].filetype = "oil" + vim.bo[bufnr].syntax = 'oil' + vim.bo[bufnr].filetype = 'oil' vim.b[bufnr].EditorConfig_disable = 1 session[bufnr] = session[bufnr] or {} for k, v in pairs(config.buf_options) do @@ -401,9 +401,9 @@ M.initialize = function(bufnr) end vim.api.nvim_buf_call(bufnr, M.set_win_options) - vim.api.nvim_create_autocmd("BufHidden", { - desc = "Delete oil buffers when no longer in use", - group = "Oil", + vim.api.nvim_create_autocmd('BufHidden', { + desc = 'Delete oil buffers when no longer in use', + group = 'Oil', nested = true, buffer = bufnr, callback = function() @@ -413,7 +413,7 @@ M.initialize = function(bufnr) -- Only delete oil buffers if none of them are visible if visible_buffers and vim.tbl_isempty(visible_buffers) then -- Check if cleanup is enabled - if type(config.cleanup_delay_ms) == "number" then + if type(config.cleanup_delay_ms) == 'number' then if config.cleanup_delay_ms > 0 then vim.defer_fn(function() M.delete_hidden_buffers() @@ -426,8 +426,8 @@ M.initialize = function(bufnr) end, 100) end, }) - vim.api.nvim_create_autocmd("BufUnload", { - group = "Oil", + vim.api.nvim_create_autocmd('BufUnload', { + group = 'Oil', nested = true, once = true, buffer = bufnr, @@ -439,8 +439,8 @@ M.initialize = function(bufnr) end end, }) - vim.api.nvim_create_autocmd("BufEnter", { - group = "Oil", + vim.api.nvim_create_autocmd('BufEnter', { + group = 'Oil', buffer = bufnr, callback = function(args) local opts = vim.b[args.buf].oil_dirty @@ -451,9 +451,9 @@ M.initialize = function(bufnr) end, }) local timer - vim.api.nvim_create_autocmd("InsertEnter", { - desc = "Constrain oil cursor position", - group = "Oil", + vim.api.nvim_create_autocmd('InsertEnter', { + desc = 'Constrain oil cursor position', + group = 'Oil', buffer = bufnr, callback = function() -- For some reason the cursor bounces back to its original position, @@ -461,12 +461,12 @@ M.initialize = function(bufnr) vim.schedule_wrap(constrain_cursor)(bufnr, config.constrain_cursor) end, }) - vim.api.nvim_create_autocmd({ "CursorMoved", "ModeChanged" }, { - desc = "Update oil preview window", - group = "Oil", + vim.api.nvim_create_autocmd({ 'CursorMoved', 'ModeChanged' }, { + desc = 'Update oil preview window', + group = 'Oil', buffer = bufnr, callback = function() - local oil = require("oil") + local oil = require('oil') if vim.wo.previewwindow then return end @@ -513,7 +513,7 @@ M.initialize = function(bufnr) -- Set up a watcher that will refresh the directory if adapter - and adapter.name == "files" + and adapter.name == 'files' and config.watch_for_changes and not session[bufnr].fs_event then @@ -532,7 +532,7 @@ M.initialize = function(bufnr) fs_event:stop() return end - local mutator = require("oil.mutator") + local mutator = require('oil.mutator') if err or vim.bo[bufnr].modified or vim.b[bufnr].oil_dirty or mutator.is_mutating() then return end @@ -553,11 +553,11 @@ M.initialize = function(bufnr) end -- Watch for TextChanged and update the trash original path extmarks - if adapter and adapter.name == "trash" then + if adapter and adapter.name == 'trash' then local debounce_timer = assert(uv.new_timer()) local pending = false - vim.api.nvim_create_autocmd("TextChanged", { - desc = "Update oil virtual text of original path", + vim.api.nvim_create_autocmd('TextChanged', { + desc = 'Update oil virtual text of original path', buffer = bufnr, callback = function() -- Respond immediately to prevent flickering, the set the timer for a "cooldown period" @@ -583,14 +583,14 @@ M.initialize = function(bufnr) M.render_buffer_async(bufnr, {}, function(err) if err then vim.notify( - string.format("Error rendering oil buffer %s: %s", vim.api.nvim_buf_get_name(bufnr), err), + string.format('Error rendering oil buffer %s: %s', vim.api.nvim_buf_get_name(bufnr), err), vim.log.levels.ERROR ) else vim.b[bufnr].oil_ready = true vim.api.nvim_exec_autocmds( - "User", - { pattern = "OilEnter", modeline = false, data = { buf = bufnr } } + 'User', + { pattern = 'OilEnter', modeline = false, data = { buf = bufnr } } ) end end) @@ -606,12 +606,12 @@ local function get_sort_function(adapter, num_entries) -- If empty, default to type + name sorting if vim.tbl_isempty(sort_config) then - sort_config = { { "type", "asc" }, { "name", "asc" } } + sort_config = { { 'type', 'asc' }, { 'name', 'asc' } } end for _, sort_pair in ipairs(sort_config) do local col_name, order = unpack(sort_pair) - if order ~= "asc" and order ~= "desc" then + if order ~= 'asc' and order ~= 'desc' then vim.notify_once( string.format( "Column '%s' has invalid sort order '%s'. Should be either 'asc' or 'desc'", @@ -639,7 +639,7 @@ local function get_sort_function(adapter, num_entries) local a_val = get_sort_value(a) local b_val = get_sort_value(b) if a_val ~= b_val then - if order == "desc" then + if order == 'desc' then return a_val > b_val else return a_val < b_val @@ -663,7 +663,7 @@ local function render_buffer(bufnr, opts) return false end local bufname = vim.api.nvim_buf_get_name(bufnr) - opts = vim.tbl_extend("keep", opts or {}, { + opts = vim.tbl_extend('keep', opts or {}, { jump = false, jump_first = false, }) @@ -693,10 +693,10 @@ local function render_buffer(bufnr, opts) for i, col_def in ipairs(column_defs) do col_width[i + 1] = 1 local _, conf = util.split_config(col_def) - col_align[i + 1] = conf and conf.align or "left" + col_align[i + 1] = conf and conf.align or 'left' end - local parent_entry = { 0, "..", "directory" } + local parent_entry = { 0, '..', 'directory' } if M.should_display(bufnr, parent_entry) then local cols = M.format_entry_cols(parent_entry, column_defs, col_width, adapter, true, bufnr) table.insert(line_table, cols) @@ -732,7 +732,7 @@ local function render_buffer(bufnr, opts) if jump_idx then local lnum = jump_idx local line = vim.api.nvim_buf_get_lines(bufnr, lnum - 1, lnum, true)[1] - local id_str = line:match("^/(%d+)") + local id_str = line:match('^/(%d+)') local id = tonumber(id_str) if id then local entry = cache.get_entry_by_id(id) @@ -745,7 +745,7 @@ local function render_buffer(bufnr, opts) end end - constrain_cursor(bufnr, "name") + constrain_cursor(bufnr, 'name') end end end) @@ -760,13 +760,13 @@ end local function get_link_text(name, meta) local link_text if meta then - if meta.link_stat and meta.link_stat.type == "directory" then - name = name .. "/" + if meta.link_stat and meta.link_stat.type == 'directory' then + name = name .. '/' end if meta.link then - link_text = "-> " .. meta.link:gsub("\n", "") - if meta.link_stat and meta.link_stat.type == "directory" then + link_text = '-> ' .. meta.link:gsub('\n', '') + if meta.link_stat and meta.link_stat.type == 'directory' then link_text = util.addslash(link_text) end end @@ -786,15 +786,15 @@ end M.format_entry_cols = function(entry, column_defs, col_width, adapter, is_hidden, bufnr) local name = entry[FIELD_NAME] local meta = entry[FIELD_META] - local hl_suffix = "" + local hl_suffix = '' if is_hidden then - hl_suffix = "Hidden" + hl_suffix = 'Hidden' end if meta and meta.display_name then name = meta.display_name end -- We can't handle newlines in filenames (and shame on you for doing that) - name = name:gsub("\n", "") + name = name:gsub('\n', '') -- First put the unique ID local cols = {} local id_key = cache.format_id(entry[FIELD_ID]) @@ -803,7 +803,7 @@ M.format_entry_cols = function(entry, column_defs, col_width, adapter, is_hidden -- Then add all the configured columns for i, column in ipairs(column_defs) do local chunk = columns.render_col(adapter, column, entry, bufnr) - local text = type(chunk) == "table" and chunk[1] or chunk + local text = type(chunk) == 'table' and chunk[1] or chunk ---@cast text string col_width[i + 1] = math.max(col_width[i + 1], vim.api.nvim_strwidth(text)) table.insert(cols, chunk) @@ -816,7 +816,7 @@ M.format_entry_cols = function(entry, column_defs, col_width, adapter, is_hidden if get_custom_hl then local external_entry = util.export_entry(entry) - if entry_type == "link" then + if entry_type == 'link' then link_name, link_target = get_link_text(name, meta) local is_orphan = not (meta and meta.link_stat) link_name_hl = get_custom_hl(external_entry, is_hidden, false, is_orphan, bufnr) @@ -830,8 +830,8 @@ M.format_entry_cols = function(entry, column_defs, col_width, adapter, is_hidden local hl = get_custom_hl(external_entry, is_hidden, false, false, bufnr) if hl then -- Add the trailing / if this is a directory, this is important - if entry_type == "directory" then - name = name .. "/" + if entry_type == 'directory' then + name = name .. '/' end table.insert(cols, { name, hl }) return cols @@ -840,49 +840,50 @@ M.format_entry_cols = function(entry, column_defs, col_width, adapter, is_hidden end local highlight_as_executable = false - if entry_type ~= "directory" then + if entry_type ~= 'directory' then local lower = name:lower() if - lower:match("%.exe$") - or lower:match("%.bat$") - or lower:match("%.cmd$") - or lower:match("%.com$") - or lower:match("%.ps1$") + lower:match('%.exe$') + or lower:match('%.bat$') + or lower:match('%.cmd$') + or lower:match('%.com$') + or lower:match('%.ps1$') then highlight_as_executable = true + -- selene: allow(if_same_then_else) elseif is_unix_executable(entry) then highlight_as_executable = true end end - if entry_type == "directory" then - table.insert(cols, { name .. "/", "OilDir" .. hl_suffix }) - elseif entry_type == "socket" then - table.insert(cols, { name, "OilSocket" .. hl_suffix }) - elseif entry_type == "link" then + if entry_type == 'directory' then + table.insert(cols, { name .. '/', 'OilDir' .. hl_suffix }) + elseif entry_type == 'socket' then + table.insert(cols, { name, 'OilSocket' .. hl_suffix }) + elseif entry_type == 'link' then if not link_name then link_name, link_target = get_link_text(name, meta) end local is_orphan = not (meta and meta.link_stat) if not link_name_hl then if highlight_as_executable then - link_name_hl = "OilExecutable" .. hl_suffix + link_name_hl = 'OilExecutable' .. hl_suffix else - link_name_hl = (is_orphan and "OilOrphanLink" or "OilLink") .. hl_suffix + link_name_hl = (is_orphan and 'OilOrphanLink' or 'OilLink') .. hl_suffix end end table.insert(cols, { link_name, link_name_hl }) if link_target then if not link_target_hl then - link_target_hl = (is_orphan and "OilOrphanLinkTarget" or "OilLinkTarget") .. hl_suffix + link_target_hl = (is_orphan and 'OilOrphanLinkTarget' or 'OilLinkTarget') .. hl_suffix end table.insert(cols, { link_target, link_target_hl }) end elseif highlight_as_executable then - table.insert(cols, { name, "OilExecutable" .. hl_suffix }) + table.insert(cols, { name, 'OilExecutable' .. hl_suffix }) else - table.insert(cols, { name, "OilFile" .. hl_suffix }) + table.insert(cols, { name, 'OilFile' .. hl_suffix }) end return cols @@ -914,8 +915,8 @@ M.render_buffer_async = function(bufnr, opts, caller_callback) local function callback(err) if not err then vim.api.nvim_exec_autocmds( - "User", - { pattern = "OilReadPost", modeline = false, data = { buf = bufnr } } + 'User', + { pattern = 'OilReadPost', modeline = false, data = { buf = bufnr } } ) end if caller_callback then @@ -923,7 +924,7 @@ M.render_buffer_async = function(bufnr, opts, caller_callback) end end - opts = vim.tbl_deep_extend("keep", opts or {}, { + opts = vim.tbl_deep_extend('keep', opts or {}, { refetch = true, }) ---@cast opts -nil @@ -949,8 +950,8 @@ M.render_buffer_async = function(bufnr, opts, caller_callback) vim.bo[bufnr].undolevels = -1 local handle_error = vim.schedule_wrap(function(message) vim.b[bufnr].oil_rendering = false - vim.bo[bufnr].undolevels = vim.api.nvim_get_option_value("undolevels", { scope = "global" }) - util.render_text(bufnr, { "Error: " .. message }) + vim.bo[bufnr].undolevels = vim.api.nvim_get_option_value('undolevels', { scope = 'global' }) + util.render_text(bufnr, { 'Error: ' .. message }) if pending_renders[bufnr] then for _, cb in ipairs(pending_renders[bufnr]) do cb(message) @@ -987,7 +988,7 @@ M.render_buffer_async = function(bufnr, opts, caller_callback) loading.set_loading(bufnr, false) render_buffer(bufnr, { jump = true }) M.set_last_cursor(bufname, nil) - vim.bo[bufnr].undolevels = vim.api.nvim_get_option_value("undolevels", { scope = "global" }) + vim.bo[bufnr].undolevels = vim.api.nvim_get_option_value('undolevels', { scope = 'global' }) vim.bo[bufnr].modifiable = not buffers_locked and adapter.is_modifiable(bufnr) if callback then callback() diff --git a/lua/resession/extensions/oil.lua b/lua/resession/extensions/oil.lua index 427843d..b3ba754 100644 --- a/lua/resession/extensions/oil.lua +++ b/lua/resession/extensions/oil.lua @@ -1,7 +1,7 @@ local M = {} M.is_win_supported = function(winid, bufnr) - return vim.bo[bufnr].filetype == "oil" + return vim.bo[bufnr].filetype == 'oil' end M.save_win = function(winid) @@ -11,7 +11,7 @@ M.save_win = function(winid) end M.load_win = function(winid, config) - require("oil").open(config.bufname) + require('oil').open(config.bufname) end return M diff --git a/perf/bootstrap.lua b/perf/bootstrap.lua index 5f10c06..19e17e8 100644 --- a/perf/bootstrap.lua +++ b/perf/bootstrap.lua @@ -1,7 +1,7 @@ -vim.opt.runtimepath:prepend("scripts/benchmark.nvim") -vim.opt.runtimepath:prepend(".") +vim.opt.runtimepath:prepend('scripts/benchmark.nvim') +vim.opt.runtimepath:prepend('.') -local bm = require("benchmark") +local bm = require('benchmark') bm.sandbox() ---@module 'oil' @@ -14,50 +14,53 @@ local DIR_SIZE = tonumber(vim.env.DIR_SIZE) or 100000 local ITERATIONS = tonumber(vim.env.ITERATIONS) or 10 local WARM_UP = tonumber(vim.env.WARM_UP) or 1 local OUTLIERS = tonumber(vim.env.OUTLIERS) or math.floor(ITERATIONS / 10) -local TEST_DIR = "perf/tmp/test_" .. DIR_SIZE +local TEST_DIR = 'perf/tmp/test_' .. DIR_SIZE -vim.fn.mkdir(TEST_DIR, "p") -require("benchmark.files").create_files(TEST_DIR, "file %d.txt", DIR_SIZE) +vim.fn.mkdir(TEST_DIR, 'p') +require('benchmark.files').create_files(TEST_DIR, 'file %d.txt', DIR_SIZE) +-- selene: allow(global_usage) function _G.jit_profile() - require("oil").setup(setup_opts) - local finish = bm.jit_profile({ filename = TEST_DIR .. "/profile.txt" }) - bm.wait_for_user_event("OilEnter", function() + require('oil').setup(setup_opts) + local finish = bm.jit_profile({ filename = TEST_DIR .. '/profile.txt' }) + bm.wait_for_user_event('OilEnter', function() finish() end) - require("oil").open(TEST_DIR) + require('oil').open(TEST_DIR) end +-- selene: allow(global_usage) function _G.flame_profile() local start, stop = bm.flame_profile({ - pattern = "oil*", - filename = "profile.json", + pattern = 'oil*', + filename = 'profile.json', }) - require("oil").setup(setup_opts) + require('oil').setup(setup_opts) start() - bm.wait_for_user_event("OilEnter", function() + bm.wait_for_user_event('OilEnter', function() stop(function() vim.cmd.qall({ mods = { silent = true } }) end) end) - require("oil").open(TEST_DIR) + require('oil').open(TEST_DIR) end +-- selene: allow(global_usage) function _G.benchmark() - require("oil").setup(setup_opts) - bm.run({ title = "oil.nvim", iterations = ITERATIONS, warm_up = WARM_UP }, function(callback) - bm.wait_for_user_event("OilEnter", callback) - require("oil").open(TEST_DIR) + require('oil').setup(setup_opts) + bm.run({ title = 'oil.nvim', iterations = ITERATIONS, warm_up = WARM_UP }, function(callback) + bm.wait_for_user_event('OilEnter', callback) + require('oil').open(TEST_DIR) end, function(times) local avg = bm.avg(times, { trim_outliers = OUTLIERS }) local std_dev = bm.std_dev(times, { trim_outliers = OUTLIERS }) local lines = { - table.concat(vim.tbl_map(bm.format_time, times), " "), - string.format("Average: %s", bm.format_time(avg)), - string.format("Std deviation: %s", bm.format_time(std_dev)), + table.concat(vim.tbl_map(bm.format_time, times), ' '), + string.format('Average: %s', bm.format_time(avg)), + string.format('Std deviation: %s', bm.format_time(std_dev)), } - vim.fn.writefile(lines, "perf/tmp/benchmark.txt") + vim.fn.writefile(lines, 'perf/tmp/benchmark.txt') vim.cmd.qall({ mods = { silent = true } }) end) end diff --git a/plugin/oil.lua b/plugin/oil.lua index 2b1c352..bcb530d 100644 --- a/plugin/oil.lua +++ b/plugin/oil.lua @@ -1,3 +1,3 @@ if vim.g.oil ~= nil then - require("oil").setup() + require('oil').setup() end diff --git a/selene.toml b/selene.toml new file mode 100644 index 0000000..ab57300 --- /dev/null +++ b/selene.toml @@ -0,0 +1,5 @@ +std = 'vim' + +[lints] +mixed_table = 'allow' +unused_variable = 'allow' diff --git a/tests/altbuf_spec.lua b/tests/altbuf_spec.lua index beece15..1f03ffb 100644 --- a/tests/altbuf_spec.lua +++ b/tests/altbuf_spec.lua @@ -1,157 +1,157 @@ -require("plenary.async").tests.add_to_env() -local fs = require("oil.fs") -local oil = require("oil") -local test_util = require("tests.test_util") +require('plenary.async').tests.add_to_env() +local fs = require('oil.fs') +local oil = require('oil') +local test_util = require('tests.test_util') -a.describe("Alternate buffer", function() +a.describe('Alternate buffer', function() after_each(function() test_util.reset_editor() end) - a.it("sets previous buffer as alternate", function() - vim.cmd.edit({ args = { "foo" } }) + a.it('sets previous buffer as alternate', function() + vim.cmd.edit({ args = { 'foo' } }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - vim.cmd.edit({ args = { "bar" } }) - assert.equals("foo", vim.fn.expand("#")) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + vim.cmd.edit({ args = { 'bar' } }) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("sets previous buffer as alternate when editing url file", function() - vim.cmd.edit({ args = { "foo" } }) + a.it('sets previous buffer as alternate when editing url file', function() + vim.cmd.edit({ args = { 'foo' } }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - local readme = fs.join(vim.fn.getcwd(), "README.md") - vim.cmd.edit({ args = { "oil://" .. fs.os_to_posix_path(readme) } }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + local readme = fs.join(vim.fn.getcwd(), 'README.md') + vim.cmd.edit({ args = { 'oil://' .. fs.os_to_posix_path(readme) } }) -- We're gonna jump around to 2 different buffers - test_util.wait_for_autocmd("BufEnter") - test_util.wait_for_autocmd("BufEnter") + test_util.wait_for_autocmd('BufEnter') + test_util.wait_for_autocmd('BufEnter') assert.equals(readme, vim.api.nvim_buf_get_name(0)) - assert.equals("foo", vim.fn.expand("#")) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("sets previous buffer as alternate when editing oil://", function() - vim.cmd.edit({ args = { "foo" } }) - vim.cmd.edit({ args = { "oil://" .. fs.os_to_posix_path(vim.fn.getcwd()) } }) - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - vim.cmd.edit({ args = { "bar" } }) - assert.equals("foo", vim.fn.expand("#")) + a.it('sets previous buffer as alternate when editing oil://', function() + vim.cmd.edit({ args = { 'foo' } }) + vim.cmd.edit({ args = { 'oil://' .. fs.os_to_posix_path(vim.fn.getcwd()) } }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + vim.cmd.edit({ args = { 'bar' } }) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("preserves alternate buffer if editing the same file", function() - vim.cmd.edit({ args = { "foo" } }) - vim.cmd.edit({ args = { "bar" } }) + a.it('preserves alternate buffer if editing the same file', function() + vim.cmd.edit({ args = { 'foo' } }) + vim.cmd.edit({ args = { 'bar' } }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - vim.cmd.edit({ args = { "bar" } }) - assert.equals("foo", vim.fn.expand("#")) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + vim.cmd.edit({ args = { 'bar' } }) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("preserves alternate buffer if discarding changes", function() - vim.cmd.edit({ args = { "foo" } }) - vim.cmd.edit({ args = { "bar" } }) + a.it('preserves alternate buffer if discarding changes', function() + vim.cmd.edit({ args = { 'foo' } }) + vim.cmd.edit({ args = { 'bar' } }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) oil.close() - assert.equals("bar", vim.fn.expand("%")) - assert.equals("foo", vim.fn.expand("#")) + assert.equals('bar', vim.fn.expand('%')) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("sets previous buffer as alternate after multi-dir hops", function() - vim.cmd.edit({ args = { "foo" } }) + a.it('sets previous buffer as alternate after multi-dir hops', function() + vim.cmd.edit({ args = { 'foo' } }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - vim.cmd.edit({ args = { "bar" } }) - assert.equals("foo", vim.fn.expand("#")) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + vim.cmd.edit({ args = { 'bar' } }) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("sets previous buffer as alternate when inside oil buffer", function() - vim.cmd.edit({ args = { "foo" } }) + a.it('sets previous buffer as alternate when inside oil buffer', function() + vim.cmd.edit({ args = { 'foo' } }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("foo", vim.fn.expand("#")) - vim.cmd.edit({ args = { "bar" } }) - assert.equals("foo", vim.fn.expand("#")) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('foo', vim.fn.expand('#')) + vim.cmd.edit({ args = { 'bar' } }) + assert.equals('foo', vim.fn.expand('#')) oil.open() - assert.equals("bar", vim.fn.expand("#")) + assert.equals('bar', vim.fn.expand('#')) end) - a.it("preserves alternate when traversing oil dirs", function() - vim.cmd.edit({ args = { "foo" } }) + a.it('preserves alternate when traversing oil dirs', function() + vim.cmd.edit({ args = { 'foo' } }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("foo", vim.fn.expand("#")) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('foo', vim.fn.expand('#')) vim.wait(1000, function() return oil.get_cursor_entry() end, 10) vim.api.nvim_win_set_cursor(0, { 1, 1 }) oil.select() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("foo", vim.fn.expand("#")) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("preserves alternate when opening preview", function() - vim.cmd.edit({ args = { "foo" } }) + a.it('preserves alternate when opening preview', function() + vim.cmd.edit({ args = { 'foo' } }) oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("foo", vim.fn.expand("#")) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('foo', vim.fn.expand('#')) vim.wait(1000, function() return oil.get_cursor_entry() end, 10) vim.api.nvim_win_set_cursor(0, { 1, 1 }) oil.open_preview() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("foo", vim.fn.expand("#")) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('foo', vim.fn.expand('#')) end) - a.describe("floating window", function() - a.it("sets previous buffer as alternate", function() - vim.cmd.edit({ args = { "foo" } }) + a.describe('floating window', function() + a.it('sets previous buffer as alternate', function() + vim.cmd.edit({ args = { 'foo' } }) oil.open_float() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) -- This is lazy, but testing the actual select logic is more difficult. We can simply -- replicate it by closing the current window and then doing the edit vim.api.nvim_win_close(0, true) - vim.cmd.edit({ args = { "bar" } }) - assert.equals("foo", vim.fn.expand("#")) + vim.cmd.edit({ args = { 'bar' } }) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("preserves alternate buffer if editing the same file", function() - vim.cmd.edit({ args = { "foo" } }) - vim.cmd.edit({ args = { "bar" } }) + a.it('preserves alternate buffer if editing the same file', function() + vim.cmd.edit({ args = { 'foo' } }) + vim.cmd.edit({ args = { 'bar' } }) oil.open_float() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) -- This is lazy, but testing the actual select logic is more difficult. We can simply -- replicate it by closing the current window and then doing the edit vim.api.nvim_win_close(0, true) - vim.cmd.edit({ args = { "bar" } }) - assert.equals("foo", vim.fn.expand("#")) + vim.cmd.edit({ args = { 'bar' } }) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("preserves alternate buffer if discarding changes", function() - vim.cmd.edit({ args = { "foo" } }) - vim.cmd.edit({ args = { "bar" } }) + a.it('preserves alternate buffer if discarding changes', function() + vim.cmd.edit({ args = { 'foo' } }) + vim.cmd.edit({ args = { 'bar' } }) oil.open_float() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) oil.close() - assert.equals("foo", vim.fn.expand("#")) + assert.equals('foo', vim.fn.expand('#')) end) - a.it("preserves alternate when traversing to a new file", function() - vim.cmd.edit({ args = { "foo" } }) + a.it('preserves alternate when traversing to a new file', function() + vim.cmd.edit({ args = { 'foo' } }) oil.open_float() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("foo", vim.fn.expand("#")) - test_util.feedkeys({ "/LICENSE" }, 10) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('foo', vim.fn.expand('#')) + test_util.feedkeys({ '/LICENSE' }, 10) oil.select() - test_util.wait_for_autocmd("BufEnter") - assert.equals("LICENSE", vim.fn.expand("%:.")) - assert.equals("foo", vim.fn.expand("#")) + test_util.wait_for_autocmd('BufEnter') + assert.equals('LICENSE', vim.fn.expand('%:.')) + assert.equals('foo', vim.fn.expand('#')) end) end) end) diff --git a/tests/close_spec.lua b/tests/close_spec.lua index ff14738..61a1e13 100644 --- a/tests/close_spec.lua +++ b/tests/close_spec.lua @@ -1,8 +1,8 @@ -require("plenary.async").tests.add_to_env() -local oil = require("oil") -local test_util = require("tests.test_util") +require('plenary.async').tests.add_to_env() +local oil = require('oil') +local test_util = require('tests.test_util') -a.describe("close", function() +a.describe('close', function() a.before_each(function() test_util.reset_editor() end) @@ -10,36 +10,36 @@ a.describe("close", function() test_util.reset_editor() end) - a.it("does not close buffer from visual mode", function() + a.it('does not close buffer from visual mode', function() oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("oil", vim.bo.filetype) - test_util.feedkeys({ "V" }, 10) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('oil', vim.bo.filetype) + test_util.feedkeys({ 'V' }, 10) oil.close() - assert.equals("oil", vim.bo.filetype) - test_util.feedkeys({ "" }, 10) + assert.equals('oil', vim.bo.filetype) + test_util.feedkeys({ '' }, 10) end) - a.it("does not close buffer from operator-pending mode", function() + a.it('does not close buffer from operator-pending mode', function() oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("oil", vim.bo.filetype) - vim.api.nvim_feedkeys("d", "n", false) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('oil', vim.bo.filetype) + vim.api.nvim_feedkeys('d', 'n', false) a.util.sleep(20) local mode = vim.api.nvim_get_mode().mode - if mode:match("^no") then + if mode:match('^no') then oil.close() - assert.equals("oil", vim.bo.filetype) + assert.equals('oil', vim.bo.filetype) end - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("", true, true, true), "n", false) + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, true, true), 'n', false) a.util.sleep(20) end) - a.it("closes buffer from normal mode", function() + a.it('closes buffer from normal mode', function() oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("oil", vim.bo.filetype) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('oil', vim.bo.filetype) oil.close() - assert.not_equals("oil", vim.bo.filetype) + assert.not_equals('oil', vim.bo.filetype) end) end) diff --git a/tests/config_spec.lua b/tests/config_spec.lua index aac4eb1..c565c72 100644 --- a/tests/config_spec.lua +++ b/tests/config_spec.lua @@ -1,25 +1,25 @@ -local config = require("oil.config") +local config = require('oil.config') -describe("config", function() +describe('config', function() after_each(function() vim.g.oil = nil end) - it("falls back to vim.g.oil when setup() is called with no args", function() + it('falls back to vim.g.oil when setup() is called with no args', function() vim.g.oil = { delete_to_trash = true, cleanup_delay_ms = 5000 } config.setup() assert.is_true(config.delete_to_trash) assert.equals(5000, config.cleanup_delay_ms) end) - it("uses defaults when neither opts nor vim.g.oil is set", function() + it('uses defaults when neither opts nor vim.g.oil is set', function() vim.g.oil = nil config.setup() assert.is_false(config.delete_to_trash) assert.equals(2000, config.cleanup_delay_ms) end) - it("prefers explicit opts over vim.g.oil", function() + it('prefers explicit opts over vim.g.oil', function() vim.g.oil = { delete_to_trash = true } config.setup({ delete_to_trash = false }) assert.is_false(config.delete_to_trash) diff --git a/tests/files_spec.lua b/tests/files_spec.lua index 4333d80..ae07ef8 100644 --- a/tests/files_spec.lua +++ b/tests/files_spec.lua @@ -1,9 +1,9 @@ -require("plenary.async").tests.add_to_env() -local TmpDir = require("tests.tmpdir") -local files = require("oil.adapters.files") -local test_util = require("tests.test_util") +require('plenary.async').tests.add_to_env() +local TmpDir = require('tests.tmpdir') +local files = require('oil.adapters.files') +local test_util = require('tests.test_util') -a.describe("files adapter", function() +a.describe('files adapter', function() local tmpdir a.before_each(function() tmpdir = TmpDir.new() @@ -15,159 +15,159 @@ a.describe("files adapter", function() test_util.reset_editor() end) - a.it("tmpdir creates files and asserts they exist", function() - tmpdir:create({ "a.txt", "foo/b.txt", "foo/c.txt", "bar/" }) + a.it('tmpdir creates files and asserts they exist', function() + tmpdir:create({ 'a.txt', 'foo/b.txt', 'foo/c.txt', 'bar/' }) tmpdir:assert_fs({ - ["a.txt"] = "a.txt", - ["foo/b.txt"] = "foo/b.txt", - ["foo/c.txt"] = "foo/c.txt", - ["bar/"] = true, + ['a.txt'] = 'a.txt', + ['foo/b.txt'] = 'foo/b.txt', + ['foo/c.txt'] = 'foo/c.txt', + ['bar/'] = true, }) end) - a.it("Creates files", function() + a.it('Creates files', function() local err = a.wrap(files.perform_action, 2)({ - url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a.txt", - entry_type = "file", - type = "create", + url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt', + entry_type = 'file', + type = 'create', }) assert.is_nil(err) tmpdir:assert_fs({ - ["a.txt"] = "", + ['a.txt'] = '', }) end) - a.it("Creates directories", function() + a.it('Creates directories', function() local err = a.wrap(files.perform_action, 2)({ - url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a", - entry_type = "directory", - type = "create", + url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a', + entry_type = 'directory', + type = 'create', }) assert.is_nil(err) tmpdir:assert_fs({ - ["a/"] = true, + ['a/'] = true, }) end) - a.it("Deletes files", function() - tmpdir:create({ "a.txt" }) + a.it('Deletes files', function() + tmpdir:create({ 'a.txt' }) a.util.scheduler() - local url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a.txt" + local url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' local err = a.wrap(files.perform_action, 2)({ url = url, - entry_type = "file", - type = "delete", + entry_type = 'file', + type = 'delete', }) assert.is_nil(err) tmpdir:assert_fs({}) end) - a.it("Deletes directories", function() - tmpdir:create({ "a/" }) - local url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a" + a.it('Deletes directories', function() + tmpdir:create({ 'a/' }) + local url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' local err = a.wrap(files.perform_action, 2)({ url = url, - entry_type = "directory", - type = "delete", + entry_type = 'directory', + type = 'delete', }) assert.is_nil(err) tmpdir:assert_fs({}) end) - a.it("Moves files", function() - tmpdir:create({ "a.txt" }) + a.it('Moves files', function() + tmpdir:create({ 'a.txt' }) a.util.scheduler() - local src_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a.txt" - local dest_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "b.txt" + local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' + local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b.txt' local err = a.wrap(files.perform_action, 2)({ src_url = src_url, dest_url = dest_url, - entry_type = "file", - type = "move", + entry_type = 'file', + type = 'move', }) assert.is_nil(err) tmpdir:assert_fs({ - ["b.txt"] = "a.txt", + ['b.txt'] = 'a.txt', }) end) - a.it("Moves directories", function() - tmpdir:create({ "a/a.txt" }) + a.it('Moves directories', function() + tmpdir:create({ 'a/a.txt' }) a.util.scheduler() - local src_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a" - local dest_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "b" + local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' + local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b' local err = a.wrap(files.perform_action, 2)({ src_url = src_url, dest_url = dest_url, - entry_type = "directory", - type = "move", + entry_type = 'directory', + type = 'move', }) assert.is_nil(err) tmpdir:assert_fs({ - ["b/a.txt"] = "a/a.txt", - ["b/"] = true, + ['b/a.txt'] = 'a/a.txt', + ['b/'] = true, }) end) - a.it("Copies files", function() - tmpdir:create({ "a.txt" }) + a.it('Copies files', function() + tmpdir:create({ 'a.txt' }) a.util.scheduler() - local src_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a.txt" - local dest_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "b.txt" + local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' + local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b.txt' local err = a.wrap(files.perform_action, 2)({ src_url = src_url, dest_url = dest_url, - entry_type = "file", - type = "copy", + entry_type = 'file', + type = 'copy', }) assert.is_nil(err) tmpdir:assert_fs({ - ["a.txt"] = "a.txt", - ["b.txt"] = "a.txt", + ['a.txt'] = 'a.txt', + ['b.txt'] = 'a.txt', }) end) - a.it("Recursively copies directories", function() - tmpdir:create({ "a/a.txt" }) + a.it('Recursively copies directories', function() + tmpdir:create({ 'a/a.txt' }) a.util.scheduler() - local src_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a" - local dest_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "b" + local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' + local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b' local err = a.wrap(files.perform_action, 2)({ src_url = src_url, dest_url = dest_url, - entry_type = "directory", - type = "copy", + entry_type = 'directory', + type = 'copy', }) assert.is_nil(err) tmpdir:assert_fs({ - ["b/a.txt"] = "a/a.txt", - ["b/"] = true, - ["a/a.txt"] = "a/a.txt", - ["a/"] = true, + ['b/a.txt'] = 'a/a.txt', + ['b/'] = true, + ['a/a.txt'] = 'a/a.txt', + ['a/'] = true, }) end) - a.it("Editing a new oil://path/ creates an oil buffer", function() - local tmpdir_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "/" + a.it('Editing a new oil://path/ creates an oil buffer', function() + local tmpdir_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. '/' vim.cmd.edit({ args = { tmpdir_url } }) test_util.wait_oil_ready() - local new_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "newdir" + local new_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'newdir' vim.cmd.edit({ args = { new_url } }) test_util.wait_oil_ready() - assert.equals("oil", vim.bo.filetype) + assert.equals('oil', vim.bo.filetype) -- The normalization will add a '/' - assert.equals(new_url .. "/", vim.api.nvim_buf_get_name(0)) + assert.equals(new_url .. '/', vim.api.nvim_buf_get_name(0)) end) - a.it("Editing a new oil://file.rb creates a normal buffer", function() - local tmpdir_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "/" + a.it('Editing a new oil://file.rb creates a normal buffer', function() + local tmpdir_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. '/' vim.cmd.edit({ args = { tmpdir_url } }) - test_util.wait_for_autocmd("BufReadPost") - local new_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "file.rb" + test_util.wait_for_autocmd('BufReadPost') + local new_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'file.rb' vim.cmd.edit({ args = { new_url } }) - test_util.wait_for_autocmd("BufReadPost") - assert.equals("ruby", vim.bo.filetype) - assert.equals(vim.fn.fnamemodify(tmpdir.path, ":p") .. "file.rb", vim.api.nvim_buf_get_name(0)) - assert.equals(tmpdir.path .. "/file.rb", vim.fn.bufname()) + test_util.wait_for_autocmd('BufReadPost') + assert.equals('ruby', vim.bo.filetype) + assert.equals(vim.fn.fnamemodify(tmpdir.path, ':p') .. 'file.rb', vim.api.nvim_buf_get_name(0)) + assert.equals(tmpdir.path .. '/file.rb', vim.fn.bufname()) end) end) diff --git a/tests/manual_progress.lua b/tests/manual_progress.lua index bb838e2..593a748 100644 --- a/tests/manual_progress.lua +++ b/tests/manual_progress.lua @@ -1,5 +1,5 @@ -- Manual test for minimizing/restoring progress window -local Progress = require("oil.mutator.progress") +local Progress = require('oil.mutator.progress') local progress = Progress.new() @@ -12,9 +12,9 @@ progress:show({ for i = 1, 10, 1 do vim.defer_fn(function() progress:set_action({ - type = "create", - url = string.format("oil:///tmp/test_%d.txt", i), - entry_type = "file", + type = 'create', + url = string.format('oil:///tmp/test_%d.txt', i), + entry_type = 'file', }, i, 10) end, (i - 1) * 1000) end @@ -23,6 +23,6 @@ vim.defer_fn(function() progress:close() end, 10000) -vim.keymap.set("n", "R", function() +vim.keymap.set('n', 'R', function() progress:restore() end, {}) diff --git a/tests/minimal_init.lua b/tests/minimal_init.lua index 70a66b1..8db9e9a 100644 --- a/tests/minimal_init.lua +++ b/tests/minimal_init.lua @@ -1,5 +1,5 @@ -vim.opt.runtimepath:append(".") +vim.opt.runtimepath:append('.') vim.o.swapfile = false vim.bo.swapfile = false -require("tests.test_util").reset_editor() +require('tests.test_util').reset_editor() diff --git a/tests/move_rename_spec.lua b/tests/move_rename_spec.lua index 660ab64..16eb763 100644 --- a/tests/move_rename_spec.lua +++ b/tests/move_rename_spec.lua @@ -1,59 +1,59 @@ -local fs = require("oil.fs") -local test_util = require("tests.test_util") -local util = require("oil.util") +local fs = require('oil.fs') +local test_util = require('tests.test_util') +local util = require('oil.util') -describe("update_moved_buffers", function() +describe('update_moved_buffers', function() after_each(function() test_util.reset_editor() end) - it("Renames moved buffers", function() - vim.cmd.edit({ args = { "oil-test:///foo/bar.txt" } }) - util.update_moved_buffers("file", "oil-test:///foo/bar.txt", "oil-test:///foo/baz.txt") - assert.equals("oil-test:///foo/baz.txt", vim.api.nvim_buf_get_name(0)) + it('Renames moved buffers', function() + vim.cmd.edit({ args = { 'oil-test:///foo/bar.txt' } }) + util.update_moved_buffers('file', 'oil-test:///foo/bar.txt', 'oil-test:///foo/baz.txt') + assert.equals('oil-test:///foo/baz.txt', vim.api.nvim_buf_get_name(0)) end) - it("Renames moved buffers when they are normal files", function() - local tmpdir = fs.join(vim.loop.fs_realpath(vim.fn.stdpath("cache")), "oil", "test") - local testfile = fs.join(tmpdir, "foo.txt") + it('Renames moved buffers when they are normal files', function() + local tmpdir = fs.join(vim.loop.fs_realpath(vim.fn.stdpath('cache')), 'oil', 'test') + local testfile = fs.join(tmpdir, 'foo.txt') vim.cmd.edit({ args = { testfile } }) util.update_moved_buffers( - "file", - "oil://" .. fs.os_to_posix_path(testfile), - "oil://" .. fs.os_to_posix_path(fs.join(tmpdir, "bar.txt")) + 'file', + 'oil://' .. fs.os_to_posix_path(testfile), + 'oil://' .. fs.os_to_posix_path(fs.join(tmpdir, 'bar.txt')) ) - assert.equals(fs.join(tmpdir, "bar.txt"), vim.api.nvim_buf_get_name(0)) + assert.equals(fs.join(tmpdir, 'bar.txt'), vim.api.nvim_buf_get_name(0)) end) - it("Renames directories", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) - util.update_moved_buffers("directory", "oil-test:///foo/", "oil-test:///bar/") - assert.equals("oil-test:///bar/", vim.api.nvim_buf_get_name(0)) + it('Renames directories', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + util.update_moved_buffers('directory', 'oil-test:///foo/', 'oil-test:///bar/') + assert.equals('oil-test:///bar/', vim.api.nvim_buf_get_name(0)) end) - it("Renames subdirectories", function() - vim.cmd.edit({ args = { "oil-test:///foo/bar/" } }) - util.update_moved_buffers("directory", "oil-test:///foo/", "oil-test:///baz/") - assert.equals("oil-test:///baz/bar/", vim.api.nvim_buf_get_name(0)) + it('Renames subdirectories', function() + vim.cmd.edit({ args = { 'oil-test:///foo/bar/' } }) + util.update_moved_buffers('directory', 'oil-test:///foo/', 'oil-test:///baz/') + assert.equals('oil-test:///baz/bar/', vim.api.nvim_buf_get_name(0)) end) - it("Renames subfiles", function() - vim.cmd.edit({ args = { "oil-test:///foo/bar.txt" } }) - util.update_moved_buffers("directory", "oil-test:///foo/", "oil-test:///baz/") - assert.equals("oil-test:///baz/bar.txt", vim.api.nvim_buf_get_name(0)) + it('Renames subfiles', function() + vim.cmd.edit({ args = { 'oil-test:///foo/bar.txt' } }) + util.update_moved_buffers('directory', 'oil-test:///foo/', 'oil-test:///baz/') + assert.equals('oil-test:///baz/bar.txt', vim.api.nvim_buf_get_name(0)) end) - it("Renames subfiles when they are normal files", function() - local tmpdir = fs.join(vim.loop.fs_realpath(vim.fn.stdpath("cache")), "oil", "test") - local foo = fs.join(tmpdir, "foo") - local bar = fs.join(tmpdir, "bar") - local testfile = fs.join(foo, "foo.txt") + it('Renames subfiles when they are normal files', function() + local tmpdir = fs.join(vim.loop.fs_realpath(vim.fn.stdpath('cache')), 'oil', 'test') + local foo = fs.join(tmpdir, 'foo') + local bar = fs.join(tmpdir, 'bar') + local testfile = fs.join(foo, 'foo.txt') vim.cmd.edit({ args = { testfile } }) util.update_moved_buffers( - "directory", - "oil://" .. fs.os_to_posix_path(foo), - "oil://" .. fs.os_to_posix_path(bar) + 'directory', + 'oil://' .. fs.os_to_posix_path(foo), + 'oil://' .. fs.os_to_posix_path(bar) ) - assert.equals(fs.join(bar, "foo.txt"), vim.api.nvim_buf_get_name(0)) + assert.equals(fs.join(bar, 'foo.txt'), vim.api.nvim_buf_get_name(0)) end) end) diff --git a/tests/mutator_spec.lua b/tests/mutator_spec.lua index 17548d3..0bddaab 100644 --- a/tests/mutator_spec.lua +++ b/tests/mutator_spec.lua @@ -1,22 +1,22 @@ -require("plenary.async").tests.add_to_env() -local cache = require("oil.cache") -local constants = require("oil.constants") -local mutator = require("oil.mutator") -local test_adapter = require("oil.adapters.test") -local test_util = require("tests.test_util") +require('plenary.async').tests.add_to_env() +local cache = require('oil.cache') +local constants = require('oil.constants') +local mutator = require('oil.mutator') +local test_adapter = require('oil.adapters.test') +local test_util = require('tests.test_util') local FIELD_ID = constants.FIELD_ID local FIELD_NAME = constants.FIELD_NAME local FIELD_TYPE = constants.FIELD_TYPE -a.describe("mutator", function() +a.describe('mutator', function() after_each(function() test_util.reset_editor() end) - describe("build actions", function() - it("empty diffs produce no actions", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + describe('build actions', function() + it('empty diffs produce no actions', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local actions = mutator.create_actions_from_diffs({ [bufnr] = {}, @@ -24,320 +24,320 @@ a.describe("mutator", function() assert.are.same({}, actions) end) - it("constructs CREATE actions", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('constructs CREATE actions', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { - { type = "new", name = "a.txt", entry_type = "file" }, + { type = 'new', name = 'a.txt', entry_type = 'file' }, } local actions = mutator.create_actions_from_diffs({ [bufnr] = diffs, }) assert.are.same({ { - type = "create", - entry_type = "file", - url = "oil-test:///foo/a.txt", + type = 'create', + entry_type = 'file', + url = 'oil-test:///foo/a.txt', }, }, actions) end) - it("constructs DELETE actions", function() - local file = test_adapter.test_set("/foo/a.txt", "file") - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('constructs DELETE actions', function() + local file = test_adapter.test_set('/foo/a.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { - { type = "delete", name = "a.txt", id = file[FIELD_ID] }, + { type = 'delete', name = 'a.txt', id = file[FIELD_ID] }, } local actions = mutator.create_actions_from_diffs({ [bufnr] = diffs, }) assert.are.same({ { - type = "delete", - entry_type = "file", - url = "oil-test:///foo/a.txt", + type = 'delete', + entry_type = 'file', + url = 'oil-test:///foo/a.txt', }, }, actions) end) - it("constructs COPY actions", function() - local file = test_adapter.test_set("/foo/a.txt", "file") - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('constructs COPY actions', function() + local file = test_adapter.test_set('/foo/a.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { - { type = "new", name = "b.txt", entry_type = "file", id = file[FIELD_ID] }, + { type = 'new', name = 'b.txt', entry_type = 'file', id = file[FIELD_ID] }, } local actions = mutator.create_actions_from_diffs({ [bufnr] = diffs, }) assert.are.same({ { - type = "copy", - entry_type = "file", - src_url = "oil-test:///foo/a.txt", - dest_url = "oil-test:///foo/b.txt", + type = 'copy', + entry_type = 'file', + src_url = 'oil-test:///foo/a.txt', + dest_url = 'oil-test:///foo/b.txt', }, }, actions) end) - it("constructs MOVE actions", function() - local file = test_adapter.test_set("/foo/a.txt", "file") - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('constructs MOVE actions', function() + local file = test_adapter.test_set('/foo/a.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { - { type = "delete", name = "a.txt", id = file[FIELD_ID] }, - { type = "new", name = "b.txt", entry_type = "file", id = file[FIELD_ID] }, + { type = 'delete', name = 'a.txt', id = file[FIELD_ID] }, + { type = 'new', name = 'b.txt', entry_type = 'file', id = file[FIELD_ID] }, } local actions = mutator.create_actions_from_diffs({ [bufnr] = diffs, }) assert.are.same({ { - type = "move", - entry_type = "file", - src_url = "oil-test:///foo/a.txt", - dest_url = "oil-test:///foo/b.txt", + type = 'move', + entry_type = 'file', + src_url = 'oil-test:///foo/a.txt', + dest_url = 'oil-test:///foo/b.txt', }, }, actions) end) - it("correctly orders MOVE + CREATE", function() - local file = test_adapter.test_set("/a.txt", "file") - vim.cmd.edit({ args = { "oil-test:///" } }) + it('correctly orders MOVE + CREATE', function() + local file = test_adapter.test_set('/a.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { - { type = "delete", name = "a.txt", id = file[FIELD_ID] }, - { type = "new", name = "b.txt", entry_type = "file", id = file[FIELD_ID] }, - { type = "new", name = "a.txt", entry_type = "file" }, + { type = 'delete', name = 'a.txt', id = file[FIELD_ID] }, + { type = 'new', name = 'b.txt', entry_type = 'file', id = file[FIELD_ID] }, + { type = 'new', name = 'a.txt', entry_type = 'file' }, } local actions = mutator.create_actions_from_diffs({ [bufnr] = diffs, }) assert.are.same({ { - type = "move", - entry_type = "file", - src_url = "oil-test:///a.txt", - dest_url = "oil-test:///b.txt", + type = 'move', + entry_type = 'file', + src_url = 'oil-test:///a.txt', + dest_url = 'oil-test:///b.txt', }, { - type = "create", - entry_type = "file", - url = "oil-test:///a.txt", + type = 'create', + entry_type = 'file', + url = 'oil-test:///a.txt', }, }, actions) end) - it("resolves MOVE loops", function() - local afile = test_adapter.test_set("/a.txt", "file") - local bfile = test_adapter.test_set("/b.txt", "file") - vim.cmd.edit({ args = { "oil-test:///" } }) + it('resolves MOVE loops', function() + local afile = test_adapter.test_set('/a.txt', 'file') + local bfile = test_adapter.test_set('/b.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { - { type = "delete", name = "a.txt", id = afile[FIELD_ID] }, - { type = "new", name = "b.txt", entry_type = "file", id = afile[FIELD_ID] }, - { type = "delete", name = "b.txt", id = bfile[FIELD_ID] }, - { type = "new", name = "a.txt", entry_type = "file", id = bfile[FIELD_ID] }, + { type = 'delete', name = 'a.txt', id = afile[FIELD_ID] }, + { type = 'new', name = 'b.txt', entry_type = 'file', id = afile[FIELD_ID] }, + { type = 'delete', name = 'b.txt', id = bfile[FIELD_ID] }, + { type = 'new', name = 'a.txt', entry_type = 'file', id = bfile[FIELD_ID] }, } math.randomseed(2983982) local actions = mutator.create_actions_from_diffs({ [bufnr] = diffs, }) - local tmp_url = "oil-test:///a.txt__oil_tmp_510852" + local tmp_url = 'oil-test:///a.txt__oil_tmp_510852' assert.are.same({ { - type = "move", - entry_type = "file", - src_url = "oil-test:///a.txt", + type = 'move', + entry_type = 'file', + src_url = 'oil-test:///a.txt', dest_url = tmp_url, }, { - type = "move", - entry_type = "file", - src_url = "oil-test:///b.txt", - dest_url = "oil-test:///a.txt", + type = 'move', + entry_type = 'file', + src_url = 'oil-test:///b.txt', + dest_url = 'oil-test:///a.txt', }, { - type = "move", - entry_type = "file", + type = 'move', + entry_type = 'file', src_url = tmp_url, - dest_url = "oil-test:///b.txt", + dest_url = 'oil-test:///b.txt', }, }, actions) end) end) - describe("order actions", function() - it("Creates files inside dir before move", function() + describe('order actions', function() + it('Creates files inside dir before move', function() local move = { - type = "move", - src_url = "oil-test:///a", - dest_url = "oil-test:///b", - entry_type = "directory", + type = 'move', + src_url = 'oil-test:///a', + dest_url = 'oil-test:///b', + entry_type = 'directory', } - local create = { type = "create", url = "oil-test:///a/hi.txt", entry_type = "file" } + local create = { type = 'create', url = 'oil-test:///a/hi.txt', entry_type = 'file' } local actions = { move, create } local ordered_actions = mutator.enforce_action_order(actions) assert.are.same({ create, move }, ordered_actions) end) - it("Moves file out of parent before deleting parent", function() + it('Moves file out of parent before deleting parent', function() local move = { - type = "move", - src_url = "oil-test:///a/b.txt", - dest_url = "oil-test:///b.txt", - entry_type = "file", + type = 'move', + src_url = 'oil-test:///a/b.txt', + dest_url = 'oil-test:///b.txt', + entry_type = 'file', } - local delete = { type = "delete", url = "oil-test:///a", entry_type = "directory" } + local delete = { type = 'delete', url = 'oil-test:///a', entry_type = 'directory' } local actions = { delete, move } local ordered_actions = mutator.enforce_action_order(actions) assert.are.same({ move, delete }, ordered_actions) end) - it("Handles parent child move ordering", function() + it('Handles parent child move ordering', function() -- move parent into a child and child OUT of parent -- MOVE /a/b -> /b -- MOVE /a -> /b/a local move1 = { - type = "move", - src_url = "oil-test:///a/b", - dest_url = "oil-test:///b", - entry_type = "directory", + type = 'move', + src_url = 'oil-test:///a/b', + dest_url = 'oil-test:///b', + entry_type = 'directory', } local move2 = { - type = "move", - src_url = "oil-test:///a", - dest_url = "oil-test:///b/a", - entry_type = "directory", + type = 'move', + src_url = 'oil-test:///a', + dest_url = 'oil-test:///b/a', + entry_type = 'directory', } local actions = { move2, move1 } local ordered_actions = mutator.enforce_action_order(actions) assert.are.same({ move1, move2 }, ordered_actions) end) - it("Handles a delete inside a moved folder", function() + it('Handles a delete inside a moved folder', function() -- delete in directory and move directory -- DELETE /a/b.txt -- MOVE /a/ -> /b/ local del = { - type = "delete", - url = "oil-test:///a/b.txt", - entry_type = "file", + type = 'delete', + url = 'oil-test:///a/b.txt', + entry_type = 'file', } local move = { - type = "move", - src_url = "oil-test:///a", - dest_url = "oil-test:///b", - entry_type = "directory", + type = 'move', + src_url = 'oil-test:///a', + dest_url = 'oil-test:///b', + entry_type = 'directory', } local actions = { move, del } local ordered_actions = mutator.enforce_action_order(actions) assert.are.same({ del, move }, ordered_actions) end) - it("Detects move directory loops", function() + it('Detects move directory loops', function() local move = { - type = "move", - src_url = "oil-test:///a", - dest_url = "oil-test:///a/b", - entry_type = "directory", + type = 'move', + src_url = 'oil-test:///a', + dest_url = 'oil-test:///a/b', + entry_type = 'directory', } assert.has_error(function() mutator.enforce_action_order({ move }) end) end) - it("Detects copy directory loops", function() + it('Detects copy directory loops', function() local move = { - type = "copy", - src_url = "oil-test:///a", - dest_url = "oil-test:///a/b", - entry_type = "directory", + type = 'copy', + src_url = 'oil-test:///a', + dest_url = 'oil-test:///a/b', + entry_type = 'directory', } assert.has_error(function() mutator.enforce_action_order({ move }) end) end) - it("Detects nested copy directory loops", function() + it('Detects nested copy directory loops', function() local move = { - type = "copy", - src_url = "oil-test:///a", - dest_url = "oil-test:///a/b/a", - entry_type = "directory", + type = 'copy', + src_url = 'oil-test:///a', + dest_url = 'oil-test:///a/b/a', + entry_type = 'directory', } assert.has_error(function() mutator.enforce_action_order({ move }) end) end) - describe("change", function() - it("applies CHANGE after CREATE", function() - local create = { type = "create", url = "oil-test:///a/hi.txt", entry_type = "file" } + describe('change', function() + it('applies CHANGE after CREATE', function() + local create = { type = 'create', url = 'oil-test:///a/hi.txt', entry_type = 'file' } local change = { - type = "change", - url = "oil-test:///a/hi.txt", - entry_type = "file", - column = "TEST", - value = "TEST", + type = 'change', + url = 'oil-test:///a/hi.txt', + entry_type = 'file', + column = 'TEST', + value = 'TEST', } local actions = { change, create } local ordered_actions = mutator.enforce_action_order(actions) assert.are.same({ create, change }, ordered_actions) end) - it("applies CHANGE after COPY src", function() + it('applies CHANGE after COPY src', function() local copy = { - type = "copy", - src_url = "oil-test:///a/hi.txt", - dest_url = "oil-test:///b.txt", - entry_type = "file", + type = 'copy', + src_url = 'oil-test:///a/hi.txt', + dest_url = 'oil-test:///b.txt', + entry_type = 'file', } local change = { - type = "change", - url = "oil-test:///a/hi.txt", - entry_type = "file", - column = "TEST", - value = "TEST", + type = 'change', + url = 'oil-test:///a/hi.txt', + entry_type = 'file', + column = 'TEST', + value = 'TEST', } local actions = { change, copy } local ordered_actions = mutator.enforce_action_order(actions) assert.are.same({ copy, change }, ordered_actions) end) - it("applies CHANGE after COPY dest", function() + it('applies CHANGE after COPY dest', function() local copy = { - type = "copy", - src_url = "oil-test:///b.txt", - dest_url = "oil-test:///a/hi.txt", - entry_type = "file", + type = 'copy', + src_url = 'oil-test:///b.txt', + dest_url = 'oil-test:///a/hi.txt', + entry_type = 'file', } local change = { - type = "change", - url = "oil-test:///a/hi.txt", - entry_type = "file", - column = "TEST", - value = "TEST", + type = 'change', + url = 'oil-test:///a/hi.txt', + entry_type = 'file', + column = 'TEST', + value = 'TEST', } local actions = { change, copy } local ordered_actions = mutator.enforce_action_order(actions) assert.are.same({ copy, change }, ordered_actions) end) - it("applies CHANGE after MOVE dest", function() + it('applies CHANGE after MOVE dest', function() local move = { - type = "move", - src_url = "oil-test:///b.txt", - dest_url = "oil-test:///a/hi.txt", - entry_type = "file", + type = 'move', + src_url = 'oil-test:///b.txt', + dest_url = 'oil-test:///a/hi.txt', + entry_type = 'file', } local change = { - type = "change", - url = "oil-test:///a/hi.txt", - entry_type = "file", - column = "TEST", - value = "TEST", + type = 'change', + url = 'oil-test:///a/hi.txt', + entry_type = 'file', + column = 'TEST', + value = 'TEST', } local actions = { change, move } local ordered_actions = mutator.enforce_action_order(actions) @@ -346,29 +346,29 @@ a.describe("mutator", function() end) end) - a.describe("perform actions", function() - a.it("creates new entries", function() + a.describe('perform actions', function() + a.it('creates new entries', function() local actions = { - { type = "create", url = "oil-test:///a.txt", entry_type = "file" }, + { type = 'create', url = 'oil-test:///a.txt', entry_type = 'file' }, } a.wrap(mutator.process_actions, 2)(actions) - local files = cache.list_url("oil-test:///") + local files = cache.list_url('oil-test:///') assert.are.same({ - ["a.txt"] = { + ['a.txt'] = { [FIELD_ID] = 1, - [FIELD_TYPE] = "file", - [FIELD_NAME] = "a.txt", + [FIELD_TYPE] = 'file', + [FIELD_NAME] = 'a.txt', }, }, files) end) - a.it("deletes entries", function() - local file = test_adapter.test_set("/a.txt", "file") + a.it('deletes entries', function() + local file = test_adapter.test_set('/a.txt', 'file') local actions = { - { type = "delete", url = "oil-test:///a.txt", entry_type = "file" }, + { type = 'delete', url = 'oil-test:///a.txt', entry_type = 'file' }, } a.wrap(mutator.process_actions, 2)(actions) - local files = cache.list_url("oil-test:///") + local files = cache.list_url('oil-test:///') assert.are.same({}, files) assert.is_nil(cache.get_entry_by_id(file[FIELD_ID])) assert.has_error(function() @@ -376,50 +376,50 @@ a.describe("mutator", function() end) end) - a.it("moves entries", function() - local file = test_adapter.test_set("/a.txt", "file") + a.it('moves entries', function() + local file = test_adapter.test_set('/a.txt', 'file') local actions = { { - type = "move", - src_url = "oil-test:///a.txt", - dest_url = "oil-test:///b.txt", - entry_type = "file", + type = 'move', + src_url = 'oil-test:///a.txt', + dest_url = 'oil-test:///b.txt', + entry_type = 'file', }, } a.wrap(mutator.process_actions, 2)(actions) - local files = cache.list_url("oil-test:///") + local files = cache.list_url('oil-test:///') local new_entry = { [FIELD_ID] = file[FIELD_ID], - [FIELD_TYPE] = "file", - [FIELD_NAME] = "b.txt", + [FIELD_TYPE] = 'file', + [FIELD_NAME] = 'b.txt', } assert.are.same({ - ["b.txt"] = new_entry, + ['b.txt'] = new_entry, }, files) assert.are.same(new_entry, cache.get_entry_by_id(file[FIELD_ID])) - assert.equals("oil-test:///", cache.get_parent_url(file[FIELD_ID])) + assert.equals('oil-test:///', cache.get_parent_url(file[FIELD_ID])) end) - a.it("copies entries", function() - local file = test_adapter.test_set("/a.txt", "file") + a.it('copies entries', function() + local file = test_adapter.test_set('/a.txt', 'file') local actions = { { - type = "copy", - src_url = "oil-test:///a.txt", - dest_url = "oil-test:///b.txt", - entry_type = "file", + type = 'copy', + src_url = 'oil-test:///a.txt', + dest_url = 'oil-test:///b.txt', + entry_type = 'file', }, } a.wrap(mutator.process_actions, 2)(actions) - local files = cache.list_url("oil-test:///") + local files = cache.list_url('oil-test:///') local new_entry = { [FIELD_ID] = file[FIELD_ID] + 1, - [FIELD_TYPE] = "file", - [FIELD_NAME] = "b.txt", + [FIELD_TYPE] = 'file', + [FIELD_NAME] = 'b.txt', } assert.are.same({ - ["a.txt"] = file, - ["b.txt"] = new_entry, + ['a.txt'] = file, + ['b.txt'] = new_entry, }, files) end) end) diff --git a/tests/parser_spec.lua b/tests/parser_spec.lua index 9884ca1..ef81405 100644 --- a/tests/parser_spec.lua +++ b/tests/parser_spec.lua @@ -1,10 +1,10 @@ -require("plenary.async").tests.add_to_env() -local constants = require("oil.constants") -local parser = require("oil.mutator.parser") -local test_adapter = require("oil.adapters.test") -local test_util = require("tests.test_util") -local util = require("oil.util") -local view = require("oil.view") +require('plenary.async').tests.add_to_env() +local constants = require('oil.constants') +local parser = require('oil.mutator.parser') +local test_adapter = require('oil.adapters.test') +local test_util = require('tests.test_util') +local util = require('oil.util') +local view = require('oil.view') local FIELD_ID = constants.FIELD_ID local FIELD_META = constants.FIELD_META @@ -14,101 +14,101 @@ local function set_lines(bufnr, lines) vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, lines) end -describe("parser", function() +describe('parser', function() after_each(function() test_util.reset_editor() end) - it("detects new files", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('detects new files', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - "a.txt", + 'a.txt', }) local diffs = parser.parse(bufnr) - assert.are.same({ { entry_type = "file", name = "a.txt", type = "new" } }, diffs) + assert.are.same({ { entry_type = 'file', name = 'a.txt', type = 'new' } }, diffs) end) - it("detects new directories", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('detects new directories', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - "foo/", + 'foo/', }) local diffs = parser.parse(bufnr) - assert.are.same({ { entry_type = "directory", name = "foo", type = "new" } }, diffs) + assert.are.same({ { entry_type = 'directory', name = 'foo', type = 'new' } }, diffs) end) - it("detects new links", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('detects new links', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - "a.txt -> b.txt", + 'a.txt -> b.txt', }) local diffs = parser.parse(bufnr) assert.are.same( - { { entry_type = "link", name = "a.txt", type = "new", link = "b.txt" } }, + { { entry_type = 'link', name = 'a.txt', type = 'new', link = 'b.txt' } }, diffs ) end) - it("detects deleted files", function() - local file = test_adapter.test_set("/foo/a.txt", "file") - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('detects deleted files', function() + local file = test_adapter.test_set('/foo/a.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, {}) local diffs = parser.parse(bufnr) assert.are.same({ - { name = "a.txt", type = "delete", id = file[FIELD_ID] }, + { name = 'a.txt', type = 'delete', id = file[FIELD_ID] }, }, diffs) end) - it("detects deleted directories", function() - local dir = test_adapter.test_set("/foo/bar", "directory") - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('detects deleted directories', function() + local dir = test_adapter.test_set('/foo/bar', 'directory') + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, {}) local diffs = parser.parse(bufnr) assert.are.same({ - { name = "bar", type = "delete", id = dir[FIELD_ID] }, + { name = 'bar', type = 'delete', id = dir[FIELD_ID] }, }, diffs) end) - it("detects deleted links", function() - local file = test_adapter.test_set("/foo/a.txt", "link") - file[FIELD_META] = { link = "b.txt" } - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('detects deleted links', function() + local file = test_adapter.test_set('/foo/a.txt', 'link') + file[FIELD_META] = { link = 'b.txt' } + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, {}) local diffs = parser.parse(bufnr) assert.are.same({ - { name = "a.txt", type = "delete", id = file[FIELD_ID] }, + { name = 'a.txt', type = 'delete', id = file[FIELD_ID] }, }, diffs) end) - it("ignores empty lines", function() - local file = test_adapter.test_set("/foo/a.txt", "file") - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('ignores empty lines', function() + local file = test_adapter.test_set('/foo/a.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local cols = view.format_entry_cols(file, {}, {}, test_adapter, false) local lines = util.render_table({ cols }, {}) - table.insert(lines, "") - table.insert(lines, " ") + table.insert(lines, '') + table.insert(lines, ' ') set_lines(bufnr, lines) local diffs = parser.parse(bufnr) assert.are.same({}, diffs) end) - it("errors on missing filename", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('errors on missing filename', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - "/008", + '/008', }) local _, errors = parser.parse(bufnr) assert.are_same({ { - message = "Malformed ID at start of line", + message = 'Malformed ID at start of line', lnum = 0, end_lnum = 1, col = 0, @@ -116,16 +116,16 @@ describe("parser", function() }, errors) end) - it("errors on empty dirname", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('errors on empty dirname', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - "/008 /", + '/008 /', }) local _, errors = parser.parse(bufnr) assert.are.same({ { - message = "No filename found", + message = 'No filename found', lnum = 0, end_lnum = 1, col = 0, @@ -133,17 +133,17 @@ describe("parser", function() }, errors) end) - it("errors on duplicate names", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('errors on duplicate names', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - "foo", - "foo/", + 'foo', + 'foo/', }) local _, errors = parser.parse(bufnr) assert.are.same({ { - message = "Duplicate filename", + message = 'Duplicate filename', lnum = 1, end_lnum = 2, col = 0, @@ -151,18 +151,18 @@ describe("parser", function() }, errors) end) - it("errors on duplicate names for existing files", function() - local file = test_adapter.test_set("/foo/a.txt", "file") - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('errors on duplicate names for existing files', function() + local file = test_adapter.test_set('/foo/a.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - "a.txt", - string.format("/%d a.txt", file[FIELD_ID]), + 'a.txt', + string.format('/%d a.txt', file[FIELD_ID]), }) local _, errors = parser.parse(bufnr) assert.are.same({ { - message = "Duplicate filename", + message = 'Duplicate filename', lnum = 1, end_lnum = 2, col = 0, @@ -170,52 +170,52 @@ describe("parser", function() }, errors) end) - it("ignores new dirs with empty name", function() - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('ignores new dirs with empty name', function() + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - "/", + '/', }) local diffs = parser.parse(bufnr) assert.are.same({}, diffs) end) - it("parses a rename as a delete + new", function() - local file = test_adapter.test_set("/foo/a.txt", "file") - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('parses a rename as a delete + new', function() + local file = test_adapter.test_set('/foo/a.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - string.format("/%d b.txt", file[FIELD_ID]), + string.format('/%d b.txt', file[FIELD_ID]), }) local diffs = parser.parse(bufnr) assert.are.same({ - { type = "new", id = file[FIELD_ID], name = "b.txt", entry_type = "file" }, - { type = "delete", id = file[FIELD_ID], name = "a.txt" }, + { type = 'new', id = file[FIELD_ID], name = 'b.txt', entry_type = 'file' }, + { type = 'delete', id = file[FIELD_ID], name = 'a.txt' }, }, diffs) end) - it("detects a new trailing slash as a delete + create", function() - local file = test_adapter.test_set("/foo", "file") - vim.cmd.edit({ args = { "oil-test:///" } }) + it('detects a new trailing slash as a delete + create', function() + local file = test_adapter.test_set('/foo', 'file') + vim.cmd.edit({ args = { 'oil-test:///' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - string.format("/%d foo/", file[FIELD_ID]), + string.format('/%d foo/', file[FIELD_ID]), }) local diffs = parser.parse(bufnr) assert.are.same({ - { type = "new", name = "foo", entry_type = "directory" }, - { type = "delete", id = file[FIELD_ID], name = "foo" }, + { type = 'new', name = 'foo', entry_type = 'directory' }, + { type = 'delete', id = file[FIELD_ID], name = 'foo' }, }, diffs) end) - it("detects renamed files that conflict", function() - local afile = test_adapter.test_set("/foo/a.txt", "file") - local bfile = test_adapter.test_set("/foo/b.txt", "file") - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('detects renamed files that conflict', function() + local afile = test_adapter.test_set('/foo/a.txt', 'file') + local bfile = test_adapter.test_set('/foo/b.txt', 'file') + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - string.format("/%d a.txt", bfile[FIELD_ID]), - string.format("/%d b.txt", afile[FIELD_ID]), + string.format('/%d a.txt', bfile[FIELD_ID]), + string.format('/%d b.txt', afile[FIELD_ID]), }) local diffs = parser.parse(bufnr) local first_two = { diffs[1], diffs[2] } @@ -227,22 +227,22 @@ describe("parser", function() return a.id < b.id end) assert.are.same({ - { name = "b.txt", type = "new", id = afile[FIELD_ID], entry_type = "file" }, - { name = "a.txt", type = "new", id = bfile[FIELD_ID], entry_type = "file" }, + { name = 'b.txt', type = 'new', id = afile[FIELD_ID], entry_type = 'file' }, + { name = 'a.txt', type = 'new', id = bfile[FIELD_ID], entry_type = 'file' }, }, first_two) assert.are.same({ - { name = "a.txt", type = "delete", id = afile[FIELD_ID] }, - { name = "b.txt", type = "delete", id = bfile[FIELD_ID] }, + { name = 'a.txt', type = 'delete', id = afile[FIELD_ID] }, + { name = 'b.txt', type = 'delete', id = bfile[FIELD_ID] }, }, last_two) end) - it("views link targets with trailing slashes as the same", function() - local file = test_adapter.test_set("/foo/mydir", "link") - file[FIELD_META] = { link = "dir/" } - vim.cmd.edit({ args = { "oil-test:///foo/" } }) + it('views link targets with trailing slashes as the same', function() + local file = test_adapter.test_set('/foo/mydir', 'link') + file[FIELD_META] = { link = 'dir/' } + vim.cmd.edit({ args = { 'oil-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { - string.format("/%d mydir/ -> dir/", file[FIELD_ID]), + string.format('/%d mydir/ -> dir/', file[FIELD_ID]), }) local diffs = parser.parse(bufnr) assert.are.same({}, diffs) diff --git a/tests/path_spec.lua b/tests/path_spec.lua index a92a1ca..ab83fe4 100644 --- a/tests/path_spec.lua +++ b/tests/path_spec.lua @@ -1,13 +1,13 @@ -local pathutil = require("oil.pathutil") -describe("pathutil", function() - it("calculates parent path", function() +local pathutil = require('oil.pathutil') +describe('pathutil', function() + it('calculates parent path', function() local cases = { - { "/foo/bar", "/foo/" }, - { "/foo/bar/", "/foo/" }, - { "/", "/" }, - { "", "" }, - { "foo/bar/", "foo/" }, - { "foo", "" }, + { '/foo/bar', '/foo/' }, + { '/foo/bar/', '/foo/' }, + { '/', '/' }, + { '', '' }, + { 'foo/bar/', 'foo/' }, + { 'foo', '' }, } for _, case in ipairs(cases) do local input, expected = unpack(case) @@ -16,12 +16,12 @@ describe("pathutil", function() end end) - it("calculates basename", function() + it('calculates basename', function() local cases = { - { "/foo/bar", "bar" }, - { "/foo/bar/", "bar" }, - { "/", nil }, - { "", nil }, + { '/foo/bar', 'bar' }, + { '/foo/bar/', 'bar' }, + { '/', nil }, + { '', nil }, } for _, case in ipairs(cases) do local input, expected = unpack(case) diff --git a/tests/preview_spec.lua b/tests/preview_spec.lua index 08aba78..c5ba81a 100644 --- a/tests/preview_spec.lua +++ b/tests/preview_spec.lua @@ -1,10 +1,10 @@ -require("plenary.async").tests.add_to_env() -local TmpDir = require("tests.tmpdir") -local oil = require("oil") -local test_util = require("tests.test_util") -local util = require("oil.util") +require('plenary.async').tests.add_to_env() +local TmpDir = require('tests.tmpdir') +local oil = require('oil') +local test_util = require('tests.test_util') +local util = require('oil.util') -a.describe("oil preview", function() +a.describe('oil preview', function() local tmpdir a.before_each(function() tmpdir = TmpDir.new() @@ -16,8 +16,8 @@ a.describe("oil preview", function() test_util.reset_editor() end) - a.it("opens preview window", function() - tmpdir:create({ "a.txt" }) + a.it('opens preview window', function() + tmpdir:create({ 'a.txt' }) test_util.oil_open(tmpdir.path) a.wrap(oil.open_preview, 2)() local preview_win = util.get_preview_win() @@ -25,17 +25,17 @@ a.describe("oil preview", function() assert(preview_win) local bufnr = vim.api.nvim_win_get_buf(preview_win) local preview_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) - assert.are.same({ "a.txt" }, preview_lines) + assert.are.same({ 'a.txt' }, preview_lines) end) - a.it("opens preview window when open(preview={})", function() - tmpdir:create({ "a.txt" }) + a.it('opens preview window when open(preview={})', function() + tmpdir:create({ 'a.txt' }) test_util.oil_open(tmpdir.path, { preview = {} }) local preview_win = util.get_preview_win() assert.not_nil(preview_win) assert(preview_win) local bufnr = vim.api.nvim_win_get_buf(preview_win) local preview_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) - assert.are.same({ "a.txt" }, preview_lines) + assert.are.same({ 'a.txt' }, preview_lines) end) end) diff --git a/tests/regression_spec.lua b/tests/regression_spec.lua index 9d8f944..21bdddb 100644 --- a/tests/regression_spec.lua +++ b/tests/regression_spec.lua @@ -1,11 +1,11 @@ -require("plenary.async").tests.add_to_env() -local TmpDir = require("tests.tmpdir") -local actions = require("oil.actions") -local oil = require("oil") -local test_util = require("tests.test_util") -local view = require("oil.view") +require('plenary.async').tests.add_to_env() +local TmpDir = require('tests.tmpdir') +local actions = require('oil.actions') +local oil = require('oil') +local test_util = require('tests.test_util') +local view = require('oil.view') -a.describe("regression tests", function() +a.describe('regression tests', function() local tmpdir a.before_each(function() tmpdir = TmpDir.new() @@ -19,37 +19,37 @@ a.describe("regression tests", function() end) -- see https://github.com/stevearc/oil.nvim/issues/25 - a.it("can edit dirs that will be renamed to an existing buffer", function() - vim.cmd.edit({ args = { "README.md" } }) + a.it('can edit dirs that will be renamed to an existing buffer', function() + vim.cmd.edit({ args = { 'README.md' } }) vim.cmd.vsplit() - vim.cmd.edit({ args = { "%:p:h" } }) - assert.equals("oil", vim.bo.filetype) - vim.cmd.wincmd({ args = { "p" } }) - assert.equals("markdown", vim.bo.filetype) - vim.cmd.edit({ args = { "%:p:h" } }) - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.equals("oil", vim.bo.filetype) + vim.cmd.edit({ args = { '%:p:h' } }) + assert.equals('oil', vim.bo.filetype) + vim.cmd.wincmd({ args = { 'p' } }) + assert.equals('markdown', vim.bo.filetype) + vim.cmd.edit({ args = { '%:p:h' } }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.equals('oil', vim.bo.filetype) end) -- https://github.com/stevearc/oil.nvim/issues/37 - a.it("places the cursor on correct entry when opening on file", function() - vim.cmd.edit({ args = { "." } }) - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + a.it('places the cursor on correct entry when opening on file', function() + vim.cmd.edit({ args = { '.' } }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) local entry = oil.get_cursor_entry() assert.not_nil(entry) - assert.not_equals("README.md", entry and entry.name) - vim.cmd.edit({ args = { "README.md" } }) + assert.not_equals('README.md', entry and entry.name) + vim.cmd.edit({ args = { 'README.md' } }) view.delete_hidden_buffers() oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) entry = oil.get_cursor_entry() - assert.equals("README.md", entry and entry.name) + assert.equals('README.md', entry and entry.name) end) -- https://github.com/stevearc/oil.nvim/issues/64 a.it("doesn't close floating windows oil didn't open itself", function() - local winid = vim.api.nvim_open_win(vim.fn.bufadd("README.md"), true, { - relative = "editor", + local winid = vim.api.nvim_open_win(vim.fn.bufadd('README.md'), true, { + relative = 'editor', row = 1, col = 1, width = 100, @@ -64,7 +64,7 @@ a.describe("regression tests", function() -- https://github.com/stevearc/oil.nvim/issues/64 a.it("doesn't close splits on oil.close", function() - vim.cmd.edit({ args = { "README.md" } }) + vim.cmd.edit({ args = { 'README.md' } }) vim.cmd.vsplit() local winid = vim.api.nvim_get_current_win() local bufnr = vim.api.nvim_get_current_buf() @@ -78,71 +78,71 @@ a.describe("regression tests", function() end) -- https://github.com/stevearc/oil.nvim/issues/79 - a.it("Returns to empty buffer on close", function() + a.it('Returns to empty buffer on close', function() oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) oil.close() - assert.not_equals("oil", vim.bo.filetype) - assert.equals("", vim.api.nvim_buf_get_name(0)) + assert.not_equals('oil', vim.bo.filetype) + assert.equals('', vim.api.nvim_buf_get_name(0)) end) - a.it("All buffers set nomodified after save", function() - tmpdir:create({ "a.txt" }) + a.it('All buffers set nomodified after save', function() + tmpdir:create({ 'a.txt' }) a.util.scheduler() - vim.cmd.edit({ args = { "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") } }) + vim.cmd.edit({ args = { 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') } }) local first_dir = vim.api.nvim_get_current_buf() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - test_util.feedkeys({ "dd", "itest/", "" }, 10) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + test_util.feedkeys({ 'dd', 'itest/', '' }, 10) vim.wait(1000, function() return vim.bo.modifiable end, 10) - test_util.feedkeys({ "p" }, 10) + test_util.feedkeys({ 'p' }, 10) a.util.scheduler() oil.save({ confirm = false }) vim.wait(1000, function() return vim.bo.modifiable end, 10) tmpdir:assert_fs({ - ["test/a.txt"] = "a.txt", + ['test/a.txt'] = 'a.txt', }) -- The first oil buffer should not be modified anymore assert.falsy(vim.bo[first_dir].modified) end) a.it("refreshing buffer doesn't lose track of it", function() - vim.cmd.edit({ args = { "." } }) - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + vim.cmd.edit({ args = { '.' } }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) local bufnr = vim.api.nvim_get_current_buf() vim.cmd.edit({ bang = true }) - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) - assert.are.same({ bufnr }, require("oil.view").get_all_buffers()) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + assert.are.same({ bufnr }, require('oil.view').get_all_buffers()) end) - a.it("can copy a file multiple times", function() + a.it('can copy a file multiple times', function() test_util.actions.open({ tmpdir.path }) - vim.api.nvim_feedkeys("ifoo.txt", "x", true) + vim.api.nvim_feedkeys('ifoo.txt', 'x', true) test_util.actions.save() - vim.api.nvim_feedkeys("yyp$ciWbar.txt", "x", true) - vim.api.nvim_feedkeys("yyp$ciWbaz.txt", "x", true) + vim.api.nvim_feedkeys('yyp$ciWbar.txt', 'x', true) + vim.api.nvim_feedkeys('yyp$ciWbaz.txt', 'x', true) test_util.actions.save() - assert.are.same({ "bar.txt", "baz.txt", "foo.txt" }, test_util.parse_entries(0)) + assert.are.same({ 'bar.txt', 'baz.txt', 'foo.txt' }, test_util.parse_entries(0)) tmpdir:assert_fs({ - ["foo.txt"] = "", - ["bar.txt"] = "", - ["baz.txt"] = "", + ['foo.txt'] = '', + ['bar.txt'] = '', + ['baz.txt'] = '', }) end) -- https://github.com/stevearc/oil.nvim/issues/355 - a.it("can open files from floating window", function() - tmpdir:create({ "a.txt" }) + a.it('can open files from floating window', function() + tmpdir:create({ 'a.txt' }) a.util.scheduler() oil.open_float(tmpdir.path) - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) actions.select.callback() vim.wait(1000, function() - return vim.fn.expand("%:t") == "a.txt" + return vim.fn.expand('%:t') == 'a.txt' end, 10) - assert.equals("a.txt", vim.fn.expand("%:t")) + assert.equals('a.txt', vim.fn.expand('%:t')) end) end) diff --git a/tests/select_spec.lua b/tests/select_spec.lua index 9de2eb4..3f8621a 100644 --- a/tests/select_spec.lua +++ b/tests/select_spec.lua @@ -1,22 +1,22 @@ -require("plenary.async").tests.add_to_env() -local oil = require("oil") -local test_util = require("tests.test_util") +require('plenary.async').tests.add_to_env() +local oil = require('oil') +local test_util = require('tests.test_util') -a.describe("oil select", function() +a.describe('oil select', function() after_each(function() test_util.reset_editor() end) - a.it("opens file under cursor", function() + a.it('opens file under cursor', function() test_util.oil_open() -- Go to the bottom, so the cursor is not on a directory - vim.cmd.normal({ args = { "G" } }) + vim.cmd.normal({ args = { 'G' } }) a.wrap(oil.select, 2)() assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) - assert.not_equals("oil", vim.bo.filetype) + assert.not_equals('oil', vim.bo.filetype) end) - a.it("opens file in new tab", function() + a.it('opens file in new tab', function() test_util.oil_open() local tabpage = vim.api.nvim_get_current_tabpage() a.wrap(oil.select, 2)({ tab = true }) @@ -25,7 +25,7 @@ a.describe("oil select", function() assert.not_equals(tabpage, vim.api.nvim_get_current_tabpage()) end) - a.it("opens file in new split", function() + a.it('opens file in new split', function() test_util.oil_open() local winid = vim.api.nvim_get_current_win() a.wrap(oil.select, 2)({ vertical = true }) @@ -34,9 +34,9 @@ a.describe("oil select", function() assert.not_equals(winid, vim.api.nvim_get_current_win()) end) - a.it("opens multiple files in new tabs", function() + a.it('opens multiple files in new tabs', function() test_util.oil_open() - vim.api.nvim_feedkeys("Vj", "x", true) + vim.api.nvim_feedkeys('Vj', 'x', true) local tabpage = vim.api.nvim_get_current_tabpage() a.wrap(oil.select, 2)({ tab = true }) assert.equals(3, #vim.api.nvim_list_tabpages()) @@ -44,9 +44,9 @@ a.describe("oil select", function() assert.not_equals(tabpage, vim.api.nvim_get_current_tabpage()) end) - a.it("opens multiple files in new splits", function() + a.it('opens multiple files in new splits', function() test_util.oil_open() - vim.api.nvim_feedkeys("Vj", "x", true) + vim.api.nvim_feedkeys('Vj', 'x', true) local winid = vim.api.nvim_get_current_win() a.wrap(oil.select, 2)({ vertical = true }) assert.equals(1, #vim.api.nvim_list_tabpages()) @@ -54,23 +54,23 @@ a.describe("oil select", function() assert.not_equals(winid, vim.api.nvim_get_current_win()) end) - a.describe("close after open", function() - a.it("same window", function() - vim.cmd.edit({ args = { "foo" } }) + a.describe('close after open', function() + a.it('same window', function() + vim.cmd.edit({ args = { 'foo' } }) local bufnr = vim.api.nvim_get_current_buf() test_util.oil_open() -- Go to the bottom, so the cursor is not on a directory - vim.cmd.normal({ args = { "G" } }) + vim.cmd.normal({ args = { 'G' } }) a.wrap(oil.select, 2)({ close = true }) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) -- This one we actually don't expect the buffer to be the same as the initial buffer, because -- we opened a file assert.not_equals(bufnr, vim.api.nvim_get_current_buf()) - assert.not_equals("oil", vim.bo.filetype) + assert.not_equals('oil', vim.bo.filetype) end) - a.it("split", function() - vim.cmd.edit({ args = { "foo" } }) + a.it('split', function() + vim.cmd.edit({ args = { 'foo' } }) local bufnr = vim.api.nvim_get_current_buf() local winid = vim.api.nvim_get_current_win() test_util.oil_open() @@ -79,8 +79,8 @@ a.describe("oil select", function() assert.equals(bufnr, vim.api.nvim_win_get_buf(winid)) end) - a.it("tab", function() - vim.cmd.edit({ args = { "foo" } }) + a.it('tab', function() + vim.cmd.edit({ args = { 'foo' } }) local bufnr = vim.api.nvim_get_current_buf() local tabpage = vim.api.nvim_get_current_tabpage() test_util.oil_open() diff --git a/tests/test_util.lua b/tests/test_util.lua index 46f63df..b6c29a6 100644 --- a/tests/test_util.lua +++ b/tests/test_util.lua @@ -1,14 +1,14 @@ -require("plenary.async").tests.add_to_env() -local cache = require("oil.cache") -local test_adapter = require("oil.adapters.test") -local util = require("oil.util") +require('plenary.async').tests.add_to_env() +local cache = require('oil.cache') +local test_adapter = require('oil.adapters.test') +local util = require('oil.util') local M = {} M.reset_editor = function() - require("oil").setup({ + require('oil').setup({ columms = {}, adapters = { - ["oil-test://"] = "test", + ['oil-test://'] = 'test', }, prompt_save_on_select_new_entry = false, }) @@ -35,7 +35,7 @@ local function throwiferr(err, ...) end M.oil_open = function(...) - a.wrap(require("oil").open, 3)(...) + a.wrap(require('oil').open, 3)(...) end M.await = function(fn, nargs, ...) @@ -44,12 +44,12 @@ end M.wait_for_autocmd = a.wrap(function(autocmd, cb) local opts = { - pattern = "*", + pattern = '*', nested = true, once = true, } - if type(autocmd) == "table" then - opts = vim.tbl_extend("force", opts, autocmd) + if type(autocmd) == 'table' then + opts = vim.tbl_extend('force', opts, autocmd) autocmd = autocmd[1] opts[1] = nil end @@ -70,12 +70,12 @@ M.feedkeys = function(actions, timestep) for _, action in ipairs(actions) do a.util.sleep(timestep) local escaped = vim.api.nvim_replace_termcodes(action, true, false, true) - vim.api.nvim_feedkeys(escaped, "m", true) + vim.api.nvim_feedkeys(escaped, 'm', true) end a.util.sleep(timestep) -- process pending keys until the queue is empty. -- Note that this will exit insert mode. - vim.api.nvim_feedkeys("", "x", true) + vim.api.nvim_feedkeys('', 'x', true) a.util.sleep(timestep) end @@ -87,39 +87,39 @@ M.actions = { vim.cmd.Oil({ args = args }) -- If this buffer was already open, manually dispatch the autocmd to finish the wait if vim.b.oil_ready then - vim.api.nvim_exec_autocmds("User", { - pattern = "OilEnter", + vim.api.nvim_exec_autocmds('User', { + pattern = 'OilEnter', modeline = false, data = { buf = vim.api.nvim_get_current_buf() }, }) end end) - M.wait_for_autocmd({ "User", pattern = "OilEnter" }) + M.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) end, ---Save all changes and wait for operation to complete save = function() - vim.schedule_wrap(require("oil").save)({ confirm = false }) - M.wait_for_autocmd({ "User", pattern = "OilMutationComplete" }) + vim.schedule_wrap(require('oil').save)({ confirm = false }) + M.wait_for_autocmd({ 'User', pattern = 'OilMutationComplete' }) end, ---@param bufnr? integer reload = function(bufnr) - M.await(require("oil.view").render_buffer_async, 3, bufnr or 0) + M.await(require('oil.view').render_buffer_async, 3, bufnr or 0) end, ---Move cursor to a file or directory in an oil buffer ---@param filename string focus = function(filename) local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true) - local search = " " .. filename .. "$" + local search = ' ' .. filename .. '$' for i, line in ipairs(lines) do if line:match(search) then vim.api.nvim_win_set_cursor(0, { i, 0 }) return end end - error("Could not find file " .. filename) + error('Could not find file ' .. filename) end, } @@ -133,7 +133,7 @@ M.parse_entries = function(bufnr) end local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) return vim.tbl_map(function(line) - return line:match("^/%d+ +(.+)$") + return line:match('^/%d+ +(.+)$') end, lines) end diff --git a/tests/tmpdir.lua b/tests/tmpdir.lua index bb8a9c0..f4d09e7 100644 --- a/tests/tmpdir.lua +++ b/tests/tmpdir.lua @@ -1,16 +1,16 @@ -local fs = require("oil.fs") -local test_util = require("tests.test_util") +local fs = require('oil.fs') +local test_util = require('tests.test_util') local await = test_util.await ---@param path string ---@param cb fun(err: nil|string) local function touch(path, cb) - vim.loop.fs_open(path, "w", 420, function(err, fd) -- 0644 + vim.loop.fs_open(path, 'w', 420, function(err, fd) -- 0644 if err then cb(err) else - local shortpath = path:gsub("^[^" .. fs.sep .. "]*" .. fs.sep, "") + local shortpath = path:gsub('^[^' .. fs.sep .. ']*' .. fs.sep, '') vim.loop.fs_write(fd, shortpath, nil, function(err2) if err2 then cb(err2) @@ -31,7 +31,7 @@ end local TmpDir = {} TmpDir.new = function() - local path = await(vim.loop.fs_mkdtemp, 2, "oil_test_XXXXXXXXX") + local path = await(vim.loop.fs_mkdtemp, 2, 'oil_test_XXXXXXXXX') a.util.scheduler() return setmetatable({ path = path }, { __index = TmpDir, @@ -58,7 +58,7 @@ end ---@param filepath string ---@return string? local read_file = function(filepath) - local fd = vim.loop.fs_open(filepath, "r", 420) + local fd = vim.loop.fs_open(filepath, 'r', 420) if not fd then return nil end @@ -79,7 +79,7 @@ local function walk(dir) type = type, root = dir, }) - if type == "directory" then + if type == 'directory' then vim.list_extend(ret, walk(fs.join(dir, name))) end end @@ -90,10 +90,10 @@ end local assert_fs = function(root, paths) local unlisted_dirs = {} for k in pairs(paths) do - local pieces = vim.split(k, "/") - local partial_path = "" + local pieces = vim.split(k, '/') + local partial_path = '' for i, piece in ipairs(pieces) do - partial_path = partial_path .. piece .. "/" + partial_path = partial_path .. piece .. '/' if i ~= #pieces then unlisted_dirs[partial_path] = true end @@ -107,13 +107,13 @@ local assert_fs = function(root, paths) for _, entry in ipairs(entries) do local fullpath = fs.join(entry.root, entry.name) local shortpath = fullpath:sub(root:len() + 2) - if entry.type == "directory" then - shortpath = shortpath .. "/" + if entry.type == 'directory' then + shortpath = shortpath .. '/' end local expected_content = paths[shortpath] paths[shortpath] = nil assert.truthy(expected_content, string.format("Unexpected entry '%s'", shortpath)) - if entry.type == "file" then + if entry.type == 'file' then local data = read_file(fullpath) assert.equals( expected_content, @@ -133,7 +133,7 @@ local assert_fs = function(root, paths) k, string.format( "Expected %s '%s', but it was not found", - v == true and "directory" or "file", + v == true and 'directory' or 'file', k ) ) @@ -161,7 +161,7 @@ function TmpDir:assert_not_exists(path) end function TmpDir:dispose() - await(fs.recursive_delete, 3, "directory", self.path) + await(fs.recursive_delete, 3, 'directory', self.path) a.util.scheduler() end diff --git a/tests/trash_spec.lua b/tests/trash_spec.lua index d09a57f..c3897e6 100644 --- a/tests/trash_spec.lua +++ b/tests/trash_spec.lua @@ -1,16 +1,16 @@ -require("plenary.async").tests.add_to_env() -local TmpDir = require("tests.tmpdir") -local test_util = require("tests.test_util") +require('plenary.async').tests.add_to_env() +local TmpDir = require('tests.tmpdir') +local test_util = require('tests.test_util') -a.describe("freedesktop", function() +a.describe('freedesktop', function() local tmpdir local tmphome local home = vim.env.XDG_DATA_HOME a.before_each(function() - require("oil.config").delete_to_trash = true + require('oil.config').delete_to_trash = true tmpdir = TmpDir.new() tmphome = TmpDir.new() - package.loaded["oil.adapters.trash"] = require("oil.adapters.trash.freedesktop") + package.loaded['oil.adapters.trash'] = require('oil.adapters.trash.freedesktop') vim.env.XDG_DATA_HOME = tmphome.path end) a.after_each(function() @@ -22,129 +22,129 @@ a.describe("freedesktop", function() tmphome:dispose() end test_util.reset_editor() - package.loaded["oil.adapters.trash"] = nil + package.loaded['oil.adapters.trash'] = nil end) - a.it("files can be moved to the trash", function() - tmpdir:create({ "a.txt", "foo/b.txt" }) + a.it('files can be moved to the trash', function() + tmpdir:create({ 'a.txt', 'foo/b.txt' }) test_util.actions.open({ tmpdir.path }) - test_util.actions.focus("a.txt") - vim.api.nvim_feedkeys("dd", "x", true) - test_util.actions.open({ "--trash", tmpdir.path }) - vim.api.nvim_feedkeys("p", "x", true) + test_util.actions.focus('a.txt') + vim.api.nvim_feedkeys('dd', 'x', true) + test_util.actions.open({ '--trash', tmpdir.path }) + vim.api.nvim_feedkeys('p', 'x', true) test_util.actions.save() - tmpdir:assert_not_exists("a.txt") - tmpdir:assert_exists("foo/b.txt") + tmpdir:assert_not_exists('a.txt') + tmpdir:assert_exists('foo/b.txt') test_util.actions.reload() - assert.are.same({ "a.txt" }, test_util.parse_entries(0)) + assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it("deleting a file moves it to trash", function() - tmpdir:create({ "a.txt", "foo/b.txt" }) + a.it('deleting a file moves it to trash', function() + tmpdir:create({ 'a.txt', 'foo/b.txt' }) test_util.actions.open({ tmpdir.path }) - test_util.actions.focus("a.txt") - vim.api.nvim_feedkeys("dd", "x", true) + test_util.actions.focus('a.txt') + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() - tmpdir:assert_not_exists("a.txt") - tmpdir:assert_exists("foo/b.txt") - test_util.actions.open({ "--trash", tmpdir.path }) - assert.are.same({ "a.txt" }, test_util.parse_entries(0)) + tmpdir:assert_not_exists('a.txt') + tmpdir:assert_exists('foo/b.txt') + test_util.actions.open({ '--trash', tmpdir.path }) + assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it("deleting a directory moves it to trash", function() - tmpdir:create({ "a.txt", "foo/b.txt" }) + a.it('deleting a directory moves it to trash', function() + tmpdir:create({ 'a.txt', 'foo/b.txt' }) test_util.actions.open({ tmpdir.path }) - test_util.actions.focus("foo/") - vim.api.nvim_feedkeys("dd", "x", true) + test_util.actions.focus('foo/') + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() - tmpdir:assert_not_exists("foo") - tmpdir:assert_exists("a.txt") - test_util.actions.open({ "--trash", tmpdir.path }) - assert.are.same({ "foo/" }, test_util.parse_entries(0)) + tmpdir:assert_not_exists('foo') + tmpdir:assert_exists('a.txt') + test_util.actions.open({ '--trash', tmpdir.path }) + assert.are.same({ 'foo/' }, test_util.parse_entries(0)) end) - a.it("deleting a file from trash deletes it permanently", function() - tmpdir:create({ "a.txt" }) + a.it('deleting a file from trash deletes it permanently', function() + tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) - test_util.actions.focus("a.txt") - vim.api.nvim_feedkeys("dd", "x", true) + test_util.actions.focus('a.txt') + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() - test_util.actions.open({ "--trash", tmpdir.path }) - test_util.actions.focus("a.txt") - vim.api.nvim_feedkeys("dd", "x", true) + test_util.actions.open({ '--trash', tmpdir.path }) + test_util.actions.focus('a.txt') + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() test_util.actions.reload() - tmpdir:assert_not_exists("a.txt") + tmpdir:assert_not_exists('a.txt') assert.are.same({}, test_util.parse_entries(0)) end) - a.it("cannot create files in the trash", function() - tmpdir:create({ "a.txt" }) + a.it('cannot create files in the trash', function() + tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) - test_util.actions.focus("a.txt") - vim.api.nvim_feedkeys("dd", "x", true) + test_util.actions.focus('a.txt') + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() - test_util.actions.open({ "--trash", tmpdir.path }) - vim.api.nvim_feedkeys("onew_file.txt", "x", true) + test_util.actions.open({ '--trash', tmpdir.path }) + vim.api.nvim_feedkeys('onew_file.txt', 'x', true) test_util.actions.save() test_util.actions.reload() - assert.are.same({ "a.txt" }, test_util.parse_entries(0)) + assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it("cannot rename files in the trash", function() - tmpdir:create({ "a.txt" }) + a.it('cannot rename files in the trash', function() + tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) - test_util.actions.focus("a.txt") - vim.api.nvim_feedkeys("dd", "x", true) + test_util.actions.focus('a.txt') + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() - test_util.actions.open({ "--trash", tmpdir.path }) - vim.api.nvim_feedkeys("0facwnew_name", "x", true) + test_util.actions.open({ '--trash', tmpdir.path }) + vim.api.nvim_feedkeys('0facwnew_name', 'x', true) test_util.actions.save() test_util.actions.reload() - assert.are.same({ "a.txt" }, test_util.parse_entries(0)) + assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it("cannot copy files in the trash", function() - tmpdir:create({ "a.txt" }) + a.it('cannot copy files in the trash', function() + tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) - test_util.actions.focus("a.txt") - vim.api.nvim_feedkeys("dd", "x", true) + test_util.actions.focus('a.txt') + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() - test_util.actions.open({ "--trash", tmpdir.path }) - vim.api.nvim_feedkeys("yypp", "x", true) + test_util.actions.open({ '--trash', tmpdir.path }) + vim.api.nvim_feedkeys('yypp', 'x', true) test_util.actions.save() test_util.actions.reload() - assert.are.same({ "a.txt" }, test_util.parse_entries(0)) + assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it("can restore files from trash", function() - tmpdir:create({ "a.txt" }) + a.it('can restore files from trash', function() + tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) - test_util.actions.focus("a.txt") - vim.api.nvim_feedkeys("dd", "x", true) + test_util.actions.focus('a.txt') + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() - test_util.actions.open({ "--trash", tmpdir.path }) - vim.api.nvim_feedkeys("dd", "x", true) + test_util.actions.open({ '--trash', tmpdir.path }) + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.open({ tmpdir.path }) - vim.api.nvim_feedkeys("p", "x", true) + vim.api.nvim_feedkeys('p', 'x', true) test_util.actions.save() test_util.actions.reload() - assert.are.same({ "a.txt" }, test_util.parse_entries(0)) + assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) tmpdir:assert_fs({ - ["a.txt"] = "a.txt", + ['a.txt'] = 'a.txt', }) end) - a.it("can have multiple files with the same name in trash", function() - tmpdir:create({ "a.txt" }) + a.it('can have multiple files with the same name in trash', function() + tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) - vim.api.nvim_feedkeys("dd", "x", true) + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() - tmpdir:create({ "a.txt" }) + tmpdir:create({ 'a.txt' }) test_util.actions.reload() - vim.api.nvim_feedkeys("dd", "x", true) + vim.api.nvim_feedkeys('dd', 'x', true) test_util.actions.save() - test_util.actions.open({ "--trash", tmpdir.path }) - assert.are.same({ "a.txt", "a.txt" }, test_util.parse_entries(0)) + test_util.actions.open({ '--trash', tmpdir.path }) + assert.are.same({ 'a.txt', 'a.txt' }, test_util.parse_entries(0)) end) end) diff --git a/tests/url_spec.lua b/tests/url_spec.lua index 32d801e..46b7af7 100644 --- a/tests/url_spec.lua +++ b/tests/url_spec.lua @@ -1,15 +1,15 @@ -local oil = require("oil") -local util = require("oil.util") -describe("url", function() - it("get_url_for_path", function() +local oil = require('oil') +local util = require('oil.util') +describe('url', function() + it('get_url_for_path', function() local cases = { - { "", "oil://" .. util.addslash(vim.fn.getcwd()) }, - { "term://~/oil.nvim//52953:/bin/sh", "oil://" .. vim.loop.os_homedir() .. "/oil.nvim/" }, - { "/foo/bar.txt", "oil:///foo/", "bar.txt" }, - { "oil:///foo/bar.txt", "oil:///foo/", "bar.txt" }, - { "oil:///", "oil:///" }, - { "oil-ssh://user@hostname:8888//bar.txt", "oil-ssh://user@hostname:8888//", "bar.txt" }, - { "oil-ssh://user@hostname:8888//", "oil-ssh://user@hostname:8888//" }, + { '', 'oil://' .. util.addslash(vim.fn.getcwd()) }, + { 'term://~/oil.nvim//52953:/bin/sh', 'oil://' .. vim.loop.os_homedir() .. '/oil.nvim/' }, + { '/foo/bar.txt', 'oil:///foo/', 'bar.txt' }, + { 'oil:///foo/bar.txt', 'oil:///foo/', 'bar.txt' }, + { 'oil:///', 'oil:///' }, + { 'oil-ssh://user@hostname:8888//bar.txt', 'oil-ssh://user@hostname:8888//', 'bar.txt' }, + { 'oil-ssh://user@hostname:8888//', 'oil-ssh://user@hostname:8888//' }, } for _, case in ipairs(cases) do local input, expected, expected_basename = unpack(case) diff --git a/tests/util_spec.lua b/tests/util_spec.lua index 3193842..5796398 100644 --- a/tests/util_spec.lua +++ b/tests/util_spec.lua @@ -1,10 +1,10 @@ -local util = require("oil.util") -describe("util", function() - it("url_escape", function() +local util = require('oil.util') +describe('util', function() + it('url_escape', function() local cases = { - { "foobar", "foobar" }, - { "foo bar", "foo%20bar" }, - { "/foo/bar", "%2Ffoo%2Fbar" }, + { 'foobar', 'foobar' }, + { 'foo bar', 'foo%20bar' }, + { '/foo/bar', '%2Ffoo%2Fbar' }, } for _, case in ipairs(cases) do local input, expected = unpack(case) @@ -13,12 +13,12 @@ describe("util", function() end end) - it("url_unescape", function() + it('url_unescape', function() local cases = { - { "foobar", "foobar" }, - { "foo%20bar", "foo bar" }, - { "%2Ffoo%2Fbar", "/foo/bar" }, - { "foo%%bar", "foo%%bar" }, + { 'foobar', 'foobar' }, + { 'foo%20bar', 'foo bar' }, + { '%2Ffoo%2Fbar', '/foo/bar' }, + { 'foo%%bar', 'foo%%bar' }, } for _, case in ipairs(cases) do local input, expected = unpack(case) diff --git a/tests/win_options_spec.lua b/tests/win_options_spec.lua index cb638a7..d6db3f5 100644 --- a/tests/win_options_spec.lua +++ b/tests/win_options_spec.lua @@ -1,62 +1,62 @@ -require("plenary.async").tests.add_to_env() -local oil = require("oil") -local test_util = require("tests.test_util") +require('plenary.async').tests.add_to_env() +local oil = require('oil') +local test_util = require('tests.test_util') -a.describe("window options", function() +a.describe('window options', function() after_each(function() test_util.reset_editor() end) - a.it("Restores window options on close", function() - vim.cmd.edit({ args = { "README.md" } }) + a.it('Restores window options on close', function() + vim.cmd.edit({ args = { 'README.md' } }) test_util.oil_open() - assert.equals("no", vim.o.signcolumn) + assert.equals('no', vim.o.signcolumn) oil.close() - assert.equals("auto", vim.o.signcolumn) + assert.equals('auto', vim.o.signcolumn) end) - a.it("Restores window options on edit", function() + a.it('Restores window options on edit', function() test_util.oil_open() - assert.equals("no", vim.o.signcolumn) - vim.cmd.edit({ args = { "README.md" } }) - assert.equals("auto", vim.o.signcolumn) + assert.equals('no', vim.o.signcolumn) + vim.cmd.edit({ args = { 'README.md' } }) + assert.equals('auto', vim.o.signcolumn) end) - a.it("Restores window options on split ", function() + a.it('Restores window options on split ', function() test_util.oil_open() - assert.equals("no", vim.o.signcolumn) - vim.cmd.split({ args = { "README.md" } }) - assert.equals("auto", vim.o.signcolumn) + assert.equals('no', vim.o.signcolumn) + vim.cmd.split({ args = { 'README.md' } }) + assert.equals('auto', vim.o.signcolumn) end) - a.it("Restores window options on split", function() + a.it('Restores window options on split', function() test_util.oil_open() - assert.equals("no", vim.o.signcolumn) + assert.equals('no', vim.o.signcolumn) vim.cmd.split() - vim.cmd.edit({ args = { "README.md" } }) - assert.equals("auto", vim.o.signcolumn) + vim.cmd.edit({ args = { 'README.md' } }) + assert.equals('auto', vim.o.signcolumn) end) - a.it("Restores window options on tabnew ", function() + a.it('Restores window options on tabnew ', function() test_util.oil_open() - assert.equals("no", vim.o.signcolumn) - vim.cmd.tabnew({ args = { "README.md" } }) - assert.equals("auto", vim.o.signcolumn) + assert.equals('no', vim.o.signcolumn) + vim.cmd.tabnew({ args = { 'README.md' } }) + assert.equals('auto', vim.o.signcolumn) end) - a.it("Restores window options on tabnew", function() + a.it('Restores window options on tabnew', function() test_util.oil_open() - assert.equals("no", vim.o.signcolumn) + assert.equals('no', vim.o.signcolumn) vim.cmd.tabnew() - vim.cmd.edit({ args = { "README.md" } }) - assert.equals("auto", vim.o.signcolumn) + vim.cmd.edit({ args = { 'README.md' } }) + assert.equals('auto', vim.o.signcolumn) end) - a.it("Sets the window options when re-entering oil buffer", function() + a.it('Sets the window options when re-entering oil buffer', function() oil.open() - test_util.wait_for_autocmd({ "User", pattern = "OilEnter" }) + test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) assert.truthy(vim.w.oil_did_enter) - vim.cmd.edit({ args = { "README.md" } }) + vim.cmd.edit({ args = { 'README.md' } }) assert.falsy(vim.w.oil_did_enter) oil.open() assert.truthy(vim.w.oil_did_enter) diff --git a/vim.toml b/vim.toml new file mode 100644 index 0000000..0fbe00a --- /dev/null +++ b/vim.toml @@ -0,0 +1,36 @@ +[selene] +base = "lua51" +name = "vim" + +[vim] +any = true + +[jit] +any = true + +[bit] +any = true + +[assert] +any = true + +[a] +any = true + +[describe] +any = true + +[it] +any = true + +[before_each] +any = true + +[after_each] +any = true + +[spy] +any = true + +[stub] +any = true From a4da206b672d0e173b8d2db578144172a199882f Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 22 Feb 2026 00:04:18 -0500 Subject: [PATCH 05/77] doc: canonicalize all upstream issues (#21) --- README.md | 167 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 135 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 3792191..c9422ad 100644 --- a/README.md +++ b/README.md @@ -11,51 +11,154 @@ upstream yet.
Changes from upstream -### PRs +### Cherry-picked PRs Upstream PRs cherry-picked or adapted into this fork. | PR | Description | Commit | |---|---|---| -| [#495](https://github.com/stevearc/oil.nvim/pull/495) | Cancel visual/operator-pending mode on close instead of closing buffer | [`16f3d7b`](https://github.com/barrettruth/oil.nvim/commit/16f3d7b) | -| [#537](https://github.com/stevearc/oil.nvim/pull/537) | Configurable file and directory creation permissions (`new_file_mode`, `new_dir_mode`) | [`c6b4a7a`](https://github.com/barrettruth/oil.nvim/commit/c6b4a7a) | -| [#578](https://github.com/stevearc/oil.nvim/issues/578) | Recipe to disable hidden file dimming by relinking `Oil*Hidden` groups | [`38db6cf`](https://github.com/barrettruth/oil.nvim/commit/38db6cf) | -| [#618](https://github.com/stevearc/oil.nvim/pull/618) | Opt-in filetype detection for icons via `use_slow_filetype_detection` | [`ded1725`](https://github.com/barrettruth/oil.nvim/commit/ded1725) | -| [#644](https://github.com/stevearc/oil.nvim/pull/644) | Pass full entry to `is_hidden_file` and `is_always_hidden` callbacks | [`4ab4765`](https://github.com/barrettruth/oil.nvim/commit/4ab4765) | -| [#645](https://github.com/stevearc/oil.nvim/pull/645) | Add `close_float` action (close only floating oil windows) | [`f6bcdda`](https://github.com/barrettruth/oil.nvim/commit/f6bcdda) | -| [#690](https://github.com/stevearc/oil.nvim/pull/690) | Add `OilFileIcon` highlight group as fallback for unrecognized icons | [`ce64ae1`](https://github.com/barrettruth/oil.nvim/commit/ce64ae1) | -| [#697](https://github.com/stevearc/oil.nvim/pull/697) | Recipe for custom file extension column with sorting | [`dcb3a08`](https://github.com/barrettruth/oil.nvim/commit/dcb3a08) | -| [#698](https://github.com/stevearc/oil.nvim/pull/698) | Executable file highlighting (`OilExecutable`, `OilExecutableHidden`) | [`41556ec`](https://github.com/barrettruth/oil.nvim/commit/41556ec), [`85ed9b8`](https://github.com/barrettruth/oil.nvim/commit/85ed9b8) | -| [#717](https://github.com/stevearc/oil.nvim/pull/717) | Add malewicz1337/oil-git.nvim to third-party extensions | [`582d9fc`](https://github.com/barrettruth/oil.nvim/commit/582d9fc) | -| [#720](https://github.com/stevearc/oil.nvim/pull/720) | Gate `BufAdd` autocmd behind `default_file_explorer` check | [`2228f80`](https://github.com/barrettruth/oil.nvim/commit/2228f80) | -| [#722](https://github.com/stevearc/oil.nvim/pull/722) | Fix dead freedesktop trash specification URL | [`b92ecb0`](https://github.com/barrettruth/oil.nvim/commit/b92ecb0) | -| [#723](https://github.com/stevearc/oil.nvim/pull/723) | Emit `OilReadPost` user event after every buffer render | [`29239d5`](https://github.com/barrettruth/oil.nvim/commit/29239d5) | -| [#725](https://github.com/stevearc/oil.nvim/pull/725) | Normalize keymap keys before config merge (`` = ``) | [`723145c`](https://github.com/barrettruth/oil.nvim/commit/723145c) | -| [#727](https://github.com/stevearc/oil.nvim/pull/727) | Clarify `get_current_dir` nil return and add Telescope recipe | [`eed6697`](https://github.com/barrettruth/oil.nvim/commit/eed6697) | +| [#495](https://github.com/stevearc/oil.nvim/pull/495) | Cancel visual/operator-pending mode on close | [`16f3d7b`](https://github.com/barrettruth/oil.nvim/commit/16f3d7b) | +| [#537](https://github.com/stevearc/oil.nvim/pull/537) | Configurable file/directory creation permissions | [`c6b4a7a`](https://github.com/barrettruth/oil.nvim/commit/c6b4a7a) | +| [#618](https://github.com/stevearc/oil.nvim/pull/618) | Opt-in filetype detection for icons | [`ded1725`](https://github.com/barrettruth/oil.nvim/commit/ded1725) | +| [#644](https://github.com/stevearc/oil.nvim/pull/644) | Pass entry to `is_hidden_file`/`is_always_hidden` | [`4ab4765`](https://github.com/barrettruth/oil.nvim/commit/4ab4765) | +| [#697](https://github.com/stevearc/oil.nvim/pull/697) | Recipe for file extension column | [`dcb3a08`](https://github.com/barrettruth/oil.nvim/commit/dcb3a08) | +| [#698](https://github.com/stevearc/oil.nvim/pull/698) | Executable file highlighting | [`41556ec`](https://github.com/barrettruth/oil.nvim/commit/41556ec), [`85ed9b8`](https://github.com/barrettruth/oil.nvim/commit/85ed9b8) | +| [#717](https://github.com/stevearc/oil.nvim/pull/717) | Add oil-git.nvim to extensions | [`582d9fc`](https://github.com/barrettruth/oil.nvim/commit/582d9fc) | +| [#720](https://github.com/stevearc/oil.nvim/pull/720) | Gate `BufAdd` autocmd behind config check | [`2228f80`](https://github.com/barrettruth/oil.nvim/commit/2228f80) | +| [#722](https://github.com/stevearc/oil.nvim/pull/722) | Fix freedesktop trash URL | [`b92ecb0`](https://github.com/barrettruth/oil.nvim/commit/b92ecb0) | +| [#723](https://github.com/stevearc/oil.nvim/pull/723) | Emit `OilReadPost` event after render | [`29239d5`](https://github.com/barrettruth/oil.nvim/commit/29239d5) | +| [#725](https://github.com/stevearc/oil.nvim/pull/725) | Normalize keymap keys before config merge | [`723145c`](https://github.com/barrettruth/oil.nvim/commit/723145c) | +| [#727](https://github.com/stevearc/oil.nvim/pull/727) | Clarify `get_current_dir` nil + Telescope recipe | [`eed6697`](https://github.com/barrettruth/oil.nvim/commit/eed6697) | + +### Open upstream PRs + +Open PRs on upstream not yet incorporated into this fork. + +| PR | Description | Status | +|---|---|---| +| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR, 0 changes | +| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | +| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable — fork uses different release process | +| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | +| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | +| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite for multi-level dirs, tests | +| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | +| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [barrettruth/oil.nvim#2](https://github.com/barrettruth/oil.nvim/issues/2) | ### Issues -Upstream issues triaged against this fork. +All open upstream issues, triaged against this fork. -| Issue | Status | Resolution | +**Status key:** `fixed` = original fix in fork, `resolved` = addressed by cherry-picked PR, +`not actionable` = can't/won't fix, `tracking` = known/not yet addressed, `open` = not yet triaged. + +| Issue | Status | Notes | |---|---|---| -| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — implemented by PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in neovim ([neovim#34940](https://github.com/neovim/neovim/pull/34940)) | -| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | Question — j/k remapping, answered in comments | -| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro from reporter | +| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | +| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | +| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | +| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | +| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | +| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | +| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | +| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | +| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | +| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | +| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | +| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | +| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | +| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | +| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | +| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | +| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | +| [#302](https://github.com/stevearc/oil.nvim/issues/302) | open | C-o parent nav makes buffer buflisted (P0) | +| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | +| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | +| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | +| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | +| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | +| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | +| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | +| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | +| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | +| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | +| [#363](https://github.com/stevearc/oil.nvim/issues/363) | open | `prompt_save_on_select_new_entry` uses wrong prompt | +| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | +| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | +| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | +| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | +| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | +| [#392](https://github.com/stevearc/oil.nvim/issues/392) | open | Option to skip delete prompt | +| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | +| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | +| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | +| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | +| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | +| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | +| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | +| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | +| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | +| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | +| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | +| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | +| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | +| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | +| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | +| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | +| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | +| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | +| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | +| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | +| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | +| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | +| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | +| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | +| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | +| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/oil.nvim/commit/38db6cf) | | [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | -| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin issue | -| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation-in-progress race — no reliable repro | -| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [`fe16993`](https://github.com/barrettruth/oil.nvim/commit/fe16993) | +| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | +| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | +| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | +| [#612](https://github.com/stevearc/oil.nvim/issues/612) | open | Delete buffers on file delete (P2) | +| [#615](https://github.com/stevearc/oil.nvim/issues/615) | open | Cursor at name column on o/O (P2) | +| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | +| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | +| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | +| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | +| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | +| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [PR #12](https://github.com/barrettruth/oil.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/oil.nvim/commit/fe16993)) | +| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | +| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | +| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | | [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/oil.nvim/commit/ca834cf) | -| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Extra buffer on session reload — no repro | -| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [`70861e5`](https://github.com/barrettruth/oil.nvim/commit/70861e5) | +| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/oil.nvim/commit/f6bcdda) | +| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | +| [#650](https://github.com/stevearc/oil.nvim/issues/650) | open | Emit LSP `workspace.fileOperations` events | +| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | +| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | +| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | +| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | +| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | +| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [PR #11](https://github.com/barrettruth/oil.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/oil.nvim/commit/70861e5)) | +| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | | [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/oil.nvim/commit/9110a1a) | -| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — implemented by PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — fixed by PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | -| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [`01b860e`](https://github.com/barrettruth/oil.nvim/commit/01b860e) | -| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — already answered | -| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules delete — libuv/neovim bug | +| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | +| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | +| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#682](https://github.com/stevearc/oil.nvim/issues/682) | open | `get_current_dir()` nil in non-telescope context | +| [#683](https://github.com/stevearc/oil.nvim/issues/683) | open | Path not shown in floating mode | +| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | +| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | +| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/oil.nvim/commit/ce64ae1) | +| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | +| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | +| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [PR #10](https://github.com/barrettruth/oil.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/oil.nvim/commit/01b860e)) | +| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | +| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | | [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap |
From 6be0148eef5820b8e1aa2bc33ef72be589adf784 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 00:26:54 -0500 Subject: [PATCH 06/77] build: migrate test framework from plenary to busted Problem: plenary.nvim is deprecated. The test suite depends on plenary's async test runner and coroutine-based utilities, tying the project to an unmaintained dependency. CI also tests against Neovim 0.8-0.11, which are no longer relevant. Solution: replace plenary with busted + nlua (nvim -l). Convert all async test patterns (a.wrap, a.util.sleep, a.util.scheduler) to synchronous equivalents using vim.wait. Rename tests/ to spec/ to follow busted convention. Replace the CI test matrix with nvim-busted-action targeting stable/nightly only. Add .busted config, luarocks test_dependencies, and update the nix devshell. --- .busted | 9 ++++ .github/workflows/install_nvim.sh | 16 ------ .github/workflows/tests.yml | 32 +++++------- .gitignore | 1 - Makefile | 6 +-- flake.nix | 4 ++ oil.nvim-scm-1.rockspec | 9 ++++ run_tests.sh | 24 --------- {tests => spec}/altbuf_spec.lua | 38 ++++++-------- {tests => spec}/close_spec.lua | 19 ++++--- {tests => spec}/config_spec.lua | 0 {tests => spec}/files_spec.lua | 55 +++++++++----------- {tests => spec}/manual_progress.lua | 0 spec/minimal_init.lua | 8 +++ {tests => spec}/move_rename_spec.lua | 2 +- {tests => spec}/mutator_spec.lua | 29 ++++------- {tests => spec}/parser_spec.lua | 3 +- {tests => spec}/path_spec.lua | 0 {tests => spec}/preview_spec.lua | 17 +++---- {tests => spec}/regression_spec.lua | 47 +++++++---------- {tests => spec}/select_spec.lua | 43 +++++++--------- {tests => spec}/test_util.lua | 76 ++++++++++++++++++++-------- {tests => spec}/tmpdir.lua | 64 ++++++++++------------- {tests => spec}/trash_spec.lua | 29 +++++------ {tests => spec}/url_spec.lua | 0 {tests => spec}/util_spec.lua | 0 {tests => spec}/win_options_spec.lua | 19 ++++--- tests/minimal_init.lua | 5 -- 28 files changed, 257 insertions(+), 298 deletions(-) create mode 100644 .busted delete mode 100644 .github/workflows/install_nvim.sh delete mode 100755 run_tests.sh rename {tests => spec}/altbuf_spec.lua (75%) rename {tests => spec}/close_spec.lua (71%) rename {tests => spec}/config_spec.lua (100%) rename {tests => spec}/files_spec.lua (75%) rename {tests => spec}/manual_progress.lua (100%) create mode 100644 spec/minimal_init.lua rename {tests => spec}/move_rename_spec.lua (98%) rename {tests => spec}/mutator_spec.lua (94%) rename {tests => spec}/parser_spec.lua (98%) rename {tests => spec}/path_spec.lua (100%) rename {tests => spec}/preview_spec.lua (72%) rename {tests => spec}/regression_spec.lua (73%) rename {tests => spec}/select_spec.lua (68%) rename {tests => spec}/test_util.lua (73%) rename {tests => spec}/tmpdir.lua (70%) rename {tests => spec}/trash_spec.lua (85%) rename {tests => spec}/url_spec.lua (100%) rename {tests => spec}/util_spec.lua (100%) rename {tests => spec}/win_options_spec.lua (72%) delete mode 100644 tests/minimal_init.lua diff --git a/.busted b/.busted new file mode 100644 index 0000000..f729b3e --- /dev/null +++ b/.busted @@ -0,0 +1,9 @@ +return { + _all = { + lua = "nlua", + }, + default = { + ROOT = { "./spec/" }, + helper = "spec/minimal_init.lua", + }, +} diff --git a/.github/workflows/install_nvim.sh b/.github/workflows/install_nvim.sh deleted file mode 100644 index 9ba2d26..0000000 --- a/.github/workflows/install_nvim.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -set -e -version="${NVIM_TAG-stable}" -dl_name="nvim-linux-x86_64.appimage" -# The appimage name changed in v0.10.4 -if python -c 'from packaging.version import Version; import sys; sys.exit(not (Version(sys.argv[1]) < Version("v0.10.4")))' "$version" 2>/dev/null; then - dl_name="nvim.appimage" -fi -curl -sL "https://github.com/neovim/neovim/releases/download/${version}/${dl_name}" -o nvim.appimage -chmod +x nvim.appimage -./nvim.appimage --appimage-extract >/dev/null -rm -f nvim.appimage -mkdir -p ~/.local/share/nvim -mv squashfs-root ~/.local/share/nvim/appimage -sudo ln -s "$HOME/.local/share/nvim/appimage/AppRun" /usr/bin/nvim -/usr/bin/nvim --version diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 05dbd67..33fe515 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ on: jobs: selene: name: Selene - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: NTBBloodbath/selene-action@v1.0.0 @@ -22,7 +22,7 @@ jobs: stylua: name: StyLua - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Stylua @@ -30,11 +30,11 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} version: v2.1.0 - args: --check lua tests + args: --check lua spec typecheck: name: typecheck - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: mrcjkb/lua-typecheck-action@v0 @@ -45,24 +45,16 @@ jobs: run_tests: strategy: + fail-fast: false matrix: - include: - - nvim_tag: v0.8.3 - - nvim_tag: v0.9.4 - - nvim_tag: v0.10.4 - - nvim_tag: v0.11.0 + nvim_version: + - stable + - nightly name: Run tests - runs-on: ubuntu-22.04 - env: - NVIM_TAG: ${{ matrix.nvim_tag }} + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - - name: Install Neovim and dependencies - run: | - bash ./.github/workflows/install_nvim.sh - - - name: Run tests - run: | - bash ./run_tests.sh + - uses: nvim-neorocks/nvim-busted-action@v1 + with: + nvim_version: ${{ matrix.nvim_version }} diff --git a/.gitignore b/.gitignore index 70bd601..9f5d17c 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ luac.out .direnv/ .envrc -.testenv/ doc/tags scripts/benchmark.nvim perf/tmp/ diff --git a/Makefile b/Makefile index e3e622e..71c7c35 100644 --- a/Makefile +++ b/Makefile @@ -11,13 +11,13 @@ all: lint test ## test: run tests .PHONY: test test: - ./run_tests.sh + luarocks test --local ## lint: run selene and stylua .PHONY: lint lint: selene --display-style quiet . - stylua --check lua tests + stylua --check lua spec ## profile: use LuaJIT profiler to profile the plugin .PHONY: profile @@ -41,4 +41,4 @@ scripts/benchmark.nvim: ## clean: reset the repository to a clean state .PHONY: clean clean: - rm -rf .testenv perf/tmp profile.json + rm -rf perf/tmp profile.json diff --git a/flake.nix b/flake.nix index 5670f55..aebd6d8 100644 --- a/flake.nix +++ b/flake.nix @@ -22,6 +22,10 @@ pkgs.prettier pkgs.stylua pkgs.selene + (pkgs.luajit.withPackages (ps: [ + ps.busted + ps.nlua + ])) ]; }; }); diff --git a/oil.nvim-scm-1.rockspec b/oil.nvim-scm-1.rockspec index e58c602..8e1bb80 100644 --- a/oil.nvim-scm-1.rockspec +++ b/oil.nvim-scm-1.rockspec @@ -16,6 +16,15 @@ dependencies = { 'lua >= 5.1', } +test_dependencies = { + 'nlua', + 'busted >= 2.1.1', +} + +test = { + type = 'busted', +} + build = { type = 'builtin', } diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index 3018bc0..0000000 --- a/run_tests.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -set -e - -mkdir -p ".testenv/config/nvim" -mkdir -p ".testenv/data/nvim" -mkdir -p ".testenv/state/nvim" -mkdir -p ".testenv/run/nvim" -mkdir -p ".testenv/cache/nvim" -PLUGINS=".testenv/data/nvim/site/pack/plugins/start" - -if [ ! -e "$PLUGINS/plenary.nvim" ]; then - git clone --depth=1 https://github.com/nvim-lua/plenary.nvim.git "$PLUGINS/plenary.nvim" -else - (cd "$PLUGINS/plenary.nvim" && git pull) -fi - -XDG_CONFIG_HOME=".testenv/config" \ - XDG_DATA_HOME=".testenv/data" \ - XDG_STATE_HOME=".testenv/state" \ - XDG_RUNTIME_DIR=".testenv/run" \ - XDG_CACHE_HOME=".testenv/cache" \ - nvim --headless -u tests/minimal_init.lua \ - -c "PlenaryBustedDirectory ${1-tests} { minimal_init = './tests/minimal_init.lua' }" -echo "Success" diff --git a/tests/altbuf_spec.lua b/spec/altbuf_spec.lua similarity index 75% rename from tests/altbuf_spec.lua rename to spec/altbuf_spec.lua index 1f03ffb..b64bfc0 100644 --- a/tests/altbuf_spec.lua +++ b/spec/altbuf_spec.lua @@ -1,14 +1,13 @@ -require('plenary.async').tests.add_to_env() local fs = require('oil.fs') local oil = require('oil') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') -a.describe('Alternate buffer', function() +describe('Alternate buffer', function() after_each(function() test_util.reset_editor() end) - a.it('sets previous buffer as alternate', function() + it('sets previous buffer as alternate', function() vim.cmd.edit({ args = { 'foo' } }) oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) @@ -16,20 +15,19 @@ a.describe('Alternate buffer', function() assert.equals('foo', vim.fn.expand('#')) end) - a.it('sets previous buffer as alternate when editing url file', function() + it('sets previous buffer as alternate when editing url file', function() vim.cmd.edit({ args = { 'foo' } }) oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) local readme = fs.join(vim.fn.getcwd(), 'README.md') vim.cmd.edit({ args = { 'oil://' .. fs.os_to_posix_path(readme) } }) - -- We're gonna jump around to 2 different buffers test_util.wait_for_autocmd('BufEnter') test_util.wait_for_autocmd('BufEnter') assert.equals(readme, vim.api.nvim_buf_get_name(0)) assert.equals('foo', vim.fn.expand('#')) end) - a.it('sets previous buffer as alternate when editing oil://', function() + it('sets previous buffer as alternate when editing oil://', function() vim.cmd.edit({ args = { 'foo' } }) vim.cmd.edit({ args = { 'oil://' .. fs.os_to_posix_path(vim.fn.getcwd()) } }) test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) @@ -37,7 +35,7 @@ a.describe('Alternate buffer', function() assert.equals('foo', vim.fn.expand('#')) end) - a.it('preserves alternate buffer if editing the same file', function() + it('preserves alternate buffer if editing the same file', function() vim.cmd.edit({ args = { 'foo' } }) vim.cmd.edit({ args = { 'bar' } }) oil.open() @@ -46,7 +44,7 @@ a.describe('Alternate buffer', function() assert.equals('foo', vim.fn.expand('#')) end) - a.it('preserves alternate buffer if discarding changes', function() + it('preserves alternate buffer if discarding changes', function() vim.cmd.edit({ args = { 'foo' } }) vim.cmd.edit({ args = { 'bar' } }) oil.open() @@ -56,7 +54,7 @@ a.describe('Alternate buffer', function() assert.equals('foo', vim.fn.expand('#')) end) - a.it('sets previous buffer as alternate after multi-dir hops', function() + it('sets previous buffer as alternate after multi-dir hops', function() vim.cmd.edit({ args = { 'foo' } }) oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) @@ -70,7 +68,7 @@ a.describe('Alternate buffer', function() assert.equals('foo', vim.fn.expand('#')) end) - a.it('sets previous buffer as alternate when inside oil buffer', function() + it('sets previous buffer as alternate when inside oil buffer', function() vim.cmd.edit({ args = { 'foo' } }) oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) @@ -81,7 +79,7 @@ a.describe('Alternate buffer', function() assert.equals('bar', vim.fn.expand('#')) end) - a.it('preserves alternate when traversing oil dirs', function() + it('preserves alternate when traversing oil dirs', function() vim.cmd.edit({ args = { 'foo' } }) oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) @@ -95,7 +93,7 @@ a.describe('Alternate buffer', function() assert.equals('foo', vim.fn.expand('#')) end) - a.it('preserves alternate when opening preview', function() + it('preserves alternate when opening preview', function() vim.cmd.edit({ args = { 'foo' } }) oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) @@ -109,31 +107,27 @@ a.describe('Alternate buffer', function() assert.equals('foo', vim.fn.expand('#')) end) - a.describe('floating window', function() - a.it('sets previous buffer as alternate', function() + describe('floating window', function() + it('sets previous buffer as alternate', function() vim.cmd.edit({ args = { 'foo' } }) oil.open_float() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - -- This is lazy, but testing the actual select logic is more difficult. We can simply - -- replicate it by closing the current window and then doing the edit vim.api.nvim_win_close(0, true) vim.cmd.edit({ args = { 'bar' } }) assert.equals('foo', vim.fn.expand('#')) end) - a.it('preserves alternate buffer if editing the same file', function() + it('preserves alternate buffer if editing the same file', function() vim.cmd.edit({ args = { 'foo' } }) vim.cmd.edit({ args = { 'bar' } }) oil.open_float() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - -- This is lazy, but testing the actual select logic is more difficult. We can simply - -- replicate it by closing the current window and then doing the edit vim.api.nvim_win_close(0, true) vim.cmd.edit({ args = { 'bar' } }) assert.equals('foo', vim.fn.expand('#')) end) - a.it('preserves alternate buffer if discarding changes', function() + it('preserves alternate buffer if discarding changes', function() vim.cmd.edit({ args = { 'foo' } }) vim.cmd.edit({ args = { 'bar' } }) oil.open_float() @@ -142,7 +136,7 @@ a.describe('Alternate buffer', function() assert.equals('foo', vim.fn.expand('#')) end) - a.it('preserves alternate when traversing to a new file', function() + it('preserves alternate when traversing to a new file', function() vim.cmd.edit({ args = { 'foo' } }) oil.open_float() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) diff --git a/tests/close_spec.lua b/spec/close_spec.lua similarity index 71% rename from tests/close_spec.lua rename to spec/close_spec.lua index 61a1e13..0e15ab7 100644 --- a/tests/close_spec.lua +++ b/spec/close_spec.lua @@ -1,16 +1,15 @@ -require('plenary.async').tests.add_to_env() local oil = require('oil') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') -a.describe('close', function() - a.before_each(function() +describe('close', function() + before_each(function() test_util.reset_editor() end) - a.after_each(function() + after_each(function() test_util.reset_editor() end) - a.it('does not close buffer from visual mode', function() + it('does not close buffer from visual mode', function() oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) assert.equals('oil', vim.bo.filetype) @@ -20,22 +19,22 @@ a.describe('close', function() test_util.feedkeys({ '' }, 10) end) - a.it('does not close buffer from operator-pending mode', function() + it('does not close buffer from operator-pending mode', function() oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) assert.equals('oil', vim.bo.filetype) vim.api.nvim_feedkeys('d', 'n', false) - a.util.sleep(20) + vim.wait(20) local mode = vim.api.nvim_get_mode().mode if mode:match('^no') then oil.close() assert.equals('oil', vim.bo.filetype) end vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, true, true), 'n', false) - a.util.sleep(20) + vim.wait(20) end) - a.it('closes buffer from normal mode', function() + it('closes buffer from normal mode', function() oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) assert.equals('oil', vim.bo.filetype) diff --git a/tests/config_spec.lua b/spec/config_spec.lua similarity index 100% rename from tests/config_spec.lua rename to spec/config_spec.lua diff --git a/tests/files_spec.lua b/spec/files_spec.lua similarity index 75% rename from tests/files_spec.lua rename to spec/files_spec.lua index ae07ef8..299b434 100644 --- a/tests/files_spec.lua +++ b/spec/files_spec.lua @@ -1,21 +1,20 @@ -require('plenary.async').tests.add_to_env() -local TmpDir = require('tests.tmpdir') +local TmpDir = require('spec.tmpdir') local files = require('oil.adapters.files') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') -a.describe('files adapter', function() +describe('files adapter', function() local tmpdir - a.before_each(function() + before_each(function() tmpdir = TmpDir.new() end) - a.after_each(function() + after_each(function() if tmpdir then tmpdir:dispose() end test_util.reset_editor() end) - a.it('tmpdir creates files and asserts they exist', function() + it('tmpdir creates files and asserts they exist', function() tmpdir:create({ 'a.txt', 'foo/b.txt', 'foo/c.txt', 'bar/' }) tmpdir:assert_fs({ ['a.txt'] = 'a.txt', @@ -25,8 +24,8 @@ a.describe('files adapter', function() }) end) - a.it('Creates files', function() - local err = a.wrap(files.perform_action, 2)({ + it('Creates files', function() + local err = test_util.await(files.perform_action, 2, { url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt', entry_type = 'file', type = 'create', @@ -37,8 +36,8 @@ a.describe('files adapter', function() }) end) - a.it('Creates directories', function() - local err = a.wrap(files.perform_action, 2)({ + it('Creates directories', function() + local err = test_util.await(files.perform_action, 2, { url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a', entry_type = 'directory', type = 'create', @@ -49,11 +48,10 @@ a.describe('files adapter', function() }) end) - a.it('Deletes files', function() + it('Deletes files', function() tmpdir:create({ 'a.txt' }) - a.util.scheduler() local url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' - local err = a.wrap(files.perform_action, 2)({ + local err = test_util.await(files.perform_action, 2, { url = url, entry_type = 'file', type = 'delete', @@ -62,10 +60,10 @@ a.describe('files adapter', function() tmpdir:assert_fs({}) end) - a.it('Deletes directories', function() + it('Deletes directories', function() tmpdir:create({ 'a/' }) local url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' - local err = a.wrap(files.perform_action, 2)({ + local err = test_util.await(files.perform_action, 2, { url = url, entry_type = 'directory', type = 'delete', @@ -74,12 +72,11 @@ a.describe('files adapter', function() tmpdir:assert_fs({}) end) - a.it('Moves files', function() + it('Moves files', function() tmpdir:create({ 'a.txt' }) - a.util.scheduler() local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b.txt' - local err = a.wrap(files.perform_action, 2)({ + local err = test_util.await(files.perform_action, 2, { src_url = src_url, dest_url = dest_url, entry_type = 'file', @@ -91,12 +88,11 @@ a.describe('files adapter', function() }) end) - a.it('Moves directories', function() + it('Moves directories', function() tmpdir:create({ 'a/a.txt' }) - a.util.scheduler() local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b' - local err = a.wrap(files.perform_action, 2)({ + local err = test_util.await(files.perform_action, 2, { src_url = src_url, dest_url = dest_url, entry_type = 'directory', @@ -109,12 +105,11 @@ a.describe('files adapter', function() }) end) - a.it('Copies files', function() + it('Copies files', function() tmpdir:create({ 'a.txt' }) - a.util.scheduler() local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b.txt' - local err = a.wrap(files.perform_action, 2)({ + local err = test_util.await(files.perform_action, 2, { src_url = src_url, dest_url = dest_url, entry_type = 'file', @@ -127,12 +122,11 @@ a.describe('files adapter', function() }) end) - a.it('Recursively copies directories', function() + it('Recursively copies directories', function() tmpdir:create({ 'a/a.txt' }) - a.util.scheduler() local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b' - local err = a.wrap(files.perform_action, 2)({ + local err = test_util.await(files.perform_action, 2, { src_url = src_url, dest_url = dest_url, entry_type = 'directory', @@ -147,7 +141,7 @@ a.describe('files adapter', function() }) end) - a.it('Editing a new oil://path/ creates an oil buffer', function() + it('Editing a new oil://path/ creates an oil buffer', function() local tmpdir_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. '/' vim.cmd.edit({ args = { tmpdir_url } }) test_util.wait_oil_ready() @@ -155,11 +149,10 @@ a.describe('files adapter', function() vim.cmd.edit({ args = { new_url } }) test_util.wait_oil_ready() assert.equals('oil', vim.bo.filetype) - -- The normalization will add a '/' assert.equals(new_url .. '/', vim.api.nvim_buf_get_name(0)) end) - a.it('Editing a new oil://file.rb creates a normal buffer', function() + it('Editing a new oil://file.rb creates a normal buffer', function() local tmpdir_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. '/' vim.cmd.edit({ args = { tmpdir_url } }) test_util.wait_for_autocmd('BufReadPost') diff --git a/tests/manual_progress.lua b/spec/manual_progress.lua similarity index 100% rename from tests/manual_progress.lua rename to spec/manual_progress.lua diff --git a/spec/minimal_init.lua b/spec/minimal_init.lua new file mode 100644 index 0000000..ee514a4 --- /dev/null +++ b/spec/minimal_init.lua @@ -0,0 +1,8 @@ +vim.cmd([[set runtimepath=$VIMRUNTIME]]) +vim.opt.runtimepath:append('.') +vim.opt.packpath = {} +vim.o.swapfile = false +vim.fn.mkdir(vim.fn.stdpath('cache'), 'p') +vim.fn.mkdir(vim.fn.stdpath('data'), 'p') +vim.fn.mkdir(vim.fn.stdpath('state'), 'p') +require('spec.test_util').reset_editor() diff --git a/tests/move_rename_spec.lua b/spec/move_rename_spec.lua similarity index 98% rename from tests/move_rename_spec.lua rename to spec/move_rename_spec.lua index 16eb763..5b7348b 100644 --- a/tests/move_rename_spec.lua +++ b/spec/move_rename_spec.lua @@ -1,5 +1,5 @@ local fs = require('oil.fs') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') local util = require('oil.util') describe('update_moved_buffers', function() diff --git a/tests/mutator_spec.lua b/spec/mutator_spec.lua similarity index 94% rename from tests/mutator_spec.lua rename to spec/mutator_spec.lua index 0bddaab..74ce935 100644 --- a/tests/mutator_spec.lua +++ b/spec/mutator_spec.lua @@ -1,15 +1,14 @@ -require('plenary.async').tests.add_to_env() local cache = require('oil.cache') local constants = require('oil.constants') local mutator = require('oil.mutator') local test_adapter = require('oil.adapters.test') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') local FIELD_ID = constants.FIELD_ID local FIELD_NAME = constants.FIELD_NAME local FIELD_TYPE = constants.FIELD_TYPE -a.describe('mutator', function() +describe('mutator', function() after_each(function() test_util.reset_editor() end) @@ -196,9 +195,6 @@ a.describe('mutator', function() end) it('Handles parent child move ordering', function() - -- move parent into a child and child OUT of parent - -- MOVE /a/b -> /b - -- MOVE /a -> /b/a local move1 = { type = 'move', src_url = 'oil-test:///a/b', @@ -217,9 +213,6 @@ a.describe('mutator', function() end) it('Handles a delete inside a moved folder', function() - -- delete in directory and move directory - -- DELETE /a/b.txt - -- MOVE /a/ -> /b/ local del = { type = 'delete', url = 'oil-test:///a/b.txt', @@ -346,12 +339,12 @@ a.describe('mutator', function() end) end) - a.describe('perform actions', function() - a.it('creates new entries', function() + describe('perform actions', function() + it('creates new entries', function() local actions = { { type = 'create', url = 'oil-test:///a.txt', entry_type = 'file' }, } - a.wrap(mutator.process_actions, 2)(actions) + test_util.await(mutator.process_actions, 2, actions) local files = cache.list_url('oil-test:///') assert.are.same({ ['a.txt'] = { @@ -362,12 +355,12 @@ a.describe('mutator', function() }, files) end) - a.it('deletes entries', function() + it('deletes entries', function() local file = test_adapter.test_set('/a.txt', 'file') local actions = { { type = 'delete', url = 'oil-test:///a.txt', entry_type = 'file' }, } - a.wrap(mutator.process_actions, 2)(actions) + test_util.await(mutator.process_actions, 2, actions) local files = cache.list_url('oil-test:///') assert.are.same({}, files) assert.is_nil(cache.get_entry_by_id(file[FIELD_ID])) @@ -376,7 +369,7 @@ a.describe('mutator', function() end) end) - a.it('moves entries', function() + it('moves entries', function() local file = test_adapter.test_set('/a.txt', 'file') local actions = { { @@ -386,7 +379,7 @@ a.describe('mutator', function() entry_type = 'file', }, } - a.wrap(mutator.process_actions, 2)(actions) + test_util.await(mutator.process_actions, 2, actions) local files = cache.list_url('oil-test:///') local new_entry = { [FIELD_ID] = file[FIELD_ID], @@ -400,7 +393,7 @@ a.describe('mutator', function() assert.equals('oil-test:///', cache.get_parent_url(file[FIELD_ID])) end) - a.it('copies entries', function() + it('copies entries', function() local file = test_adapter.test_set('/a.txt', 'file') local actions = { { @@ -410,7 +403,7 @@ a.describe('mutator', function() entry_type = 'file', }, } - a.wrap(mutator.process_actions, 2)(actions) + test_util.await(mutator.process_actions, 2, actions) local files = cache.list_url('oil-test:///') local new_entry = { [FIELD_ID] = file[FIELD_ID] + 1, diff --git a/tests/parser_spec.lua b/spec/parser_spec.lua similarity index 98% rename from tests/parser_spec.lua rename to spec/parser_spec.lua index ef81405..563c001 100644 --- a/tests/parser_spec.lua +++ b/spec/parser_spec.lua @@ -1,8 +1,7 @@ -require('plenary.async').tests.add_to_env() local constants = require('oil.constants') local parser = require('oil.mutator.parser') local test_adapter = require('oil.adapters.test') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') local util = require('oil.util') local view = require('oil.view') diff --git a/tests/path_spec.lua b/spec/path_spec.lua similarity index 100% rename from tests/path_spec.lua rename to spec/path_spec.lua diff --git a/tests/preview_spec.lua b/spec/preview_spec.lua similarity index 72% rename from tests/preview_spec.lua rename to spec/preview_spec.lua index c5ba81a..030332d 100644 --- a/tests/preview_spec.lua +++ b/spec/preview_spec.lua @@ -1,25 +1,24 @@ -require('plenary.async').tests.add_to_env() -local TmpDir = require('tests.tmpdir') +local TmpDir = require('spec.tmpdir') local oil = require('oil') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') local util = require('oil.util') -a.describe('oil preview', function() +describe('oil preview', function() local tmpdir - a.before_each(function() + before_each(function() tmpdir = TmpDir.new() end) - a.after_each(function() + after_each(function() if tmpdir then tmpdir:dispose() end test_util.reset_editor() end) - a.it('opens preview window', function() + it('opens preview window', function() tmpdir:create({ 'a.txt' }) test_util.oil_open(tmpdir.path) - a.wrap(oil.open_preview, 2)() + test_util.await(oil.open_preview, 2) local preview_win = util.get_preview_win() assert.not_nil(preview_win) assert(preview_win) @@ -28,7 +27,7 @@ a.describe('oil preview', function() assert.are.same({ 'a.txt' }, preview_lines) end) - a.it('opens preview window when open(preview={})', function() + it('opens preview window when open(preview={})', function() tmpdir:create({ 'a.txt' }) test_util.oil_open(tmpdir.path, { preview = {} }) local preview_win = util.get_preview_win() diff --git a/tests/regression_spec.lua b/spec/regression_spec.lua similarity index 73% rename from tests/regression_spec.lua rename to spec/regression_spec.lua index 21bdddb..bfa5e53 100644 --- a/tests/regression_spec.lua +++ b/spec/regression_spec.lua @@ -1,16 +1,15 @@ -require('plenary.async').tests.add_to_env() -local TmpDir = require('tests.tmpdir') +local TmpDir = require('spec.tmpdir') local actions = require('oil.actions') local oil = require('oil') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') local view = require('oil.view') -a.describe('regression tests', function() +describe('regression tests', function() local tmpdir - a.before_each(function() + before_each(function() tmpdir = TmpDir.new() end) - a.after_each(function() + after_each(function() if tmpdir then tmpdir:dispose() tmpdir = nil @@ -18,8 +17,7 @@ a.describe('regression tests', function() test_util.reset_editor() end) - -- see https://github.com/stevearc/oil.nvim/issues/25 - a.it('can edit dirs that will be renamed to an existing buffer', function() + it('can edit dirs that will be renamed to an existing buffer', function() vim.cmd.edit({ args = { 'README.md' } }) vim.cmd.vsplit() vim.cmd.edit({ args = { '%:p:h' } }) @@ -31,8 +29,7 @@ a.describe('regression tests', function() assert.equals('oil', vim.bo.filetype) end) - -- https://github.com/stevearc/oil.nvim/issues/37 - a.it('places the cursor on correct entry when opening on file', function() + it('places the cursor on correct entry when opening on file', function() vim.cmd.edit({ args = { '.' } }) test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) local entry = oil.get_cursor_entry() @@ -46,8 +43,7 @@ a.describe('regression tests', function() assert.equals('README.md', entry and entry.name) end) - -- https://github.com/stevearc/oil.nvim/issues/64 - a.it("doesn't close floating windows oil didn't open itself", function() + it("doesn't close floating windows oil didn't open itself", function() local winid = vim.api.nvim_open_win(vim.fn.bufadd('README.md'), true, { relative = 'editor', row = 1, @@ -56,29 +52,27 @@ a.describe('regression tests', function() height = 100, }) oil.open() - a.util.sleep(10) + vim.wait(10) oil.close() - a.util.sleep(10) + vim.wait(10) assert.equals(winid, vim.api.nvim_get_current_win()) end) - -- https://github.com/stevearc/oil.nvim/issues/64 - a.it("doesn't close splits on oil.close", function() + it("doesn't close splits on oil.close", function() vim.cmd.edit({ args = { 'README.md' } }) vim.cmd.vsplit() local winid = vim.api.nvim_get_current_win() local bufnr = vim.api.nvim_get_current_buf() oil.open() - a.util.sleep(10) + vim.wait(10) oil.close() - a.util.sleep(10) + vim.wait(10) assert.equals(2, #vim.api.nvim_tabpage_list_wins(0)) assert.equals(winid, vim.api.nvim_get_current_win()) assert.equals(bufnr, vim.api.nvim_get_current_buf()) end) - -- https://github.com/stevearc/oil.nvim/issues/79 - a.it('Returns to empty buffer on close', function() + it('Returns to empty buffer on close', function() oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) oil.close() @@ -86,9 +80,8 @@ a.describe('regression tests', function() assert.equals('', vim.api.nvim_buf_get_name(0)) end) - a.it('All buffers set nomodified after save', function() + it('All buffers set nomodified after save', function() tmpdir:create({ 'a.txt' }) - a.util.scheduler() vim.cmd.edit({ args = { 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') } }) local first_dir = vim.api.nvim_get_current_buf() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) @@ -97,7 +90,6 @@ a.describe('regression tests', function() return vim.bo.modifiable end, 10) test_util.feedkeys({ 'p' }, 10) - a.util.scheduler() oil.save({ confirm = false }) vim.wait(1000, function() return vim.bo.modifiable @@ -105,11 +97,10 @@ a.describe('regression tests', function() tmpdir:assert_fs({ ['test/a.txt'] = 'a.txt', }) - -- The first oil buffer should not be modified anymore assert.falsy(vim.bo[first_dir].modified) end) - a.it("refreshing buffer doesn't lose track of it", function() + it("refreshing buffer doesn't lose track of it", function() vim.cmd.edit({ args = { '.' } }) test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) local bufnr = vim.api.nvim_get_current_buf() @@ -118,7 +109,7 @@ a.describe('regression tests', function() assert.are.same({ bufnr }, require('oil.view').get_all_buffers()) end) - a.it('can copy a file multiple times', function() + it('can copy a file multiple times', function() test_util.actions.open({ tmpdir.path }) vim.api.nvim_feedkeys('ifoo.txt', 'x', true) test_util.actions.save() @@ -133,10 +124,8 @@ a.describe('regression tests', function() }) end) - -- https://github.com/stevearc/oil.nvim/issues/355 - a.it('can open files from floating window', function() + it('can open files from floating window', function() tmpdir:create({ 'a.txt' }) - a.util.scheduler() oil.open_float(tmpdir.path) test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) actions.select.callback() diff --git a/tests/select_spec.lua b/spec/select_spec.lua similarity index 68% rename from tests/select_spec.lua rename to spec/select_spec.lua index 3f8621a..47c95ac 100644 --- a/tests/select_spec.lua +++ b/spec/select_spec.lua @@ -1,90 +1,85 @@ -require('plenary.async').tests.add_to_env() local oil = require('oil') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') -a.describe('oil select', function() +describe('oil select', function() after_each(function() test_util.reset_editor() end) - a.it('opens file under cursor', function() + it('opens file under cursor', function() test_util.oil_open() - -- Go to the bottom, so the cursor is not on a directory vim.cmd.normal({ args = { 'G' } }) - a.wrap(oil.select, 2)() + test_util.await(oil.select, 2) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals('oil', vim.bo.filetype) end) - a.it('opens file in new tab', function() + it('opens file in new tab', function() test_util.oil_open() local tabpage = vim.api.nvim_get_current_tabpage() - a.wrap(oil.select, 2)({ tab = true }) + test_util.await(oil.select, 2, { tab = true }) assert.equals(2, #vim.api.nvim_list_tabpages()) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals(tabpage, vim.api.nvim_get_current_tabpage()) end) - a.it('opens file in new split', function() + it('opens file in new split', function() test_util.oil_open() local winid = vim.api.nvim_get_current_win() - a.wrap(oil.select, 2)({ vertical = true }) + test_util.await(oil.select, 2, { vertical = true }) assert.equals(1, #vim.api.nvim_list_tabpages()) assert.equals(2, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals(winid, vim.api.nvim_get_current_win()) end) - a.it('opens multiple files in new tabs', function() + it('opens multiple files in new tabs', function() test_util.oil_open() vim.api.nvim_feedkeys('Vj', 'x', true) local tabpage = vim.api.nvim_get_current_tabpage() - a.wrap(oil.select, 2)({ tab = true }) + test_util.await(oil.select, 2, { tab = true }) assert.equals(3, #vim.api.nvim_list_tabpages()) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals(tabpage, vim.api.nvim_get_current_tabpage()) end) - a.it('opens multiple files in new splits', function() + it('opens multiple files in new splits', function() test_util.oil_open() vim.api.nvim_feedkeys('Vj', 'x', true) local winid = vim.api.nvim_get_current_win() - a.wrap(oil.select, 2)({ vertical = true }) + test_util.await(oil.select, 2, { vertical = true }) assert.equals(1, #vim.api.nvim_list_tabpages()) assert.equals(3, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals(winid, vim.api.nvim_get_current_win()) end) - a.describe('close after open', function() - a.it('same window', function() + describe('close after open', function() + it('same window', function() vim.cmd.edit({ args = { 'foo' } }) local bufnr = vim.api.nvim_get_current_buf() test_util.oil_open() - -- Go to the bottom, so the cursor is not on a directory vim.cmd.normal({ args = { 'G' } }) - a.wrap(oil.select, 2)({ close = true }) + test_util.await(oil.select, 2, { close = true }) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) - -- This one we actually don't expect the buffer to be the same as the initial buffer, because - -- we opened a file assert.not_equals(bufnr, vim.api.nvim_get_current_buf()) assert.not_equals('oil', vim.bo.filetype) end) - a.it('split', function() + it('split', function() vim.cmd.edit({ args = { 'foo' } }) local bufnr = vim.api.nvim_get_current_buf() local winid = vim.api.nvim_get_current_win() test_util.oil_open() - a.wrap(oil.select, 2)({ vertical = true, close = true }) + test_util.await(oil.select, 2, { vertical = true, close = true }) assert.equals(2, #vim.api.nvim_tabpage_list_wins(0)) assert.equals(bufnr, vim.api.nvim_win_get_buf(winid)) end) - a.it('tab', function() + it('tab', function() vim.cmd.edit({ args = { 'foo' } }) local bufnr = vim.api.nvim_get_current_buf() local tabpage = vim.api.nvim_get_current_tabpage() test_util.oil_open() - a.wrap(oil.select, 2)({ tab = true, close = true }) + test_util.await(oil.select, 2, { tab = true, close = true }) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) assert.equals(2, #vim.api.nvim_list_tabpages()) vim.api.nvim_set_current_tabpage(tabpage) diff --git a/tests/test_util.lua b/spec/test_util.lua similarity index 73% rename from tests/test_util.lua rename to spec/test_util.lua index b6c29a6..b77f6f1 100644 --- a/tests/test_util.lua +++ b/spec/test_util.lua @@ -1,4 +1,3 @@ -require('plenary.async').tests.add_to_env() local cache = require('oil.cache') local test_adapter = require('oil.adapters.test') local util = require('oil.util') @@ -34,15 +33,36 @@ local function throwiferr(err, ...) end end -M.oil_open = function(...) - a.wrap(require('oil').open, 3)(...) -end - M.await = function(fn, nargs, ...) - return throwiferr(a.wrap(fn, nargs)(...)) + local done = false + local results + local n_results = 0 + local args = { ... } + args[nargs] = function(...) + results = { ... } + n_results = select('#', ...) + done = true + end + fn(unpack(args, 1, nargs)) + vim.wait(10000, function() + return done + end, 10) + if not done then + error('M.await timed out') + end + return unpack(results, 1, n_results) end -M.wait_for_autocmd = a.wrap(function(autocmd, cb) +M.await_throwiferr = function(fn, nargs, ...) + return throwiferr(M.await(fn, nargs, ...)) +end + +M.oil_open = function(...) + M.await(require('oil').open, 3, ...) +end + +M.wait_for_autocmd = function(autocmd) + local triggered = false local opts = { pattern = '*', nested = true, @@ -53,30 +73,47 @@ M.wait_for_autocmd = a.wrap(function(autocmd, cb) autocmd = autocmd[1] opts[1] = nil end - opts.callback = vim.schedule_wrap(cb) - + opts.callback = vim.schedule_wrap(function() + triggered = true + end) vim.api.nvim_create_autocmd(autocmd, opts) -end, 2) + vim.wait(10000, function() + return triggered + end, 10) + if not triggered then + error('wait_for_autocmd timed out waiting for ' .. tostring(autocmd)) + end +end -M.wait_oil_ready = a.wrap(function(cb) - util.run_after_load(0, vim.schedule_wrap(cb)) -end, 1) +M.wait_oil_ready = function() + local ready = false + util.run_after_load( + 0, + vim.schedule_wrap(function() + ready = true + end) + ) + vim.wait(10000, function() + return ready + end, 10) + if not ready then + error('wait_oil_ready timed out') + end +end ---@param actions string[] ---@param timestep integer M.feedkeys = function(actions, timestep) timestep = timestep or 10 - a.util.sleep(timestep) + vim.wait(timestep) for _, action in ipairs(actions) do - a.util.sleep(timestep) + vim.wait(timestep) local escaped = vim.api.nvim_replace_termcodes(action, true, false, true) vim.api.nvim_feedkeys(escaped, 'm', true) end - a.util.sleep(timestep) - -- process pending keys until the queue is empty. - -- Note that this will exit insert mode. + vim.wait(timestep) vim.api.nvim_feedkeys('', 'x', true) - a.util.sleep(timestep) + vim.wait(timestep) end M.actions = { @@ -85,7 +122,6 @@ M.actions = { open = function(args) vim.schedule(function() vim.cmd.Oil({ args = args }) - -- If this buffer was already open, manually dispatch the autocmd to finish the wait if vim.b.oil_ready then vim.api.nvim_exec_autocmds('User', { pattern = 'OilEnter', diff --git a/tests/tmpdir.lua b/spec/tmpdir.lua similarity index 70% rename from tests/tmpdir.lua rename to spec/tmpdir.lua index f4d09e7..00a04fd 100644 --- a/tests/tmpdir.lua +++ b/spec/tmpdir.lua @@ -1,25 +1,18 @@ local fs = require('oil.fs') -local test_util = require('tests.test_util') - -local await = test_util.await +local test_util = require('spec.test_util') ---@param path string ----@param cb fun(err: nil|string) -local function touch(path, cb) - vim.loop.fs_open(path, 'w', 420, function(err, fd) -- 0644 - if err then - cb(err) - else - local shortpath = path:gsub('^[^' .. fs.sep .. ']*' .. fs.sep, '') - vim.loop.fs_write(fd, shortpath, nil, function(err2) - if err2 then - cb(err2) - else - vim.loop.fs_close(fd, cb) - end - end) - end - end) +local function touch(path) + local fd, open_err = vim.loop.fs_open(path, 'w', 420) -- 0644 + if not fd then + error(open_err) + end + local shortpath = path:gsub('^[^' .. fs.sep .. ']*' .. fs.sep, '') + local _, write_err = vim.loop.fs_write(fd, shortpath) + if write_err then + error(write_err) + end + vim.loop.fs_close(fd) end ---@param filepath string @@ -28,11 +21,14 @@ local function exists(filepath) local stat = vim.loop.fs_stat(filepath) return stat ~= nil and stat.type ~= nil end + local TmpDir = {} TmpDir.new = function() - local path = await(vim.loop.fs_mkdtemp, 2, 'oil_test_XXXXXXXXX') - a.util.scheduler() + local path, err = vim.loop.fs_mkdtemp('oil_test_XXXXXXXXX') + if not path then + error(err) + end return setmetatable({ path = path }, { __index = TmpDir, }) @@ -46,13 +42,12 @@ function TmpDir:create(paths) for i, piece in ipairs(pieces) do partial_path = fs.join(partial_path, piece) if i == #pieces and not vim.endswith(partial_path, fs.sep) then - await(touch, 2, partial_path) + touch(partial_path) elseif not exists(partial_path) then vim.loop.fs_mkdir(partial_path, 493) end end end - a.util.scheduler() end ---@param filepath string @@ -65,12 +60,10 @@ local read_file = function(filepath) local stat = vim.loop.fs_fstat(fd) local content = vim.loop.fs_read(fd, stat.size) vim.loop.fs_close(fd) - a.util.scheduler() return content end ---@param dir string ----@param cb fun(err: nil|string, entry: {type: oil.EntryType, name: string, root: string} local function walk(dir) local ret = {} for name, type in vim.fs.dir(dir) do @@ -112,12 +105,11 @@ local assert_fs = function(root, paths) end local expected_content = paths[shortpath] paths[shortpath] = nil - assert.truthy(expected_content, string.format("Unexpected entry '%s'", shortpath)) + assert(expected_content, string.format("Unexpected entry '%s'", shortpath)) if entry.type == 'file' then local data = read_file(fullpath) - assert.equals( - expected_content, - data, + assert( + expected_content == data, string.format( "File '%s' expected content '%s' received '%s'", shortpath, @@ -129,8 +121,8 @@ local assert_fs = function(root, paths) end for k, v in pairs(paths) do - assert.falsy( - k, + assert( + not k, string.format( "Expected %s '%s', but it was not found", v == true and 'directory' or 'file', @@ -142,27 +134,23 @@ end ---@param paths table function TmpDir:assert_fs(paths) - a.util.scheduler() assert_fs(self.path, paths) end function TmpDir:assert_exists(path) - a.util.scheduler() path = fs.join(self.path, path) local stat = vim.loop.fs_stat(path) - assert.truthy(stat, string.format("Expected path '%s' to exist", path)) + assert(stat, string.format("Expected path '%s' to exist", path)) end function TmpDir:assert_not_exists(path) - a.util.scheduler() path = fs.join(self.path, path) local stat = vim.loop.fs_stat(path) - assert.falsy(stat, string.format("Expected path '%s' to not exist", path)) + assert(not stat, string.format("Expected path '%s' to not exist", path)) end function TmpDir:dispose() - await(fs.recursive_delete, 3, 'directory', self.path) - a.util.scheduler() + test_util.await_throwiferr(fs.recursive_delete, 3, 'directory', self.path) end return TmpDir diff --git a/tests/trash_spec.lua b/spec/trash_spec.lua similarity index 85% rename from tests/trash_spec.lua rename to spec/trash_spec.lua index c3897e6..b34b40b 100644 --- a/tests/trash_spec.lua +++ b/spec/trash_spec.lua @@ -1,19 +1,18 @@ -require('plenary.async').tests.add_to_env() -local TmpDir = require('tests.tmpdir') -local test_util = require('tests.test_util') +local TmpDir = require('spec.tmpdir') +local test_util = require('spec.test_util') -a.describe('freedesktop', function() +describe('freedesktop', function() local tmpdir local tmphome local home = vim.env.XDG_DATA_HOME - a.before_each(function() + before_each(function() require('oil.config').delete_to_trash = true tmpdir = TmpDir.new() tmphome = TmpDir.new() package.loaded['oil.adapters.trash'] = require('oil.adapters.trash.freedesktop') vim.env.XDG_DATA_HOME = tmphome.path end) - a.after_each(function() + after_each(function() vim.env.XDG_DATA_HOME = home if tmpdir then tmpdir:dispose() @@ -25,7 +24,7 @@ a.describe('freedesktop', function() package.loaded['oil.adapters.trash'] = nil end) - a.it('files can be moved to the trash', function() + it('files can be moved to the trash', function() tmpdir:create({ 'a.txt', 'foo/b.txt' }) test_util.actions.open({ tmpdir.path }) test_util.actions.focus('a.txt') @@ -39,7 +38,7 @@ a.describe('freedesktop', function() assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it('deleting a file moves it to trash', function() + it('deleting a file moves it to trash', function() tmpdir:create({ 'a.txt', 'foo/b.txt' }) test_util.actions.open({ tmpdir.path }) test_util.actions.focus('a.txt') @@ -51,7 +50,7 @@ a.describe('freedesktop', function() assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it('deleting a directory moves it to trash', function() + it('deleting a directory moves it to trash', function() tmpdir:create({ 'a.txt', 'foo/b.txt' }) test_util.actions.open({ tmpdir.path }) test_util.actions.focus('foo/') @@ -63,7 +62,7 @@ a.describe('freedesktop', function() assert.are.same({ 'foo/' }, test_util.parse_entries(0)) end) - a.it('deleting a file from trash deletes it permanently', function() + it('deleting a file from trash deletes it permanently', function() tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) test_util.actions.focus('a.txt') @@ -78,7 +77,7 @@ a.describe('freedesktop', function() assert.are.same({}, test_util.parse_entries(0)) end) - a.it('cannot create files in the trash', function() + it('cannot create files in the trash', function() tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) test_util.actions.focus('a.txt') @@ -91,7 +90,7 @@ a.describe('freedesktop', function() assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it('cannot rename files in the trash', function() + it('cannot rename files in the trash', function() tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) test_util.actions.focus('a.txt') @@ -104,7 +103,7 @@ a.describe('freedesktop', function() assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it('cannot copy files in the trash', function() + it('cannot copy files in the trash', function() tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) test_util.actions.focus('a.txt') @@ -117,7 +116,7 @@ a.describe('freedesktop', function() assert.are.same({ 'a.txt' }, test_util.parse_entries(0)) end) - a.it('can restore files from trash', function() + it('can restore files from trash', function() tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) test_util.actions.focus('a.txt') @@ -135,7 +134,7 @@ a.describe('freedesktop', function() }) end) - a.it('can have multiple files with the same name in trash', function() + it('can have multiple files with the same name in trash', function() tmpdir:create({ 'a.txt' }) test_util.actions.open({ tmpdir.path }) vim.api.nvim_feedkeys('dd', 'x', true) diff --git a/tests/url_spec.lua b/spec/url_spec.lua similarity index 100% rename from tests/url_spec.lua rename to spec/url_spec.lua diff --git a/tests/util_spec.lua b/spec/util_spec.lua similarity index 100% rename from tests/util_spec.lua rename to spec/util_spec.lua diff --git a/tests/win_options_spec.lua b/spec/win_options_spec.lua similarity index 72% rename from tests/win_options_spec.lua rename to spec/win_options_spec.lua index d6db3f5..f62aa83 100644 --- a/tests/win_options_spec.lua +++ b/spec/win_options_spec.lua @@ -1,13 +1,12 @@ -require('plenary.async').tests.add_to_env() local oil = require('oil') -local test_util = require('tests.test_util') +local test_util = require('spec.test_util') -a.describe('window options', function() +describe('window options', function() after_each(function() test_util.reset_editor() end) - a.it('Restores window options on close', function() + it('Restores window options on close', function() vim.cmd.edit({ args = { 'README.md' } }) test_util.oil_open() assert.equals('no', vim.o.signcolumn) @@ -15,21 +14,21 @@ a.describe('window options', function() assert.equals('auto', vim.o.signcolumn) end) - a.it('Restores window options on edit', function() + it('Restores window options on edit', function() test_util.oil_open() assert.equals('no', vim.o.signcolumn) vim.cmd.edit({ args = { 'README.md' } }) assert.equals('auto', vim.o.signcolumn) end) - a.it('Restores window options on split ', function() + it('Restores window options on split ', function() test_util.oil_open() assert.equals('no', vim.o.signcolumn) vim.cmd.split({ args = { 'README.md' } }) assert.equals('auto', vim.o.signcolumn) end) - a.it('Restores window options on split', function() + it('Restores window options on split', function() test_util.oil_open() assert.equals('no', vim.o.signcolumn) vim.cmd.split() @@ -37,14 +36,14 @@ a.describe('window options', function() assert.equals('auto', vim.o.signcolumn) end) - a.it('Restores window options on tabnew ', function() + it('Restores window options on tabnew ', function() test_util.oil_open() assert.equals('no', vim.o.signcolumn) vim.cmd.tabnew({ args = { 'README.md' } }) assert.equals('auto', vim.o.signcolumn) end) - a.it('Restores window options on tabnew', function() + it('Restores window options on tabnew', function() test_util.oil_open() assert.equals('no', vim.o.signcolumn) vim.cmd.tabnew() @@ -52,7 +51,7 @@ a.describe('window options', function() assert.equals('auto', vim.o.signcolumn) end) - a.it('Sets the window options when re-entering oil buffer', function() + it('Sets the window options when re-entering oil buffer', function() oil.open() test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) assert.truthy(vim.w.oil_did_enter) diff --git a/tests/minimal_init.lua b/tests/minimal_init.lua deleted file mode 100644 index 8db9e9a..0000000 --- a/tests/minimal_init.lua +++ /dev/null @@ -1,5 +0,0 @@ -vim.opt.runtimepath:append('.') - -vim.o.swapfile = false -vim.bo.swapfile = false -require('tests.test_util').reset_editor() From 36cc369de30fe3f8cd2e3b645bdffc30e9fc715a Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 00:32:41 -0500 Subject: [PATCH 07/77] fix(ci): set ft plugin indent --- spec/minimal_init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/minimal_init.lua b/spec/minimal_init.lua index ee514a4..c070d64 100644 --- a/spec/minimal_init.lua +++ b/spec/minimal_init.lua @@ -2,6 +2,7 @@ vim.cmd([[set runtimepath=$VIMRUNTIME]]) vim.opt.runtimepath:append('.') vim.opt.packpath = {} vim.o.swapfile = false +vim.cmd('filetype plugin indent on') vim.fn.mkdir(vim.fn.stdpath('cache'), 'p') vim.fn.mkdir(vim.fn.stdpath('data'), 'p') vim.fn.mkdir(vim.fn.stdpath('state'), 'p') From 92ff4d57747a531220b630b4749cb9870bc080d6 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:39:20 -0500 Subject: [PATCH 08/77] fix(test): resolve busted migration test isolation issues (#25) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(test): resolve busted migration test isolation issues Problem: Two issues introduced during the plenary-to-busted migration (6be0148). First, altbuf_spec waited for two BufEnter events but oil:// → file resolution only fires one async BufEnter (the synchronous one from vim.cmd.edit fires before wait_for_autocmd is registered). Second, reset_editor kept the first window which could be a preview window with stale oil_preview/oil_source_win state, causing close_preview_window_if_not_in_oil to close the wrong window in subsequent tests. Solution: Wait for a single BufEnter in the altbuf test. Replace the window-keeping logic in reset_editor with vim.cmd.new() + vim.cmd.only() to guarantee a fresh window with no inherited state. This also fixes the preview_spec.lua:30 timeout which had the same root cause. 114/114 tests pass. * fix(ci): fix nightly tests and remove unused Makefile Problem: Neovim nightly's ftplugin/markdown.lua now calls vim.treesitter.start() unconditionally, which crashes in CI where the markdown parser is not installed. The Makefile is unused — CI runs selene, stylua, and nvim-busted-action directly. Solution: Change filetype plugin indent on to filetype on in minimal_init.lua. Tests only need filetype detection for vim.bo.filetype assertions, not ftplugin or indent loading. Remove the Makefile. --- Makefile | 44 ------------------------------------------- spec/altbuf_spec.lua | 1 - spec/minimal_init.lua | 2 +- spec/test_util.lua | 8 ++------ 4 files changed, 3 insertions(+), 52 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 71c7c35..0000000 --- a/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -## help: print this help message -.PHONY: help -help: - @echo 'Usage:' - @sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /' - -## all: lint and run tests -.PHONY: all -all: lint test - -## test: run tests -.PHONY: test -test: - luarocks test --local - -## lint: run selene and stylua -.PHONY: lint -lint: - selene --display-style quiet . - stylua --check lua spec - -## profile: use LuaJIT profiler to profile the plugin -.PHONY: profile -profile: scripts/benchmark.nvim - nvim --clean -u perf/bootstrap.lua -c 'lua jit_profile()' - -## flame_profile: create a trace in the chrome profiler format -.PHONY: flame_profile -flame_profile: scripts/benchmark.nvim - nvim --clean -u perf/bootstrap.lua -c 'lua flame_profile()' - -## benchmark: benchmark performance opening directory with many files -.PHONY: benchmark -benchmark: scripts/benchmark.nvim - nvim --clean -u perf/bootstrap.lua -c 'lua benchmark()' - @cat perf/tmp/benchmark.txt - -scripts/benchmark.nvim: - git clone https://github.com/stevearc/benchmark.nvim scripts/benchmark.nvim - -## clean: reset the repository to a clean state -.PHONY: clean -clean: - rm -rf perf/tmp profile.json diff --git a/spec/altbuf_spec.lua b/spec/altbuf_spec.lua index b64bfc0..cd2cf4b 100644 --- a/spec/altbuf_spec.lua +++ b/spec/altbuf_spec.lua @@ -22,7 +22,6 @@ describe('Alternate buffer', function() local readme = fs.join(vim.fn.getcwd(), 'README.md') vim.cmd.edit({ args = { 'oil://' .. fs.os_to_posix_path(readme) } }) test_util.wait_for_autocmd('BufEnter') - test_util.wait_for_autocmd('BufEnter') assert.equals(readme, vim.api.nvim_buf_get_name(0)) assert.equals('foo', vim.fn.expand('#')) end) diff --git a/spec/minimal_init.lua b/spec/minimal_init.lua index c070d64..09f0cd3 100644 --- a/spec/minimal_init.lua +++ b/spec/minimal_init.lua @@ -2,7 +2,7 @@ vim.cmd([[set runtimepath=$VIMRUNTIME]]) vim.opt.runtimepath:append('.') vim.opt.packpath = {} vim.o.swapfile = false -vim.cmd('filetype plugin indent on') +vim.cmd('filetype on') vim.fn.mkdir(vim.fn.stdpath('cache'), 'p') vim.fn.mkdir(vim.fn.stdpath('data'), 'p') vim.fn.mkdir(vim.fn.stdpath('state'), 'p') diff --git a/spec/test_util.lua b/spec/test_util.lua index b77f6f1..57f81b1 100644 --- a/spec/test_util.lua +++ b/spec/test_util.lua @@ -12,12 +12,8 @@ M.reset_editor = function() prompt_save_on_select_new_entry = false, }) vim.cmd.tabonly({ mods = { silent = true } }) - for i, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do - if i > 1 then - vim.api.nvim_win_close(winid, true) - end - end - vim.api.nvim_win_set_buf(0, vim.api.nvim_create_buf(false, true)) + vim.cmd.new() + vim.cmd.only() for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do vim.api.nvim_buf_delete(bufnr, { force = true }) end From 6f9ed9c7a7c7c3e83a8b746b7598698c83d49abb Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 15:43:58 -0500 Subject: [PATCH 09/77] fix(doc): remove `A:` from q&a section --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c9422ad..636c8ff 100644 --- a/README.md +++ b/README.md @@ -214,7 +214,7 @@ Replace your `setup()` call with a `vim.g.oil` assignment. For example, with **Q: Why "oil"?** -**A:** From the [vim-vinegar](https://github.com/tpope/vim-vinegar) README, a quote by Drew Neil: +From the [vim-vinegar](https://github.com/tpope/vim-vinegar) README, a quote by Drew Neil: > Split windows and the project drawer go together like oil and vinegar @@ -223,8 +223,6 @@ Plus, I think it's pretty slick ;) **Q: Why would I want to use oil vs any other plugin?** -**A:** - - You like to use a netrw-like view to browse directories (as opposed to a file tree) - AND you want to be able to edit your filesystem like a buffer - AND you want to perform cross-directory actions. AFAIK there is no other plugin that does this. (update: [mini.files](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-files.md) also offers this functionality) @@ -233,12 +231,10 @@ If you don't need those features specifically, check out the alternatives listed **Q: Can oil display files as a tree view?** -**A:** No. A tree view would require a completely different methodology, necessitating a complete rewrite. +No. A tree view would require a completely different methodology, necessitating a complete rewrite. **Q: What are some alternatives?** -**A:** - - [the original](https://github.com/stevearc/oil.nvim): the lesser-maintained but official `oil.nvim` - [mini.files](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-files.md): Also supports cross-directory filesystem-as-buffer edits with a column view. From b4ab166c390add6b2e0e2dddf0920aea9376bddd Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:06:31 -0500 Subject: [PATCH 10/77] build: modernize repository (#27) * build: clean up gitignore and remove empty gitmodules Problem: .gitignore contained 48 lines of C/shared-object boilerplate irrelevant to a Lua Neovim plugin. .gitmodules was tracked but empty. Solution: replace .gitignore with minimal entries covering only files this project actually produces. Delete the vestigial .gitmodules. * build: add editorconfig and prettierrc Problem: no editor or formatter configuration, inconsistent with cp.nvim and diffs.nvim conventions. Solution: add .editorconfig (2-space Lua indent, utf-8, final newline) and .prettierrc (prose wrap, 80 cols, single quotes, no semi) matching the other repos. * build: add Makefile for lint and test targets Problem: .github/pre-commit calls `make fastlint` and .github/pre-push calls `make lint && make test`, but no Makefile existed, so the git hooks failed. Solution: add Makefile with lint (stylua + selene), fastlint (pre-commit), and test (luarocks test) targets. * docs: add fork copyright to LICENSE Problem: LICENSE only contained the original author's copyright notice. Solution: add a second copyright line for the fork maintainer. MIT requires retaining the original notice; adding a line for derivative work is standard practice. * ci: restructure workflows to quality/test/luarocks pattern Problem: CI used a single tests.yml for linting, typechecking, and testing. No conditional path filtering, no markdown format check, and a stale mirror_upstream_prs.yml and duplicate luarocks.yml existed. Solution: replace tests.yml with quality.yaml (stylua, selene, lua-typecheck, prettier with dorny/paths-filter) and test.yaml (nvim-busted, stable+nightly matrix). Update luarocks.yaml to reference quality.yaml. Delete mirror_upstream_prs.yml and duplicate luarocks.yml. Fix automation workflow sender check. * build: rewrite issue templates Problem: issue templates used upstream stevearc references, severity dropdowns, outdated lazy.nvim bootstrap, and the .yml extension inconsistent with other repos. Solution: replace with .yaml templates matching cp.nvim/diffs.nvim style. Bug report uses prerequisites checkboxes, checkhealth output, modern lazy.nvim bootstrap with vim.g.oil pattern. Feature request uses problem/solution/alternatives format. Add config.yaml to disable blank issues and link discussions. * docs: rewrite README Problem: README contained upstream triage tables, severity dropdowns, the old setup() pattern, a tree view question, and references to stevearc/oil.nvim as the primary source. Solution: full rewrite matching cp.nvim/diffs.nvim style with bold tagline, features list, requirements, installation, documentation, FAQ (lazy.nvim setup with vim.g.oil, migration guide, alternatives), and acknowledgements crediting the original author. * revert: remove Makefile Problem: Makefile was added in b9279b5 but was previously deleted intentionally. Solution: remove it. --- .editorconfig | 9 + .github/ISSUE_TEMPLATE/bug_report.yaml | 80 ++++++ .github/ISSUE_TEMPLATE/bug_report.yml | 131 --------- .github/ISSUE_TEMPLATE/config.yaml | 5 + .github/ISSUE_TEMPLATE/feature_request.yaml | 30 +++ .github/ISSUE_TEMPLATE/feature_request.yml | 43 --- ...ation_remove_question_label_on_comment.yml | 2 +- .github/workflows/luarocks.yaml | 2 +- .github/workflows/luarocks.yml | 21 -- .github/workflows/mirror_upstream_prs.yml | 85 ------ .github/workflows/quality.yaml | 90 +++++++ .github/workflows/test.yaml | 22 ++ .github/workflows/tests.yml | 60 ----- .gitignore | 51 +--- .gitmodules | 0 .prettierrc | 9 + LICENSE | 1 + README.md | 253 ++++-------------- 18 files changed, 308 insertions(+), 586 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yaml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yaml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml delete mode 100644 .github/workflows/luarocks.yml delete mode 100644 .github/workflows/mirror_upstream_prs.yml create mode 100644 .github/workflows/quality.yaml create mode 100644 .github/workflows/test.yaml delete mode 100644 .github/workflows/tests.yml delete mode 100644 .gitmodules create mode 100644 .prettierrc diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b9de190 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +insert_final_newline = true +charset = utf-8 + +[*.lua] +indent_style = space +indent_size = 2 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000..6447534 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,80 @@ +name: Bug Report +description: Report a bug +title: 'bug: ' +labels: [bug] +body: + - type: checkboxes + attributes: + label: Prerequisites + options: + - label: + I have searched [existing + issues](https://github.com/barrettruth/oil.nvim/issues) + required: true + - label: I have updated to the latest version + required: true + + - type: textarea + attributes: + label: 'Neovim version' + description: 'Output of `nvim --version`' + render: text + validations: + required: true + + - type: input + attributes: + label: 'Operating system' + placeholder: 'e.g. Arch Linux, macOS 15, Ubuntu 24.04' + validations: + required: true + + - type: textarea + attributes: + label: Description + description: What happened? What did you expect? + validations: + required: true + + - type: textarea + attributes: + label: Steps to reproduce + description: Minimal steps to trigger the bug + value: | + 1. + 2. + 3. + validations: + required: true + + - type: textarea + attributes: + label: 'Health check' + description: 'Output of `:checkhealth oil`' + render: text + + - type: textarea + attributes: + label: Minimal reproduction + description: | + Save the script below as `repro.lua`, edit if needed, and run: + ``` + nvim -u repro.lua + ``` + Confirm the bug reproduces with this config before submitting. + render: lua + value: | + vim.env.LAZY_STDPATH = '.repro' + load(vim.fn.system('curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua'))() + require('lazy.nvim').setup({ + spec = { + { + 'barrettruth/oil.nvim', + init = function() + vim.g.oil = {} + end, + }, + }, + }) + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 327aaf2..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,131 +0,0 @@ -name: Bug Report -description: File a bug/issue -title: "bug: " -labels: [bug] -body: - - type: markdown - attributes: - value: | - Before reporting a bug, make sure to search [existing issues](https://github.com/stevearc/oil.nvim/issues) - - type: checkboxes - attributes: - label: Did you check the docs and existing issues? - options: - - label: I have read the docs - required: true - - label: I have searched the existing issues - required: true - - type: input - attributes: - label: "Neovim version (nvim -v)" - placeholder: "0.8.0 commit db1b0ee3b30f" - validations: - required: true - - type: input - attributes: - label: "Operating system/version" - placeholder: "MacOS 11.5" - validations: - required: true - - type: textarea - attributes: - label: Describe the bug - description: A clear and concise description of what the bug is. Please include any related errors you see in Neovim. - validations: - required: true - - type: dropdown - attributes: - label: What is the severity of this bug? - options: - - minor (annoyance) - - tolerable (can work around it) - - breaking (some functionality is broken) - - blocking (cannot use plugin) - validations: - required: true - - type: textarea - attributes: - label: Steps To Reproduce - description: Steps to reproduce the behavior. - placeholder: | - 1. nvim -u repro.lua - 2. - 3. - validations: - required: true - - type: textarea - attributes: - label: Expected Behavior - description: A concise description of what you expected to happen. - validations: - required: true - - type: textarea - attributes: - label: Directory structure - description: The structure of the directory used to reproduce the bug - placeholder: | - a/b/foo.txt - a/bar.md - a/c/baz.txt - validations: - required: false - - type: textarea - attributes: - label: Repro - description: - Minimal `init.lua` to reproduce this issue. Save as `repro.lua` and run with `nvim -u repro.lua` - This uses lazy.nvim (a plugin manager). - You can add your config with the `config` key the same way you can do with packer.nvim. - value: | - -- save as repro.lua - -- run with nvim -u repro.lua - -- DO NOT change the paths - local root = vim.fn.fnamemodify("./.repro", ":p") - - -- set stdpaths to use .repro - for _, name in ipairs({ "config", "data", "state", "runtime", "cache" }) do - vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name - end - - -- bootstrap lazy - local lazypath = root .. "/plugins/lazy.nvim" - if not vim.loop.fs_stat(lazypath) then - vim.fn.system({ - "git", - "clone", - "--filter=blob:none", - "--single-branch", - "https://github.com/folke/lazy.nvim.git", - lazypath, - }) - end - vim.opt.runtimepath:prepend(lazypath) - - -- install plugins - local plugins = { - "folke/tokyonight.nvim", - { - "stevearc/oil.nvim", - config = function() - require("oil").setup({ - -- add any needed settings here - }) - end, - }, - -- add any other plugins here - } - require("lazy").setup(plugins, { - root = root .. "/plugins", - }) - - vim.cmd.colorscheme("tokyonight") - -- add anything else here - render: Lua - validations: - required: true - - type: checkboxes - attributes: - label: Did you check the bug with a clean config? - options: - - label: I have confirmed that the bug reproduces with `nvim -u repro.lua` using the repro.lua file above. - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yaml new file mode 100644 index 0000000..ce81bef --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yaml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Questions + url: https://github.com/barrettruth/oil.nvim/discussions + about: Ask questions and discuss ideas diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 0000000..6515953 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,30 @@ +name: Feature Request +description: Suggest a feature +title: 'feat: ' +labels: [enhancement] +body: + - type: checkboxes + attributes: + label: Prerequisites + options: + - label: + I have searched [existing + issues](https://github.com/barrettruth/oil.nvim/issues) + required: true + + - type: textarea + attributes: + label: Problem + description: What problem does this solve? + validations: + required: true + + - type: textarea + attributes: + label: Proposed solution + validations: + required: true + + - type: textarea + attributes: + label: Alternatives considered diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index 9916836..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Feature Request -description: Submit a feature request -title: "feature request: " -labels: [enhancement] -body: - - type: markdown - attributes: - value: | - Before submitting a feature request, make sure to search for [existing requests](https://github.com/stevearc/oil.nvim/issues) - - type: checkboxes - attributes: - label: Did you check existing requests? - options: - - label: I have searched the existing issues - required: true - - type: textarea - attributes: - label: Describe the feature - description: A short summary of the feature you want - validations: - required: true - - type: textarea - attributes: - label: Provide background - description: Describe the reasoning behind why you want the feature. - placeholder: I am trying to do X. My current workflow is Y. - validations: - required: false - - type: dropdown - attributes: - label: What is the significance of this feature? - options: - - nice to have - - strongly desired - - cannot use this plugin without it - validations: - required: true - - type: textarea - attributes: - label: Additional details - description: Any additional information you would like to provide. Things you've tried, alternatives considered, examples from other plugins, etc. - validations: - required: false diff --git a/.github/workflows/automation_remove_question_label_on_comment.yml b/.github/workflows/automation_remove_question_label_on_comment.yml index f99bba8..36f9336 100644 --- a/.github/workflows/automation_remove_question_label_on_comment.yml +++ b/.github/workflows/automation_remove_question_label_on_comment.yml @@ -8,7 +8,7 @@ jobs: # issues in my "needs triage" filter. remove_question: runs-on: ubuntu-latest - if: github.event.sender.login != 'stevearc' + if: github.event.sender.login != 'barrettruth' steps: - uses: actions/checkout@v4 - uses: actions-ecosystem/action-remove-labels@v1 diff --git a/.github/workflows/luarocks.yaml b/.github/workflows/luarocks.yaml index 4dc366c..9b6664e 100644 --- a/.github/workflows/luarocks.yaml +++ b/.github/workflows/luarocks.yaml @@ -7,7 +7,7 @@ on: jobs: quality: - uses: ./.github/workflows/tests.yml + uses: ./.github/workflows/quality.yaml publish: needs: quality diff --git a/.github/workflows/luarocks.yml b/.github/workflows/luarocks.yml deleted file mode 100644 index 999f728..0000000 --- a/.github/workflows/luarocks.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: luarocks - -on: - push: - tags: - - 'v*' - -jobs: - tests: - uses: ./.github/workflows/tests.yml - - publish: - needs: tests - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - uses: nvim-neorocks/luarocks-tag-release@v7 - env: - LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }} diff --git a/.github/workflows/mirror_upstream_prs.yml b/.github/workflows/mirror_upstream_prs.yml deleted file mode 100644 index af9cdb0..0000000 --- a/.github/workflows/mirror_upstream_prs.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: Mirror Upstream PRs -on: - schedule: - - cron: "0 8 * * *" - workflow_dispatch: - -permissions: - issues: write - -jobs: - mirror: - runs-on: ubuntu-latest - steps: - - name: Mirror new upstream PRs - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const upstream = { owner: 'stevearc', repo: 'oil.nvim' }; - const fork = { owner: 'barrettruth', repo: 'oil.nvim' }; - - const since = new Date(); - since.setDate(since.getDate() - 1); - const sinceISO = since.toISOString(); - - const { data: prs } = await github.rest.pulls.list({ - ...upstream, - state: 'open', - sort: 'created', - direction: 'desc', - per_page: 30, - }); - - const recentPRs = prs.filter(pr => { - if (new Date(pr.created_at) < since) return false; - if (pr.user.login === 'dependabot[bot]') return false; - if (pr.user.login === 'dependabot-preview[bot]') return false; - return true; - }); - - if (recentPRs.length === 0) { - console.log('No new upstream PRs in the last 24 hours.'); - return; - } - - const { data: existingIssues } = await github.rest.issues.listForRepo({ - ...fork, - state: 'all', - labels: 'upstream/pr', - per_page: 100, - }); - - const mirroredNumbers = new Set(); - for (const issue of existingIssues) { - const match = issue.title.match(/^upstream#(\d+)/); - if (match) mirroredNumbers.add(parseInt(match[1])); - } - - for (const pr of recentPRs) { - if (mirroredNumbers.has(pr.number)) { - console.log(`Skipping PR #${pr.number} — already mirrored.`); - continue; - } - - const labels = pr.labels.map(l => l.name).join(', ') || 'none'; - - await github.rest.issues.create({ - ...fork, - title: `upstream#${pr.number}: ${pr.title}`, - body: [ - `Mirrored from [stevearc/oil.nvim#${pr.number}](${pr.html_url}).`, - '', - `**Author:** @${pr.user.login}`, - `**Labels:** ${labels}`, - `**Created:** ${pr.created_at}`, - '', - '---', - '', - pr.body || '*No description provided.*', - ].join('\n'), - labels: ['upstream/pr'], - }); - - console.log(`Created issue for upstream PR #${pr.number}: ${pr.title}`); - } diff --git a/.github/workflows/quality.yaml b/.github/workflows/quality.yaml new file mode 100644 index 0000000..9691be9 --- /dev/null +++ b/.github/workflows/quality.yaml @@ -0,0 +1,90 @@ +name: quality + +on: + workflow_call: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + changes: + runs-on: ubuntu-latest + outputs: + lua: ${{ steps.changes.outputs.lua }} + markdown: ${{ steps.changes.outputs.markdown }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: changes + with: + filters: | + lua: + - 'lua/**' + - 'plugin/**' + - 'spec/**' + - '*.lua' + - '.luarc.json' + - '*.toml' + markdown: + - '*.md' + + lua-format: + name: Lua Format Check + runs-on: ubuntu-latest + needs: changes + if: ${{ needs.changes.outputs.lua == 'true' }} + steps: + - uses: actions/checkout@v4 + - uses: JohnnyMorganz/stylua-action@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: 2.1.0 + args: --check lua spec + + lua-lint: + name: Lua Lint Check + runs-on: ubuntu-latest + needs: changes + if: ${{ needs.changes.outputs.lua == 'true' }} + steps: + - uses: actions/checkout@v4 + - name: Lint with Selene + uses: NTBBloodbath/selene-action@v1.0.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --display-style quiet . + + lua-typecheck: + name: Lua Type Check + runs-on: ubuntu-latest + needs: changes + if: ${{ needs.changes.outputs.lua == 'true' }} + steps: + - uses: actions/checkout@v4 + - name: Run Lua LS Type Check + uses: mrcjkb/lua-typecheck-action@v0 + with: + checklevel: Warning + directories: lua + configpath: .luarc.json + + markdown-format: + name: Markdown Format Check + runs-on: ubuntu-latest + needs: changes + if: ${{ needs.changes.outputs.markdown == 'true' }} + steps: + - uses: actions/checkout@v4 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 8 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Install prettier + run: pnpm add -g prettier@3.1.0 + - name: Check markdown formatting with prettier + run: prettier --check . diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..6910389 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,22 @@ +name: test + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + nvim: [stable, nightly] + name: Test (Neovim ${{ matrix.nvim }}) + steps: + - uses: actions/checkout@v4 + + - uses: nvim-neorocks/nvim-busted-action@v1 + with: + nvim_version: ${{ matrix.nvim }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index 33fe515..0000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Tests - -on: - workflow_call: - push: - branches: - - main - pull_request: - branches: - - main - -jobs: - selene: - name: Selene - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: NTBBloodbath/selene-action@v1.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --display-style quiet . - - stylua: - name: StyLua - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Stylua - uses: JohnnyMorganz/stylua-action@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: v2.1.0 - args: --check lua spec - - typecheck: - name: typecheck - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: mrcjkb/lua-typecheck-action@v0 - with: - checklevel: Warning - directories: lua - configpath: .luarc.json - - run_tests: - strategy: - fail-fast: false - matrix: - nvim_version: - - stable - - nightly - - name: Run tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: nvim-neorocks/nvim-busted-action@v1 - with: - nvim_version: ${{ matrix.nvim_version }} diff --git a/.gitignore b/.gitignore index 9f5d17c..4a27603 100644 --- a/.gitignore +++ b/.gitignore @@ -1,47 +1,12 @@ -# Compiled Lua sources -luac.out - -# luarocks build files -*.src.rock -*.zip -*.tar.gz - -# Object files -*.o -*.os -*.ko -*.obj -*.elf - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo -*.def -*.exp - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - +doc/tags +*.log +.*cache* +CLAUDE.md +.claude/ +node_modules/ .direnv/ .envrc -doc/tags -scripts/benchmark.nvim +venv/ perf/tmp/ +scripts/benchmark.nvim profile.json diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29..0000000 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..0663621 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "proseWrap": "always", + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "none", + "semi": false, + "singleQuote": true +} diff --git a/LICENSE b/LICENSE index 4928e96..ccff038 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2022 Steven Arcangeli +Copyright (c) 2025 Barrett Ruth Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 636c8ff..d14705c 100644 --- a/README.md +++ b/README.md @@ -1,177 +1,37 @@ # oil.nvim -A [vim-vinegar](https://github.com/tpope/vim-vinegar) like file explorer that lets you edit your filesystem like a normal Neovim buffer. +**A file explorer that lets you edit your filesystem like a buffer** + +Browse directories as normal Neovim buffers, then create, rename, move, copy, +and delete files by editing the listing and saving. Cross-directory operations +work seamlessly across local, SSH, S3, and trash adapters. https://user-images.githubusercontent.com/506791/209727111-6b4a11f4-634a-4efa-9461-80e9717cea94.mp4 -This is a maintained fork of [stevearc/oil.nvim](https://github.com/stevearc/oil.nvim) -with cherry-picked upstream PRs and original bug fixes that haven't landed -upstream yet. +## Features -
-Changes from upstream - -### Cherry-picked PRs - -Upstream PRs cherry-picked or adapted into this fork. - -| PR | Description | Commit | -|---|---|---| -| [#495](https://github.com/stevearc/oil.nvim/pull/495) | Cancel visual/operator-pending mode on close | [`16f3d7b`](https://github.com/barrettruth/oil.nvim/commit/16f3d7b) | -| [#537](https://github.com/stevearc/oil.nvim/pull/537) | Configurable file/directory creation permissions | [`c6b4a7a`](https://github.com/barrettruth/oil.nvim/commit/c6b4a7a) | -| [#618](https://github.com/stevearc/oil.nvim/pull/618) | Opt-in filetype detection for icons | [`ded1725`](https://github.com/barrettruth/oil.nvim/commit/ded1725) | -| [#644](https://github.com/stevearc/oil.nvim/pull/644) | Pass entry to `is_hidden_file`/`is_always_hidden` | [`4ab4765`](https://github.com/barrettruth/oil.nvim/commit/4ab4765) | -| [#697](https://github.com/stevearc/oil.nvim/pull/697) | Recipe for file extension column | [`dcb3a08`](https://github.com/barrettruth/oil.nvim/commit/dcb3a08) | -| [#698](https://github.com/stevearc/oil.nvim/pull/698) | Executable file highlighting | [`41556ec`](https://github.com/barrettruth/oil.nvim/commit/41556ec), [`85ed9b8`](https://github.com/barrettruth/oil.nvim/commit/85ed9b8) | -| [#717](https://github.com/stevearc/oil.nvim/pull/717) | Add oil-git.nvim to extensions | [`582d9fc`](https://github.com/barrettruth/oil.nvim/commit/582d9fc) | -| [#720](https://github.com/stevearc/oil.nvim/pull/720) | Gate `BufAdd` autocmd behind config check | [`2228f80`](https://github.com/barrettruth/oil.nvim/commit/2228f80) | -| [#722](https://github.com/stevearc/oil.nvim/pull/722) | Fix freedesktop trash URL | [`b92ecb0`](https://github.com/barrettruth/oil.nvim/commit/b92ecb0) | -| [#723](https://github.com/stevearc/oil.nvim/pull/723) | Emit `OilReadPost` event after render | [`29239d5`](https://github.com/barrettruth/oil.nvim/commit/29239d5) | -| [#725](https://github.com/stevearc/oil.nvim/pull/725) | Normalize keymap keys before config merge | [`723145c`](https://github.com/barrettruth/oil.nvim/commit/723145c) | -| [#727](https://github.com/stevearc/oil.nvim/pull/727) | Clarify `get_current_dir` nil + Telescope recipe | [`eed6697`](https://github.com/barrettruth/oil.nvim/commit/eed6697) | - -### Open upstream PRs - -Open PRs on upstream not yet incorporated into this fork. - -| PR | Description | Status | -|---|---|---| -| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR, 0 changes | -| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | -| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable — fork uses different release process | -| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | -| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | -| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite for multi-level dirs, tests | -| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | -| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [barrettruth/oil.nvim#2](https://github.com/barrettruth/oil.nvim/issues/2) | - -### Issues - -All open upstream issues, triaged against this fork. - -**Status key:** `fixed` = original fix in fork, `resolved` = addressed by cherry-picked PR, -`not actionable` = can't/won't fix, `tracking` = known/not yet addressed, `open` = not yet triaged. - -| Issue | Status | Notes | -|---|---|---| -| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | -| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | -| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | -| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | -| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | -| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | -| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | -| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | -| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | -| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | -| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | -| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | -| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | -| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | -| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | -| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | -| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | -| [#302](https://github.com/stevearc/oil.nvim/issues/302) | open | C-o parent nav makes buffer buflisted (P0) | -| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | -| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | -| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | -| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | -| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | -| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | -| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | -| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | -| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | -| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | -| [#363](https://github.com/stevearc/oil.nvim/issues/363) | open | `prompt_save_on_select_new_entry` uses wrong prompt | -| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | -| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | -| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | -| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | -| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | -| [#392](https://github.com/stevearc/oil.nvim/issues/392) | open | Option to skip delete prompt | -| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | -| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | -| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | -| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | -| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | -| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | -| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | -| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | -| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | -| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | -| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | -| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | -| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | -| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | -| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | -| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | -| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | -| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | -| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | -| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | -| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | -| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | -| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | -| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | -| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | -| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/oil.nvim/commit/38db6cf) | -| [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | -| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | -| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | -| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | -| [#612](https://github.com/stevearc/oil.nvim/issues/612) | open | Delete buffers on file delete (P2) | -| [#615](https://github.com/stevearc/oil.nvim/issues/615) | open | Cursor at name column on o/O (P2) | -| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | -| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | -| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | -| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | -| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | -| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [PR #12](https://github.com/barrettruth/oil.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/oil.nvim/commit/fe16993)) | -| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | -| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | -| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | -| [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/oil.nvim/commit/ca834cf) | -| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/oil.nvim/commit/f6bcdda) | -| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | -| [#650](https://github.com/stevearc/oil.nvim/issues/650) | open | Emit LSP `workspace.fileOperations` events | -| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | -| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | -| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | -| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | -| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | -| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [PR #11](https://github.com/barrettruth/oil.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/oil.nvim/commit/70861e5)) | -| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | -| [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/oil.nvim/commit/9110a1a) | -| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | -| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | -| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#682](https://github.com/stevearc/oil.nvim/issues/682) | open | `get_current_dir()` nil in non-telescope context | -| [#683](https://github.com/stevearc/oil.nvim/issues/683) | open | Path not shown in floating mode | -| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | -| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | -| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/oil.nvim/commit/ce64ae1) | -| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | -| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | -| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [PR #10](https://github.com/barrettruth/oil.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/oil.nvim/commit/01b860e)) | -| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | -| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | -| [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | - -
+- Edit directory listings as normal buffers — mutations are derived by diffing +- Cross-directory move, copy, and rename across any adapter +- Adapters for local filesystem, SSH, S3, and OS trash +- File preview in split or floating window +- Configurable columns (icon, size, permissions, timestamps) +- Executable file highlighting and filetype-aware icons +- Floating window and split layouts ## Requirements -Neovim 0.8+ and optionally [mini.icons](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-icons.md) or [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) for file icons. +- Neovim 0.10+ +- Optional: + [mini.icons](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-icons.md) + or [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) for + file icons ## Installation -Install with your favorite package manager or with luarocks: +Install with your package manager of choice or via +[luarocks](https://luarocks.org/modules/barrettruth/oil.nvim): -```console +``` luarocks install oil.nvim ``` @@ -183,62 +43,53 @@ luarocks install oil.nvim ## FAQ -**Q: How do I migrate from `stevearc/oil.nvim` to `barrettruth/oil.nvim`?** - -Replace your `setup()` call with a `vim.g.oil` assignment. For example, with -[lazy.nvim](https://github.com/folke/lazy.nvim): +**Q: How do I set up oil.nvim with lazy.nvim?** ```lua --- before -{ - 'stevearc/oil.nvim', - config = function(_, opts) - require('oil').setup(opts) - end, - opts = { - ... - } -} - --- after { 'barrettruth/oil.nvim', init = function() vim.g.oil = { - columns = { "icon", "size" }, + columns = { 'icon', 'size' }, delete_to_trash = true, } end, } ``` +Do not use `config`, `opts`, or `lazy` — oil.nvim loads itself when you open a +directory. + +**Q: How do I migrate from stevearc/oil.nvim?** + +Replace `stevearc/oil.nvim` with `barrettruth/oil.nvim` in your plugin manager +and switch your `setup()` call to a `vim.g.oil` assignment in `init`. The +configuration table is the same. + **Q: Why "oil"?** -From the [vim-vinegar](https://github.com/tpope/vim-vinegar) README, a quote by Drew Neil: +From the [vim-vinegar](https://github.com/tpope/vim-vinegar) README, a quote by +Drew Neil: > Split windows and the project drawer go together like oil and vinegar -Vinegar was taken. Let's be oil. -Plus, I think it's pretty slick ;) - -**Q: Why would I want to use oil vs any other plugin?** - -- You like to use a netrw-like view to browse directories (as opposed to a file tree) -- AND you want to be able to edit your filesystem like a buffer -- AND you want to perform cross-directory actions. AFAIK there is no other plugin that does this. (update: [mini.files](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-files.md) also offers this functionality) - -If you don't need those features specifically, check out the alternatives listed below - -**Q: Can oil display files as a tree view?** - -No. A tree view would require a completely different methodology, necessitating a complete rewrite. - **Q: What are some alternatives?** -- [the original](https://github.com/stevearc/oil.nvim): the lesser-maintained but - official `oil.nvim` -- [mini.files](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-files.md): Also supports cross-directory filesystem-as-buffer edits with a column view. -- [vim-vinegar](https://github.com/tpope/vim-vinegar): The granddaddy of single-directory file browsing. -- [dirbuf.nvim](https://github.com/elihunter173/dirbuf.nvim): Edit filesystem like a buffer, but no cross-directory edits. -- [lir.nvim](https://github.com/tamago324/lir.nvim): Similar to vim-vinegar with better Neovim integration. -- [vim-dirvish](https://github.com/justinmk/vim-dirvish): Stable, simple directory browser. +- [stevearc/oil.nvim](https://github.com/stevearc/oil.nvim): the original + oil.nvim +- [mini.files](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-files.md): + cross-directory filesystem-as-buffer with a column view +- [vim-vinegar](https://github.com/tpope/vim-vinegar): the granddaddy of + single-directory file browsing +- [dirbuf.nvim](https://github.com/elihunter173/dirbuf.nvim): filesystem as + buffer without cross-directory edits +- [lir.nvim](https://github.com/tamago324/lir.nvim): vim-vinegar style with + Neovim integration +- [vim-dirvish](https://github.com/justinmk/vim-dirvish): stable, simple + directory browser + +## Acknowledgements + +oil.nvim was created by +[Steven Arcangeli](https://github.com/stevearc/oil.nvim). This fork is +maintained by [Barrett Ruth](https://github.com/barrettruth). From 7d410acaf129a86c9fdde328f039395b701b05fa Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:14:10 -0500 Subject: [PATCH 11/77] fix(ci): switch typecheck action to stevearc/nvim-typecheck-action (#26) Problem: mrcjkb/lua-typecheck-action runs lua-language-server in a bare nix sandbox without neovim installed, causing 71 type errors for all vim.* and uv.* types. LuaLS 3.17.x also introduced stricter type checking that flags uv.aliases.fs_types mismatches not present in 3.16.4. The .luarc.json workspace.library entries conflicted with the action's auto-appended luvit-meta, producing duplicate uv type unions. Solution: switch to stevearc/nvim-typecheck-action@v2 (matching upstream), pin LuaLS to 3.16.4, convert .luarc.json to nested format without workspace.library (let the action provide VIMRUNTIME and luvit-meta), and add .direnv/* to selene.toml exclude for local use. --- .github/workflows/quality.yaml | 8 +++----- .luarc.json | 19 +++++++++++++------ selene.toml | 1 + 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/.github/workflows/quality.yaml b/.github/workflows/quality.yaml index 9691be9..3bf8b57 100644 --- a/.github/workflows/quality.yaml +++ b/.github/workflows/quality.yaml @@ -62,12 +62,10 @@ jobs: if: ${{ needs.changes.outputs.lua == 'true' }} steps: - uses: actions/checkout@v4 - - name: Run Lua LS Type Check - uses: mrcjkb/lua-typecheck-action@v0 + - uses: stevearc/nvim-typecheck-action@v2 with: - checklevel: Warning - directories: lua - configpath: .luarc.json + path: lua + luals-version: 3.16.4 markdown-format: name: Markdown Format Check diff --git a/.luarc.json b/.luarc.json index f22884c..c0448ca 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,8 +1,15 @@ { - "runtime.version": "Lua 5.1", - "runtime.path": ["lua/?.lua", "lua/?/init.lua"], - "diagnostics.globals": ["vim", "jit", "bit"], - "workspace.library": ["$VIMRUNTIME/lua", "${3rd}/luv/library"], - "workspace.checkThirdParty": false, - "completion.callSnippet": "Replace" + "runtime": { + "version": "LuaJIT", + "pathStrict": true + }, + "workspace": { + "checkThirdParty": false + }, + "type": { + "checkTableShape": true + }, + "completion": { + "callSnippet": "Replace" + } } diff --git a/selene.toml b/selene.toml index ab57300..4fbd4a4 100644 --- a/selene.toml +++ b/selene.toml @@ -1,4 +1,5 @@ std = 'vim' +exclude = [".direnv/*"] [lints] mixed_table = 'allow' From ac787627c0b211039825fd6aff27bfa6deac16a2 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:18:56 -0500 Subject: [PATCH 12/77] docs: combine setup and migration FAQ entries (#29) --- README.md | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d14705c..326afac 100644 --- a/README.md +++ b/README.md @@ -43,28 +43,37 @@ luarocks install oil.nvim ## FAQ -**Q: How do I set up oil.nvim with lazy.nvim?** +**Q: How do I set up oil.nvim (or migrate from stevearc/oil.nvim)?** + +Change the plugin source and replace `setup()` with `vim.g.oil` in `init`. The +configuration table is identical — only the entry point changes. + +Before (stevearc/oil.nvim): + +```lua +{ + 'stevearc/oil.nvim', + opts = { ... }, + config = function(_, opts) + require('oil').setup(opts) + end, +} +``` + +After (barrettruth/oil.nvim): ```lua { 'barrettruth/oil.nvim', init = function() - vim.g.oil = { - columns = { 'icon', 'size' }, - delete_to_trash = true, - } + vim.g.oil = { ... } end, } ``` -Do not use `config`, `opts`, or `lazy` — oil.nvim loads itself when you open a -directory. - -**Q: How do I migrate from stevearc/oil.nvim?** - -Replace `stevearc/oil.nvim` with `barrettruth/oil.nvim` in your plugin manager -and switch your `setup()` call to a `vim.g.oil` assignment in `init`. The -configuration table is the same. +`init` runs before the plugin loads; `config` runs after. oil.nvim reads +`vim.g.oil` at load time, so `init` is the correct hook. Do not use `config`, +`opts`, or `lazy` — oil.nvim loads itself when you open a directory. **Q: Why "oil"?** From b1b92b629255e719cfe711c860c60c9e58882048 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 16:23:02 -0500 Subject: [PATCH 13/77] fix(doc): readme phrasing --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 326afac..8e1b1f8 100644 --- a/README.md +++ b/README.md @@ -43,12 +43,12 @@ luarocks install oil.nvim ## FAQ -**Q: How do I set up oil.nvim (or migrate from stevearc/oil.nvim)?** +**Q: How do I migrate from `stevearc/oil.nvim`?** Change the plugin source and replace `setup()` with `vim.g.oil` in `init`. The configuration table is identical — only the entry point changes. -Before (stevearc/oil.nvim): +Before (`stevearc/oil.nvim`): ```lua { @@ -60,7 +60,7 @@ Before (stevearc/oil.nvim): } ``` -After (barrettruth/oil.nvim): +After (`barrettruth/oil.nvim`): ```lua { From b6aaeaf542acb694f4b9696754d4c83dc0af5c79 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 16:24:42 -0500 Subject: [PATCH 14/77] fix(doc): explicitly mention lazy.nvim config --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8e1b1f8..1973a0e 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ luarocks install oil.nvim **Q: How do I migrate from `stevearc/oil.nvim`?** Change the plugin source and replace `setup()` with `vim.g.oil` in `init`. The -configuration table is identical — only the entry point changes. +configuration table is identical — only the entry point changes. For example, +with [lazy.nvim](https://github.com/folke/lazy.nvim): Before (`stevearc/oil.nvim`): From 07ae3a8dc3a31c2eed3dc9b46ac2feffce10b499 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 22 Feb 2026 20:58:22 -0500 Subject: [PATCH 15/77] feat(icons): add nonicons.nvim icon provider support (#30) * feat(icons): add nonicons.nvim icon provider support Problem: oil.nvim only recognizes mini.icons and nvim-web-devicons as icon providers. nonicons.nvim works when paired with devicons (via its apply() monkey-patch), but has no standalone support. Solution: add a nonicons.nvim fallback in get_icon_provider(), placed after devicons so the patched devicons path is preferred when both are installed. The standalone path handles directories via nonicons.get('file-directory'), files via filetype/extension lookup with a generic file icon fallback. * fix(doc): improve readme phrasing --- README.md | 8 ++++---- lua/oil/util.lua | 27 ++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1973a0e..5cdda64 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,10 @@ https://user-images.githubusercontent.com/506791/209727111-6b4a11f4-634a-4efa-94 ## Requirements - Neovim 0.10+ -- Optional: - [mini.icons](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-icons.md) - or [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) for - file icons +- (Optionally) any of the following icon providers: + - [mini.icons](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-icons.md) + - [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) + - [nonicons.nvim](https://github.com/barrettruth/nonicons.nvim) ## Installation diff --git a/lua/oil/util.lua b/lua/oil/util.lua index d9bca22..cd94729 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -945,7 +945,32 @@ M.get_icon_provider = function() end end - -- fallback to `nvim-web-devicons` + local has_nonicons, nonicons = pcall(require, 'nonicons') + if has_nonicons and type(nonicons.get) == 'function' then + return function(type, name, conf, ft) + if type == 'directory' then + local icon = nonicons.get('file-directory') + return icon or (conf and conf.directory or ''), 'OilDirIcon' + else + if ft then + local ft_icon = nonicons.get(ft) + if ft_icon then + return ft_icon, 'OilFileIcon' + end + end + local ext = name:match('%.([^%.]+)$') + if ext then + local ext_icon = nonicons.get(ext) + if ext_icon then + return ext_icon, 'OilFileIcon' + end + end + local icon = nonicons.get('file') + return icon or (conf and conf.default_file or ''), 'OilFileIcon' + end + end + end + local has_devicons, devicons = pcall(require, 'nvim-web-devicons') if has_devicons then return function(type, name, conf, ft) From b0f44d3af6ba2435df320dfbbb8e22f01e472e64 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 21:03:54 -0500 Subject: [PATCH 16/77] fix: remove nonicons custom impl --- lua/oil/util.lua | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/lua/oil/util.lua b/lua/oil/util.lua index cd94729..5fbb3aa 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -945,32 +945,6 @@ M.get_icon_provider = function() end end - local has_nonicons, nonicons = pcall(require, 'nonicons') - if has_nonicons and type(nonicons.get) == 'function' then - return function(type, name, conf, ft) - if type == 'directory' then - local icon = nonicons.get('file-directory') - return icon or (conf and conf.directory or ''), 'OilDirIcon' - else - if ft then - local ft_icon = nonicons.get(ft) - if ft_icon then - return ft_icon, 'OilFileIcon' - end - end - local ext = name:match('%.([^%.]+)$') - if ext then - local ext_icon = nonicons.get(ext) - if ext_icon then - return ext_icon, 'OilFileIcon' - end - end - local icon = nonicons.get('file') - return icon or (conf and conf.default_file or ''), 'OilFileIcon' - end - end - end - local has_devicons, devicons = pcall(require, 'nvim-web-devicons') if has_devicons then return function(type, name, conf, ft) From d1f7c691b5824d77c0f2473c0daacbdf22266ecd Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 22 Feb 2026 21:31:09 -0500 Subject: [PATCH 17/77] feat(icons): add direct nonicons.nvim icon provider (#31) Problem: nonicons.nvim exposes a public get_icon/get_icon_by_filetype API, but oil.nvim can only use nonicons glyphs indirectly through the devicons monkey-patch. This couples oil to devicons even when nonicons is available standalone. Solution: add a nonicons provider in get_icon_provider() between mini.icons and devicons. Feature-gated on nonicons.get_icon existing so old nonicons versions fall through to devicons. Uses OilDirIcon and OilFileIcon highlight groups. --- lua/oil/util.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lua/oil/util.lua b/lua/oil/util.lua index 5fbb3aa..1ba9872 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -945,6 +945,28 @@ M.get_icon_provider = function() end end + local has_nonicons, nonicons = pcall(require, 'nonicons') + if has_nonicons and nonicons.get_icon then + return function(type, name, conf, ft) + if type == 'directory' then + local icon = nonicons.get('file-directory') + return icon or (conf and conf.directory or ''), 'OilDirIcon' + end + if ft then + local ft_icon = nonicons.get_icon_by_filetype(ft) + if ft_icon then + return ft_icon, 'OilFileIcon' + end + end + local icon = nonicons.get_icon(name) + if icon then + return icon, 'OilFileIcon' + end + local fallback = nonicons.get('file') + return fallback or (conf and conf.default_file or ''), 'OilFileIcon' + end + end + local has_devicons, devicons = pcall(require, 'nvim-web-devicons') if has_devicons then return function(type, name, conf, ft) From c92a5bd42a28efd73cda981bf64a66fbdb9f1c66 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 22:01:34 -0500 Subject: [PATCH 18/77] docs: rename repository from oil.nvim to canola.nvim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: the fork shared the same name as upstream, making it difficult to distinguish and discover independently. Solution: rename the repository to canola.nvim — a type of oil, making the lineage obvious while establishing a distinct identity. Update all references in the README, rockspec, and issue templates. --- .github/ISSUE_TEMPLATE/bug_report.yaml | 4 ++-- .github/ISSUE_TEMPLATE/config.yaml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +- README.md | 24 +++++++++---------- ...m-1.rockspec => canola.nvim-scm-1.rockspec | 6 ++--- 5 files changed, 18 insertions(+), 20 deletions(-) rename oil.nvim-scm-1.rockspec => canola.nvim-scm-1.rockspec (68%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 6447534..8784517 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -9,7 +9,7 @@ body: options: - label: I have searched [existing - issues](https://github.com/barrettruth/oil.nvim/issues) + issues](https://github.com/barrettruth/canola.nvim/issues) required: true - label: I have updated to the latest version required: true @@ -69,7 +69,7 @@ body: require('lazy.nvim').setup({ spec = { { - 'barrettruth/oil.nvim', + 'barrettruth/canola.nvim', init = function() vim.g.oil = {} end, diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yaml index ce81bef..c1d9d46 100644 --- a/.github/ISSUE_TEMPLATE/config.yaml +++ b/.github/ISSUE_TEMPLATE/config.yaml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - name: Questions - url: https://github.com/barrettruth/oil.nvim/discussions + url: https://github.com/barrettruth/canola.nvim/discussions about: Ask questions and discuss ideas diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 6515953..2a0fad8 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -9,7 +9,7 @@ body: options: - label: I have searched [existing - issues](https://github.com/barrettruth/oil.nvim/issues) + issues](https://github.com/barrettruth/canola.nvim/issues) required: true - type: textarea diff --git a/README.md b/README.md index 5cdda64..acdd02e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ -# oil.nvim +# canola.nvim -**A file explorer that lets you edit your filesystem like a buffer** - -Browse directories as normal Neovim buffers, then create, rename, move, copy, -and delete files by editing the listing and saving. Cross-directory operations -work seamlessly across local, SSH, S3, and trash adapters. +A refined [oil.nvim](https://github.com/stevearc/oil.nvim) — edit your +filesystem like a buffer, with bug fixes and community PRs that haven't landed +upstream. https://user-images.githubusercontent.com/506791/209727111-6b4a11f4-634a-4efa-9461-80e9717cea94.mp4 @@ -29,10 +27,10 @@ https://user-images.githubusercontent.com/506791/209727111-6b4a11f4-634a-4efa-94 ## Installation Install with your package manager of choice or via -[luarocks](https://luarocks.org/modules/barrettruth/oil.nvim): +[luarocks](https://luarocks.org/modules/barrettruth/canola.nvim): ``` -luarocks install oil.nvim +luarocks install canola.nvim ``` ## Documentation @@ -61,11 +59,11 @@ Before (`stevearc/oil.nvim`): } ``` -After (`barrettruth/oil.nvim`): +After (`barrettruth/canola.nvim`): ```lua { - 'barrettruth/oil.nvim', + 'barrettruth/canola.nvim', init = function() vim.g.oil = { ... } end, @@ -100,6 +98,6 @@ Drew Neil: ## Acknowledgements -oil.nvim was created by -[Steven Arcangeli](https://github.com/stevearc/oil.nvim). This fork is -maintained by [Barrett Ruth](https://github.com/barrettruth). +canola.nvim is a fork of [oil.nvim](https://github.com/stevearc/oil.nvim), +created by [Steven Arcangeli](https://github.com/stevearc). Maintained by +[Barrett Ruth](https://github.com/barrettruth). diff --git a/oil.nvim-scm-1.rockspec b/canola.nvim-scm-1.rockspec similarity index 68% rename from oil.nvim-scm-1.rockspec rename to canola.nvim-scm-1.rockspec index 8e1bb80..988d6a2 100644 --- a/oil.nvim-scm-1.rockspec +++ b/canola.nvim-scm-1.rockspec @@ -1,14 +1,14 @@ rockspec_format = '3.0' -package = 'oil.nvim' +package = 'canola.nvim' version = 'scm-1' source = { - url = 'git+https://github.com/barrettruth/oil.nvim.git', + url = 'git+https://github.com/barrettruth/canola.nvim.git', } description = { summary = 'Neovim file explorer: edit your filesystem like a buffer', - homepage = 'https://github.com/barrettruth/oil.nvim', + homepage = 'https://github.com/barrettruth/canola.nvim', license = 'MIT', } From 33889b2171db1985d4a5cbb11782a3645ffce5d3 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 22:04:57 -0500 Subject: [PATCH 19/77] docs: add upstream tracker Problem: the full upstream PR and issue triage was removed from the README during the repository modernization, leaving no user-facing record of what the fork addresses. Solution: restore the triage tables in a dedicated doc/upstream.md and link to it from the top of the README. Keeps the README clean while giving the full picture a permanent home. --- README.md | 2 + doc/upstream.md | 163 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 doc/upstream.md diff --git a/README.md b/README.md index acdd02e..3af4ff4 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ A refined [oil.nvim](https://github.com/stevearc/oil.nvim) — edit your filesystem like a buffer, with bug fixes and community PRs that haven't landed upstream. +[Upstream tracker](doc/upstream.md) — full PR and issue triage against stevearc/oil.nvim + https://user-images.githubusercontent.com/506791/209727111-6b4a11f4-634a-4efa-9461-80e9717cea94.mp4 ## Features diff --git a/doc/upstream.md b/doc/upstream.md new file mode 100644 index 0000000..35259b8 --- /dev/null +++ b/doc/upstream.md @@ -0,0 +1,163 @@ +# Upstream Tracker + +Triage of [stevearc/oil.nvim](https://github.com/stevearc/oil.nvim) PRs and +issues against this fork. + +## Cherry-picked PRs + +Upstream PRs cherry-picked or adapted into this fork. + +| PR | Description | Commit | +|---|---|---| +| [#495](https://github.com/stevearc/oil.nvim/pull/495) | Cancel visual/operator-pending mode on close | [`16f3d7b`](https://github.com/barrettruth/canola.nvim/commit/16f3d7b) | +| [#537](https://github.com/stevearc/oil.nvim/pull/537) | Configurable file/directory creation permissions | [`c6b4a7a`](https://github.com/barrettruth/canola.nvim/commit/c6b4a7a) | +| [#618](https://github.com/stevearc/oil.nvim/pull/618) | Opt-in filetype detection for icons | [`ded1725`](https://github.com/barrettruth/canola.nvim/commit/ded1725) | +| [#644](https://github.com/stevearc/oil.nvim/pull/644) | Pass entry to `is_hidden_file`/`is_always_hidden` | [`4ab4765`](https://github.com/barrettruth/canola.nvim/commit/4ab4765) | +| [#697](https://github.com/stevearc/oil.nvim/pull/697) | Recipe for file extension column | [`dcb3a08`](https://github.com/barrettruth/canola.nvim/commit/dcb3a08) | +| [#698](https://github.com/stevearc/oil.nvim/pull/698) | Executable file highlighting | [`41556ec`](https://github.com/barrettruth/canola.nvim/commit/41556ec), [`85ed9b8`](https://github.com/barrettruth/canola.nvim/commit/85ed9b8) | +| [#717](https://github.com/stevearc/oil.nvim/pull/717) | Add oil-git.nvim to extensions | [`582d9fc`](https://github.com/barrettruth/canola.nvim/commit/582d9fc) | +| [#720](https://github.com/stevearc/oil.nvim/pull/720) | Gate `BufAdd` autocmd behind config check | [`2228f80`](https://github.com/barrettruth/canola.nvim/commit/2228f80) | +| [#722](https://github.com/stevearc/oil.nvim/pull/722) | Fix freedesktop trash URL | [`b92ecb0`](https://github.com/barrettruth/canola.nvim/commit/b92ecb0) | +| [#723](https://github.com/stevearc/oil.nvim/pull/723) | Emit `OilReadPost` event after render | [`29239d5`](https://github.com/barrettruth/canola.nvim/commit/29239d5) | +| [#725](https://github.com/stevearc/oil.nvim/pull/725) | Normalize keymap keys before config merge | [`723145c`](https://github.com/barrettruth/canola.nvim/commit/723145c) | +| [#727](https://github.com/stevearc/oil.nvim/pull/727) | Clarify `get_current_dir` nil + Telescope recipe | [`eed6697`](https://github.com/barrettruth/canola.nvim/commit/eed6697) | + +## Original fixes + +Bugs fixed in this fork that remain open upstream. + +| Upstream issue | Description | PR | +|---|---|---| +| [#632](https://github.com/stevearc/oil.nvim/issues/632) | Preview + move = copy | [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | +| [#642](https://github.com/stevearc/oil.nvim/issues/642) | W10 warning under `nvim -R` | [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | +| [#670](https://github.com/stevearc/oil.nvim/issues/670) | Multi-directory cmdline args ignored | [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | +| [#673](https://github.com/stevearc/oil.nvim/issues/673) | Symlink newlines crash | [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | +| [#710](https://github.com/stevearc/oil.nvim/issues/710) | buftype empty on BufEnter | [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | + +## Open upstream PRs + +| PR | Description | Status | +|---|---|---| +| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | +| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | +| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | +| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | +| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | +| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | +| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | +| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | + +## Upstream issues + +**Status key:** `fixed` = original fix in fork, `resolved` = addressed by +cherry-picked PR, `not actionable` = can't/won't fix, `tracking` = known/not +yet addressed, `open` = not yet triaged. + +| Issue | Status | Notes | +|---|---|---| +| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | +| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | +| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | +| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | +| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | +| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | +| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | +| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | +| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | +| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | +| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | +| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | +| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | +| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | +| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | +| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | +| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | +| [#302](https://github.com/stevearc/oil.nvim/issues/302) | open | C-o parent nav makes buffer buflisted (P0) | +| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | +| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | +| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | +| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | +| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | +| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | +| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | +| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | +| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | +| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | +| [#363](https://github.com/stevearc/oil.nvim/issues/363) | open | `prompt_save_on_select_new_entry` uses wrong prompt | +| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | +| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | +| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | +| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | +| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | +| [#392](https://github.com/stevearc/oil.nvim/issues/392) | open | Option to skip delete prompt | +| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | +| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | +| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | +| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | +| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | +| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | +| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | +| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | +| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | +| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | +| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | +| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | +| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | +| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | +| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | +| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | +| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | +| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | +| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | +| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | +| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | +| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | +| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | +| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | +| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | +| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/canola.nvim/commit/38db6cf) | +| [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | +| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | +| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | +| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | +| [#612](https://github.com/stevearc/oil.nvim/issues/612) | open | Delete buffers on file delete (P2) | +| [#615](https://github.com/stevearc/oil.nvim/issues/615) | open | Cursor at name column on o/O (P2) | +| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | +| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | +| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | +| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | +| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | +| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | +| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | +| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | +| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | +| [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | +| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/canola.nvim/commit/f6bcdda) | +| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | +| [#650](https://github.com/stevearc/oil.nvim/issues/650) | open | Emit LSP `workspace.fileOperations` events | +| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | +| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | +| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | +| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | +| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | +| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | +| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | +| [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | +| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | +| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | +| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#682](https://github.com/stevearc/oil.nvim/issues/682) | open | `get_current_dir()` nil in non-telescope context | +| [#683](https://github.com/stevearc/oil.nvim/issues/683) | open | Path not shown in floating mode | +| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | +| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | +| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/canola.nvim/commit/ce64ae1) | +| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | +| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | +| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | +| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | +| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | +| [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | From eaf4efdf8ad7e96b5ba3bf4bb7bed75d40466992 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 22:05:41 -0500 Subject: [PATCH 20/77] fix(doc): readme --- doc/{oil.txt => canola.txt} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename doc/{oil.txt => canola.txt} (99%) diff --git a/doc/oil.txt b/doc/canola.txt similarity index 99% rename from doc/oil.txt rename to doc/canola.txt index 431eff1..b861fdb 100644 --- a/doc/oil.txt +++ b/doc/canola.txt @@ -1,5 +1,5 @@ -*oil.txt* -*Oil* *oil* *oil.nvim* +*canola.txt* +*Canola* *canola* *canola.nvim* *Oil* *oil* *oil.nvim* -------------------------------------------------------------------------------- CONTENTS *oil-contents* From 62c9cff67cf94d88eb798497869208835f7de558 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 22:05:43 -0500 Subject: [PATCH 21/77] fix(doc): readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3af4ff4..d6903e6 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ luarocks install canola.nvim ## Documentation ```vim -:help oil.nvim +:help canola.nvim ``` ## FAQ From 9316524fabf4e99822aaf8826acf39f8e3f7ade9 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 22:06:54 -0500 Subject: [PATCH 22/77] fix(doc): credit stevearc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6903e6..310dfe8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A refined [oil.nvim](https://github.com/stevearc/oil.nvim) — edit your filesystem like a buffer, with bug fixes and community PRs that haven't landed upstream. -[Upstream tracker](doc/upstream.md) — full PR and issue triage against stevearc/oil.nvim +[Upstream tracker](doc/upstream.md) — full PR and issue triage against [oil.nvim](https://github.com/stevearc/oil.nvim) https://user-images.githubusercontent.com/506791/209727111-6b4a11f4-634a-4efa-9461-80e9717cea94.mp4 From 1fda80f0b2607fa4a60edb50a5a6b1c19dfb2d05 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 22:07:07 -0500 Subject: [PATCH 23/77] fix(doc): improve phrasing --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 310dfe8..02e14d7 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,6 @@ Drew Neil: **Q: What are some alternatives?** - [stevearc/oil.nvim](https://github.com/stevearc/oil.nvim): the original - oil.nvim - [mini.files](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-files.md): cross-directory filesystem-as-buffer with a column view - [vim-vinegar](https://github.com/tpope/vim-vinegar): the granddaddy of From c51e3168deaae1a277006edac28d6650ff00bd8a Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 22 Feb 2026 22:09:02 -0500 Subject: [PATCH 24/77] fix(dic): format --- doc/upstream.md | 280 ++++++++++++++++++++++++------------------------ 1 file changed, 140 insertions(+), 140 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index 35259b8..dadeea1 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -7,157 +7,157 @@ issues against this fork. Upstream PRs cherry-picked or adapted into this fork. -| PR | Description | Commit | -|---|---|---| -| [#495](https://github.com/stevearc/oil.nvim/pull/495) | Cancel visual/operator-pending mode on close | [`16f3d7b`](https://github.com/barrettruth/canola.nvim/commit/16f3d7b) | -| [#537](https://github.com/stevearc/oil.nvim/pull/537) | Configurable file/directory creation permissions | [`c6b4a7a`](https://github.com/barrettruth/canola.nvim/commit/c6b4a7a) | -| [#618](https://github.com/stevearc/oil.nvim/pull/618) | Opt-in filetype detection for icons | [`ded1725`](https://github.com/barrettruth/canola.nvim/commit/ded1725) | -| [#644](https://github.com/stevearc/oil.nvim/pull/644) | Pass entry to `is_hidden_file`/`is_always_hidden` | [`4ab4765`](https://github.com/barrettruth/canola.nvim/commit/4ab4765) | -| [#697](https://github.com/stevearc/oil.nvim/pull/697) | Recipe for file extension column | [`dcb3a08`](https://github.com/barrettruth/canola.nvim/commit/dcb3a08) | -| [#698](https://github.com/stevearc/oil.nvim/pull/698) | Executable file highlighting | [`41556ec`](https://github.com/barrettruth/canola.nvim/commit/41556ec), [`85ed9b8`](https://github.com/barrettruth/canola.nvim/commit/85ed9b8) | -| [#717](https://github.com/stevearc/oil.nvim/pull/717) | Add oil-git.nvim to extensions | [`582d9fc`](https://github.com/barrettruth/canola.nvim/commit/582d9fc) | -| [#720](https://github.com/stevearc/oil.nvim/pull/720) | Gate `BufAdd` autocmd behind config check | [`2228f80`](https://github.com/barrettruth/canola.nvim/commit/2228f80) | -| [#722](https://github.com/stevearc/oil.nvim/pull/722) | Fix freedesktop trash URL | [`b92ecb0`](https://github.com/barrettruth/canola.nvim/commit/b92ecb0) | -| [#723](https://github.com/stevearc/oil.nvim/pull/723) | Emit `OilReadPost` event after render | [`29239d5`](https://github.com/barrettruth/canola.nvim/commit/29239d5) | -| [#725](https://github.com/stevearc/oil.nvim/pull/725) | Normalize keymap keys before config merge | [`723145c`](https://github.com/barrettruth/canola.nvim/commit/723145c) | -| [#727](https://github.com/stevearc/oil.nvim/pull/727) | Clarify `get_current_dir` nil + Telescope recipe | [`eed6697`](https://github.com/barrettruth/canola.nvim/commit/eed6697) | +| PR | Description | Commit | +| ----------------------------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| [#495](https://github.com/stevearc/oil.nvim/pull/495) | Cancel visual/operator-pending mode on close | [`16f3d7b`](https://github.com/barrettruth/canola.nvim/commit/16f3d7b) | +| [#537](https://github.com/stevearc/oil.nvim/pull/537) | Configurable file/directory creation permissions | [`c6b4a7a`](https://github.com/barrettruth/canola.nvim/commit/c6b4a7a) | +| [#618](https://github.com/stevearc/oil.nvim/pull/618) | Opt-in filetype detection for icons | [`ded1725`](https://github.com/barrettruth/canola.nvim/commit/ded1725) | +| [#644](https://github.com/stevearc/oil.nvim/pull/644) | Pass entry to `is_hidden_file`/`is_always_hidden` | [`4ab4765`](https://github.com/barrettruth/canola.nvim/commit/4ab4765) | +| [#697](https://github.com/stevearc/oil.nvim/pull/697) | Recipe for file extension column | [`dcb3a08`](https://github.com/barrettruth/canola.nvim/commit/dcb3a08) | +| [#698](https://github.com/stevearc/oil.nvim/pull/698) | Executable file highlighting | [`41556ec`](https://github.com/barrettruth/canola.nvim/commit/41556ec), [`85ed9b8`](https://github.com/barrettruth/canola.nvim/commit/85ed9b8) | +| [#717](https://github.com/stevearc/oil.nvim/pull/717) | Add oil-git.nvim to extensions | [`582d9fc`](https://github.com/barrettruth/canola.nvim/commit/582d9fc) | +| [#720](https://github.com/stevearc/oil.nvim/pull/720) | Gate `BufAdd` autocmd behind config check | [`2228f80`](https://github.com/barrettruth/canola.nvim/commit/2228f80) | +| [#722](https://github.com/stevearc/oil.nvim/pull/722) | Fix freedesktop trash URL | [`b92ecb0`](https://github.com/barrettruth/canola.nvim/commit/b92ecb0) | +| [#723](https://github.com/stevearc/oil.nvim/pull/723) | Emit `OilReadPost` event after render | [`29239d5`](https://github.com/barrettruth/canola.nvim/commit/29239d5) | +| [#725](https://github.com/stevearc/oil.nvim/pull/725) | Normalize keymap keys before config merge | [`723145c`](https://github.com/barrettruth/canola.nvim/commit/723145c) | +| [#727](https://github.com/stevearc/oil.nvim/pull/727) | Clarify `get_current_dir` nil + Telescope recipe | [`eed6697`](https://github.com/barrettruth/canola.nvim/commit/eed6697) | ## Original fixes Bugs fixed in this fork that remain open upstream. -| Upstream issue | Description | PR | -|---|---|---| -| [#632](https://github.com/stevearc/oil.nvim/issues/632) | Preview + move = copy | [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | -| [#642](https://github.com/stevearc/oil.nvim/issues/642) | W10 warning under `nvim -R` | [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | +| Upstream issue | Description | PR | +| ------------------------------------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | +| [#632](https://github.com/stevearc/oil.nvim/issues/632) | Preview + move = copy | [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | +| [#642](https://github.com/stevearc/oil.nvim/issues/642) | W10 warning under `nvim -R` | [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | | [#670](https://github.com/stevearc/oil.nvim/issues/670) | Multi-directory cmdline args ignored | [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | -| [#673](https://github.com/stevearc/oil.nvim/issues/673) | Symlink newlines crash | [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | -| [#710](https://github.com/stevearc/oil.nvim/issues/710) | buftype empty on BufEnter | [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | +| [#673](https://github.com/stevearc/oil.nvim/issues/673) | Symlink newlines crash | [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | +| [#710](https://github.com/stevearc/oil.nvim/issues/710) | buftype empty on BufEnter | [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | ## Open upstream PRs -| PR | Description | Status | -|---|---|---| -| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | -| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | -| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | -| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | -| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | -| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | -| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | -| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | +| PR | Description | Status | +| ----------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------ | +| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | +| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | +| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | +| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | +| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | +| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | +| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | +| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | ## Upstream issues **Status key:** `fixed` = original fix in fork, `resolved` = addressed by -cherry-picked PR, `not actionable` = can't/won't fix, `tracking` = known/not -yet addressed, `open` = not yet triaged. +cherry-picked PR, `not actionable` = can't/won't fix, `tracking` = known/not yet +addressed, `open` = not yet triaged. -| Issue | Status | Notes | -|---|---|---| -| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | -| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | -| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | -| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | -| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | -| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | -| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | -| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | -| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | -| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | -| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | -| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | -| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | -| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | -| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | -| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | -| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | -| [#302](https://github.com/stevearc/oil.nvim/issues/302) | open | C-o parent nav makes buffer buflisted (P0) | -| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | -| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | -| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | -| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | -| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | -| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | -| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | -| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | -| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | -| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | -| [#363](https://github.com/stevearc/oil.nvim/issues/363) | open | `prompt_save_on_select_new_entry` uses wrong prompt | -| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | -| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | -| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | -| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | -| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | -| [#392](https://github.com/stevearc/oil.nvim/issues/392) | open | Option to skip delete prompt | -| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | -| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | -| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | -| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | -| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | -| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | -| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | -| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | -| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | -| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | -| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | -| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | -| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | -| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | -| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | -| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | -| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | -| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | -| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | -| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | -| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | -| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | -| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | -| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | -| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | -| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/canola.nvim/commit/38db6cf) | -| [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | -| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | -| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | -| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | -| [#612](https://github.com/stevearc/oil.nvim/issues/612) | open | Delete buffers on file delete (P2) | -| [#615](https://github.com/stevearc/oil.nvim/issues/615) | open | Cursor at name column on o/O (P2) | -| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | -| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | -| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | -| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | -| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | -| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | -| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | -| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | -| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | -| [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | -| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/canola.nvim/commit/f6bcdda) | -| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | -| [#650](https://github.com/stevearc/oil.nvim/issues/650) | open | Emit LSP `workspace.fileOperations` events | -| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | -| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | -| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | -| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | -| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | -| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | -| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | -| [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | -| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | -| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | -| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#682](https://github.com/stevearc/oil.nvim/issues/682) | open | `get_current_dir()` nil in non-telescope context | -| [#683](https://github.com/stevearc/oil.nvim/issues/683) | open | Path not shown in floating mode | -| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | -| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | -| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/canola.nvim/commit/ce64ae1) | -| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | -| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | -| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | -| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | -| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | -| [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | +| Issue | Status | Notes | +| ------------------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | +| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | +| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | +| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | +| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | +| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | +| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | +| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | +| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | +| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | +| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | +| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | +| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | +| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | +| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | +| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | +| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | +| [#302](https://github.com/stevearc/oil.nvim/issues/302) | open | C-o parent nav makes buffer buflisted (P0) | +| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | +| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | +| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | +| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | +| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | +| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | +| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | +| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | +| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | +| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | +| [#363](https://github.com/stevearc/oil.nvim/issues/363) | open | `prompt_save_on_select_new_entry` uses wrong prompt | +| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | +| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | +| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | +| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | +| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | +| [#392](https://github.com/stevearc/oil.nvim/issues/392) | open | Option to skip delete prompt | +| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | +| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | +| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | +| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | +| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | +| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | +| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | +| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | +| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | +| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | +| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | +| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | +| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | +| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | +| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | +| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | +| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | +| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | +| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | +| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | +| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | +| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | +| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | +| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | +| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | +| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/canola.nvim/commit/38db6cf) | +| [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | +| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | +| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | +| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | +| [#612](https://github.com/stevearc/oil.nvim/issues/612) | open | Delete buffers on file delete (P2) | +| [#615](https://github.com/stevearc/oil.nvim/issues/615) | open | Cursor at name column on o/O (P2) | +| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | +| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | +| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | +| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | +| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | +| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | +| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | +| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | +| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | +| [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | +| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/canola.nvim/commit/f6bcdda) | +| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | +| [#650](https://github.com/stevearc/oil.nvim/issues/650) | open | Emit LSP `workspace.fileOperations` events | +| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | +| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | +| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | +| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | +| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | +| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | +| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | +| [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | +| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | +| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | +| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#682](https://github.com/stevearc/oil.nvim/issues/682) | open | `get_current_dir()` nil in non-telescope context | +| [#683](https://github.com/stevearc/oil.nvim/issues/683) | open | Path not shown in floating mode | +| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | +| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | +| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/canola.nvim/commit/ce64ae1) | +| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | +| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | +| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | +| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | +| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | +| [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | From 60bfbe05da1a0adb0b3ed28ac055cd23528b764e Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 23 Feb 2026 15:16:25 -0500 Subject: [PATCH 25/77] fix: preserve devicons highlight groups in nonicons icon provider Problem: when the nonicons direct API was detected, all icons were returned with the generic 'OilFileIcon' highlight group, losing per-filetype colors from nvim-web-devicons. Solution: resolve highlight groups from devicons when available so nonicons glyphs retain their per-filetype colors. --- lua/oil/util.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lua/oil/util.lua b/lua/oil/util.lua index 1ba9872..8e739a8 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -947,23 +947,26 @@ M.get_icon_provider = function() local has_nonicons, nonicons = pcall(require, 'nonicons') if has_nonicons and nonicons.get_icon then + local _, devicons = pcall(require, 'nvim-web-devicons') return function(type, name, conf, ft) if type == 'directory' then local icon = nonicons.get('file-directory') return icon or (conf and conf.directory or ''), 'OilDirIcon' end + local hl = devicons and select(2, devicons.get_icon(name)) or 'OilFileIcon' if ft then local ft_icon = nonicons.get_icon_by_filetype(ft) if ft_icon then - return ft_icon, 'OilFileIcon' + local ft_hl = devicons and select(2, devicons.get_icon_by_filetype(ft)) + return ft_icon, ft_hl or hl end end local icon = nonicons.get_icon(name) if icon then - return icon, 'OilFileIcon' + return icon, hl end local fallback = nonicons.get('file') - return fallback or (conf and conf.default_file or ''), 'OilFileIcon' + return fallback or (conf and conf.default_file or ''), hl end end From b87c665ccbbb96c7adbd03819ec99cca2b1aa945 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 23 Feb 2026 17:20:44 -0500 Subject: [PATCH 26/77] fix(icon): use fill directory by default --- lua/oil/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/oil/util.lua b/lua/oil/util.lua index 8e739a8..08ecc5b 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -950,7 +950,7 @@ M.get_icon_provider = function() local _, devicons = pcall(require, 'nvim-web-devicons') return function(type, name, conf, ft) if type == 'directory' then - local icon = nonicons.get('file-directory') + local icon = nonicons.get('file-directory-fill') return icon or (conf and conf.directory or ''), 'OilDirIcon' end local hl = devicons and select(2, devicons.get_icon(name)) or 'OilFileIcon' From 3140c152ea83018d0a81fa66a8c9e5506dc6d8d1 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 23 Feb 2026 18:13:51 -0500 Subject: [PATCH 27/77] ci: migrate to nix --- .github/workflows/quality.yaml | 29 +++++++-------------------- selene.toml | 1 + vim.toml | 36 ---------------------------------- vim.yaml | 24 +++++++++++++++++++++++ 4 files changed, 32 insertions(+), 58 deletions(-) delete mode 100644 vim.toml create mode 100644 vim.yaml diff --git a/.github/workflows/quality.yaml b/.github/workflows/quality.yaml index 3bf8b57..8381400 100644 --- a/.github/workflows/quality.yaml +++ b/.github/workflows/quality.yaml @@ -26,6 +26,7 @@ jobs: - '*.lua' - '.luarc.json' - '*.toml' + - 'vim.yaml' markdown: - '*.md' @@ -36,11 +37,8 @@ jobs: if: ${{ needs.changes.outputs.lua == 'true' }} steps: - uses: actions/checkout@v4 - - uses: JohnnyMorganz/stylua-action@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: 2.1.0 - args: --check lua spec + - uses: cachix/install-nix-action@v31 + - run: nix develop --command stylua --check lua spec lua-lint: name: Lua Lint Check @@ -49,11 +47,8 @@ jobs: if: ${{ needs.changes.outputs.lua == 'true' }} steps: - uses: actions/checkout@v4 - - name: Lint with Selene - uses: NTBBloodbath/selene-action@v1.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --display-style quiet . + - uses: cachix/install-nix-action@v31 + - run: nix develop --command selene --display-style quiet . lua-typecheck: name: Lua Type Check @@ -74,15 +69,5 @@ jobs: if: ${{ needs.changes.outputs.markdown == 'true' }} steps: - uses: actions/checkout@v4 - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 8 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - - name: Install prettier - run: pnpm add -g prettier@3.1.0 - - name: Check markdown formatting with prettier - run: prettier --check . + - uses: cachix/install-nix-action@v31 + - run: nix develop --command prettier --check . diff --git a/selene.toml b/selene.toml index 4fbd4a4..7f40a3f 100644 --- a/selene.toml +++ b/selene.toml @@ -4,3 +4,4 @@ exclude = [".direnv/*"] [lints] mixed_table = 'allow' unused_variable = 'allow' +bad_string_escape = 'allow' diff --git a/vim.toml b/vim.toml deleted file mode 100644 index 0fbe00a..0000000 --- a/vim.toml +++ /dev/null @@ -1,36 +0,0 @@ -[selene] -base = "lua51" -name = "vim" - -[vim] -any = true - -[jit] -any = true - -[bit] -any = true - -[assert] -any = true - -[a] -any = true - -[describe] -any = true - -[it] -any = true - -[before_each] -any = true - -[after_each] -any = true - -[spy] -any = true - -[stub] -any = true diff --git a/vim.yaml b/vim.yaml new file mode 100644 index 0000000..401fce6 --- /dev/null +++ b/vim.yaml @@ -0,0 +1,24 @@ +--- +base: lua51 +name: vim +lua_versions: + - luajit +globals: + vim: + any: true + jit: + any: true + assert: + any: true + describe: + any: true + it: + any: true + before_each: + any: true + after_each: + any: true + spy: + any: true + stub: + any: true From e90508c459e7f6689c10c12958ce4e8869af0f08 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 23 Feb 2026 18:18:35 -0500 Subject: [PATCH 28/77] ci: add bit luajit global --- vim.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vim.yaml b/vim.yaml index 401fce6..3821d25 100644 --- a/vim.yaml +++ b/vim.yaml @@ -22,3 +22,5 @@ globals: any: true stub: any: true + bit: + any: true From 262bf8710efcb13ccbc9c9a39e73ab424218c3b8 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 2 Mar 2026 19:25:08 -0500 Subject: [PATCH 29/77] fix: ensure nvim-web-devicoins exists --- lua/oil/util.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/oil/util.lua b/lua/oil/util.lua index 08ecc5b..413e7eb 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -947,7 +947,10 @@ M.get_icon_provider = function() local has_nonicons, nonicons = pcall(require, 'nonicons') if has_nonicons and nonicons.get_icon then - local _, devicons = pcall(require, 'nvim-web-devicons') + local has_devicons, devicons = pcall(require, 'nvim-web-devicons') + if not has_devicons then + devicons = nil + end return function(type, name, conf, ft) if type == 'directory' then local icon = nonicons.get('file-directory-fill') From 05234a67baf2e5f4a19eed61da60aac852d24f48 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 2 Mar 2026 19:26:02 -0500 Subject: [PATCH 30/77] fix: use guard clause --- lua/oil/util.lua | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lua/oil/util.lua b/lua/oil/util.lua index 413e7eb..b04b6a9 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -974,22 +974,25 @@ M.get_icon_provider = function() end local has_devicons, devicons = pcall(require, 'nvim-web-devicons') - if has_devicons then - return function(type, name, conf, ft) - if type == 'directory' then - return conf and conf.directory or '', 'OilDirIcon' - else - if ft then - local ft_icon, ft_hl = devicons.get_icon_by_filetype(ft) - if ft_icon and ft_icon ~= '' then - return ft_icon, ft_hl - end + + if not has_devicons then + return + end + + return function(type, name, conf, ft) + if type == 'directory' then + return conf and conf.directory or '', 'OilDirIcon' + else + if ft then + local ft_icon, ft_hl = devicons.get_icon_by_filetype(ft) + if ft_icon and ft_icon ~= '' then + return ft_icon, ft_hl end - local icon, hl = devicons.get_icon(name) - hl = hl or 'OilFileIcon' - icon = icon or (conf and conf.default_file or '') - return icon, hl end + local icon, hl = devicons.get_icon(name) + hl = hl or 'OilFileIcon' + icon = icon or (conf and conf.default_file or '') + return icon, hl end end end From 63fb912d52d154c3e165862e6f1819374bbafd5f Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 2 Mar 2026 20:21:47 -0500 Subject: [PATCH 31/77] fix(icons): use nonicons hl groups --- lua/oil/util.lua | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lua/oil/util.lua b/lua/oil/util.lua index b04b6a9..3703d1a 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -953,23 +953,21 @@ M.get_icon_provider = function() end return function(type, name, conf, ft) if type == 'directory' then - local icon = nonicons.get('file-directory-fill') - return icon or (conf and conf.directory or ''), 'OilDirIcon' + local icon, hl = nonicons.get('file-directory-fill') + return icon or (conf and conf.directory or ''), hl or 'OilDirIcon' end - local hl = devicons and select(2, devicons.get_icon(name)) or 'OilFileIcon' if ft then - local ft_icon = nonicons.get_icon_by_filetype(ft) + local ft_icon, ft_hl = nonicons.get_icon_by_filetype(ft) if ft_icon then - local ft_hl = devicons and select(2, devicons.get_icon_by_filetype(ft)) - return ft_icon, ft_hl or hl + return ft_icon, ft_hl or 'OilFileIcon' end end - local icon = nonicons.get_icon(name) + local icon, hl = nonicons.get_icon(name) if icon then - return icon, hl + return icon, hl or 'OilFileIcon' end - local fallback = nonicons.get('file') - return fallback or (conf and conf.default_file or ''), hl + local fallback, fallback_hl = nonicons.get('file') + return fallback or (conf and conf.default_file or ''), fallback_hl or 'OilFileIcon' end end From c4d827070e7c4c8371960b38f0611574db2fb6a0 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:15:46 -0500 Subject: [PATCH 32/77] ci: add weekly upstream digest workflow (#37) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: new upstream issues and PRs slip through because there's no mechanism to surface them — manual polling of stevearc/oil.nvim is required and easy to forget. Solution: add a Monday 9am UTC scheduled workflow that reads the highest stevearc/oil.nvim number from doc/upstream.md, fetches merged PRs and new open issues/PRs above that threshold via the gh CLI, and creates a structured digest issue in barrettruth/canola.nvim. No issue is created when there's nothing new. Falls back to a 30-day window if doc/upstream.md can't be parsed. --- .github/scripts/upstream_digest.py | 156 ++++++++++++++++++++++++++ .github/workflows/upstream-digest.yml | 21 ++++ 2 files changed, 177 insertions(+) create mode 100644 .github/scripts/upstream_digest.py create mode 100644 .github/workflows/upstream-digest.yml diff --git a/.github/scripts/upstream_digest.py b/.github/scripts/upstream_digest.py new file mode 100644 index 0000000..fcd82e2 --- /dev/null +++ b/.github/scripts/upstream_digest.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +import json +import re +import subprocess +import sys +from datetime import date, timedelta + + +UPSTREAM = "stevearc/oil.nvim" +TARGET = "barrettruth/canola.nvim" +UPSTREAM_MD = "doc/upstream.md" +LABEL = "upstream/digest" + + +def get_last_tracked_number(): + try: + with open(UPSTREAM_MD) as f: + content = f.read() + numbers = re.findall( + r"\[#(\d+)\]\(https://github\.com/stevearc/oil\.nvim", content + ) + if numbers: + return max(int(n) for n in numbers) + except OSError: + pass + return None + + +def gh(*args): + result = subprocess.run( + ["gh"] + list(args), + capture_output=True, + text=True, + check=True, + ) + return result.stdout.strip() + + +def fetch_items(last_number, since_date): + merged_prs = json.loads( + gh( + "pr", "list", + "--repo", UPSTREAM, + "--state", "merged", + "--limit", "100", + "--json", "number,title,mergedAt,url", + ) + ) + + open_issues = json.loads( + gh( + "issue", "list", + "--repo", UPSTREAM, + "--state", "open", + "--limit", "100", + "--json", "number,title,createdAt,url", + ) + ) + + open_prs = json.loads( + gh( + "pr", "list", + "--repo", UPSTREAM, + "--state", "open", + "--limit", "100", + "--json", "number,title,createdAt,url", + ) + ) + + if last_number is not None: + merged_prs = [x for x in merged_prs if x["number"] > last_number] + open_issues = [x for x in open_issues if x["number"] > last_number] + open_prs = [x for x in open_prs if x["number"] > last_number] + else: + cutoff = since_date.isoformat() + merged_prs = [x for x in merged_prs if x.get("mergedAt", "") >= cutoff] + open_issues = [x for x in open_issues if x.get("createdAt", "") >= cutoff] + open_prs = [x for x in open_prs if x.get("createdAt", "") >= cutoff] + + merged_prs.sort(key=lambda x: x["number"]) + open_issues.sort(key=lambda x: x["number"]) + open_prs.sort(key=lambda x: x["number"]) + + return merged_prs, open_issues, open_prs + + +def format_row(item): + num = item["number"] + title = item["title"] + url = item["url"] + return f"- [#{num}]({url}) — {title}" + + +def build_body(merged_prs, open_issues, open_prs, last_number): + if last_number is not None: + summary = f"Items with number > #{last_number} (last entry in `doc/upstream.md`)." + else: + summary = "Last 30 days (could not parse `doc/upstream.md` for a baseline)." + + sections = [summary, ""] + + sections.append("## Merged PRs") + if merged_prs: + sections.extend(format_row(x) for x in merged_prs) + else: + sections.append("_None_") + + sections.append("") + sections.append("## New open issues") + if open_issues: + sections.extend(format_row(x) for x in open_issues) + else: + sections.append("_None_") + + sections.append("") + sections.append("## New open PRs") + if open_prs: + sections.extend(format_row(x) for x in open_prs) + else: + sections.append("_None_") + + return "\n".join(sections) + + +def main(): + last_number = get_last_tracked_number() + since_date = date.today() - timedelta(days=30) + + merged_prs, open_issues, open_prs = fetch_items(last_number, since_date) + + total = len(merged_prs) + len(open_issues) + len(open_prs) + if total == 0: + print("No new upstream activity. Skipping issue creation.") + return + + today = date.today().isoformat() + title = f"upstream digest: week of {today}" + body = build_body(merged_prs, open_issues, open_prs, last_number) + + gh( + "issue", "create", + "--repo", TARGET, + "--title", title, + "--label", LABEL, + "--body", body, + ) + + print(f"Created digest issue: {title} ({total} items)") + + +if __name__ == "__main__": + try: + main() + except subprocess.CalledProcessError as e: + print(f"gh command failed: {e.stderr}", file=sys.stderr) + sys.exit(1) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml new file mode 100644 index 0000000..18da93e --- /dev/null +++ b/.github/workflows/upstream-digest.yml @@ -0,0 +1,21 @@ +name: upstream digest + +on: + schedule: + - cron: "0 9 * * 1" + workflow_dispatch: + +permissions: + issues: write + contents: read + +jobs: + digest: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Create upstream digest issue + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: python3 .github/scripts/upstream_digest.py From 56d174541571d6fa7ea94fccb26db883e93ebbbe Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:49:30 -0500 Subject: [PATCH 33/77] ci(digest): update to PR-based upstream tracker workflow (#40) --- .github/scripts/upstream_digest.py | 134 +++++++++++++------------- .github/workflows/upstream-digest.yml | 31 +++++- 2 files changed, 96 insertions(+), 69 deletions(-) diff --git a/.github/scripts/upstream_digest.py b/.github/scripts/upstream_digest.py index fcd82e2..2f0e949 100644 --- a/.github/scripts/upstream_digest.py +++ b/.github/scripts/upstream_digest.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import json +import os import re import subprocess import sys @@ -7,9 +8,10 @@ from datetime import date, timedelta UPSTREAM = "stevearc/oil.nvim" -TARGET = "barrettruth/canola.nvim" UPSTREAM_MD = "doc/upstream.md" -LABEL = "upstream/digest" + +PRS_HEADING = "## Open upstream PRs" +ISSUES_HEADING = "## Upstream issues" def get_last_tracked_number(): @@ -43,10 +45,18 @@ def fetch_items(last_number, since_date): "--repo", UPSTREAM, "--state", "merged", "--limit", "100", - "--json", "number,title,mergedAt,url", + "--json", "number,title,url", + ) + ) + open_prs = json.loads( + gh( + "pr", "list", + "--repo", UPSTREAM, + "--state", "open", + "--limit", "100", + "--json", "number,title,createdAt,url", ) ) - open_issues = json.loads( gh( "issue", "list", @@ -57,96 +67,88 @@ def fetch_items(last_number, since_date): ) ) - open_prs = json.loads( - gh( - "pr", "list", - "--repo", UPSTREAM, - "--state", "open", - "--limit", "100", - "--json", "number,title,createdAt,url", - ) - ) - if last_number is not None: merged_prs = [x for x in merged_prs if x["number"] > last_number] - open_issues = [x for x in open_issues if x["number"] > last_number] open_prs = [x for x in open_prs if x["number"] > last_number] + open_issues = [x for x in open_issues if x["number"] > last_number] else: cutoff = since_date.isoformat() - merged_prs = [x for x in merged_prs if x.get("mergedAt", "") >= cutoff] - open_issues = [x for x in open_issues if x.get("createdAt", "") >= cutoff] + merged_prs = [] open_prs = [x for x in open_prs if x.get("createdAt", "") >= cutoff] + open_issues = [x for x in open_issues if x.get("createdAt", "") >= cutoff] merged_prs.sort(key=lambda x: x["number"]) - open_issues.sort(key=lambda x: x["number"]) open_prs.sort(key=lambda x: x["number"]) + open_issues.sort(key=lambda x: x["number"]) - return merged_prs, open_issues, open_prs + return merged_prs, open_prs, open_issues -def format_row(item): - num = item["number"] - title = item["title"] - url = item["url"] - return f"- [#{num}]({url}) — {title}" +def append_to_section(content, heading, new_rows): + lines = content.split("\n") + in_section = False + last_table_row = -1 + for i, line in enumerate(lines): + if line.startswith("## "): + in_section = line.strip() == heading + if in_section and line.startswith("|"): + last_table_row = i -def build_body(merged_prs, open_issues, open_prs, last_number): - if last_number is not None: - summary = f"Items with number > #{last_number} (last entry in `doc/upstream.md`)." - else: - summary = "Last 30 days (could not parse `doc/upstream.md` for a baseline)." + if last_table_row == -1: + return content - sections = [summary, ""] - - sections.append("## Merged PRs") - if merged_prs: - sections.extend(format_row(x) for x in merged_prs) - else: - sections.append("_None_") - - sections.append("") - sections.append("## New open issues") - if open_issues: - sections.extend(format_row(x) for x in open_issues) - else: - sections.append("_None_") - - sections.append("") - sections.append("## New open PRs") - if open_prs: - sections.extend(format_row(x) for x in open_prs) - else: - sections.append("_None_") - - return "\n".join(sections) + return "\n".join( + lines[: last_table_row + 1] + new_rows + lines[last_table_row + 1 :] + ) def main(): last_number = get_last_tracked_number() since_date = date.today() - timedelta(days=30) - merged_prs, open_issues, open_prs = fetch_items(last_number, since_date) + merged_prs, open_prs, open_issues = fetch_items(last_number, since_date) - total = len(merged_prs) + len(open_issues) + len(open_prs) + total = len(merged_prs) + len(open_prs) + len(open_issues) if total == 0: - print("No new upstream activity. Skipping issue creation.") + print("No new upstream activity.") return - today = date.today().isoformat() - title = f"upstream digest: week of {today}" - body = build_body(merged_prs, open_issues, open_prs, last_number) + with open(UPSTREAM_MD) as f: + content = f.read() - gh( - "issue", "create", - "--repo", TARGET, - "--title", title, - "--label", LABEL, - "--body", body, + pr_rows = [] + for pr in open_prs: + pr_rows.append(f"| [#{pr['number']}]({pr['url']}) | {pr['title']} | open |") + for pr in merged_prs: + pr_rows.append( + f"| [#{pr['number']}]({pr['url']}) | {pr['title']} | merged — not cherry-picked |" + ) + + issue_rows = [] + for issue in open_issues: + issue_rows.append( + f"| [#{issue['number']}]({issue['url']}) | open | {issue['title']} |" + ) + + if pr_rows: + content = append_to_section(content, PRS_HEADING, pr_rows) + if issue_rows: + content = append_to_section(content, ISSUES_HEADING, issue_rows) + + with open(UPSTREAM_MD, "w") as f: + f.write(content) + + github_output = os.environ.get("GITHUB_OUTPUT") + if github_output: + with open(github_output, "a") as f: + f.write("changed=true\n") + + print( + f"Added {len(open_prs)} open PR(s), {len(merged_prs)} merged PR(s), " + f"{len(open_issues)} issue(s) to {UPSTREAM_MD}" ) - print(f"Created digest issue: {title} ({total} items)") - if __name__ == "__main__": try: diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index 18da93e..a70ee5b 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -6,8 +6,8 @@ on: workflow_dispatch: permissions: - issues: write - contents: read + contents: write + pull-requests: write jobs: digest: @@ -15,7 +15,32 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Create upstream digest issue + - name: Update upstream tracker + id: digest env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: python3 .github/scripts/upstream_digest.py + + - name: Format doc/upstream.md + if: steps.digest.outputs.changed == 'true' + run: npx --yes prettier --write doc/upstream.md + + - name: Create PR + if: steps.digest.outputs.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + DATE=$(date +%Y-%m-%d) + BRANCH="ci/upstream-digest-${DATE}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b "${BRANCH}" + git add doc/upstream.md + git commit -m "docs(upstream): add digest for week of ${DATE}" + git push origin "${BRANCH}" + PR_URL=$(gh pr create \ + --title "docs(upstream): add digest for week of ${DATE}" \ + --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ + --base main \ + --head "${BRANCH}") + gh pr merge "${PR_URL}" --auto --squash From 61e84bbc5f995543e5333b4d923944375edeccac Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:59:08 -0500 Subject: [PATCH 34/77] ci(digest): close existing open digest PRs before creating new one (#42) Problem: if a digest PR is not merged before the next weekly run, a second PR is created for the same items plus any new ones, leading to duplicate open PRs. Solution: before fetching upstream activity, close any open PRs labeled upstream/digest (deleting their branches). The new run re-fetches all items since the last merged baseline and produces a single up-to-date PR. --- .github/workflows/upstream-digest.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index a70ee5b..533b0b3 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -15,6 +15,20 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Close existing digest PRs + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr list \ + --repo barrettruth/canola.nvim \ + --label "upstream/digest" \ + --state open \ + --json number \ + --jq '.[].number' \ + | xargs -r -I{} gh pr close {} \ + --repo barrettruth/canola.nvim \ + --delete-branch + - name: Update upstream tracker id: digest env: @@ -42,5 +56,6 @@ jobs: --title "docs(upstream): add digest for week of ${DATE}" \ --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ --base main \ - --head "${BRANCH}") + --head "${BRANCH}" \ + --label "upstream/digest") gh pr merge "${PR_URL}" --auto --squash From 20bb43057e6615d8e1b1c9f8991c662fefc4db13 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:06:08 -0500 Subject: [PATCH 35/77] ci(digest): use fixed branch with force-push for weekly digest (#44) Problem: the workflow creates a new dated branch each run. If a digest PR is not merged before the next run, duplicate PRs accumulate. Solution: use a single canonical branch ci/upstream-digest with --force push. Each run resets to main, applies any new items, and force-pushes. If a PR is already open for the branch, GitHub updates it in place. A new PR is only created (with auto-merge) when none exists. The close-stale step is no longer needed. --- .github/workflows/upstream-digest.yml | 38 +++++++++------------------ 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index 533b0b3..f3482cc 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -15,20 +15,6 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Close existing digest PRs - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr list \ - --repo barrettruth/canola.nvim \ - --label "upstream/digest" \ - --state open \ - --json number \ - --jq '.[].number' \ - | xargs -r -I{} gh pr close {} \ - --repo barrettruth/canola.nvim \ - --delete-branch - - name: Update upstream tracker id: digest env: @@ -39,23 +25,23 @@ jobs: if: steps.digest.outputs.changed == 'true' run: npx --yes prettier --write doc/upstream.md - - name: Create PR + - name: Push and open PR if needed if: steps.digest.outputs.changed == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - DATE=$(date +%Y-%m-%d) - BRANCH="ci/upstream-digest-${DATE}" + BRANCH="ci/upstream-digest" git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git checkout -b "${BRANCH}" git add doc/upstream.md - git commit -m "docs(upstream): add digest for week of ${DATE}" - git push origin "${BRANCH}" - PR_URL=$(gh pr create \ - --title "docs(upstream): add digest for week of ${DATE}" \ - --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ - --base main \ - --head "${BRANCH}" \ - --label "upstream/digest") - gh pr merge "${PR_URL}" --auto --squash + git commit -m "docs(upstream): upstream digest $(date +%Y-%m-%d)" + git push --force origin "${BRANCH}" + if ! gh pr list --head "${BRANCH}" --state open --json number --jq '.[0].number' | grep -q .; then + PR_URL=$(gh pr create \ + --title "docs(upstream): upstream digest" \ + --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ + --base main \ + --head "${BRANCH}") + gh pr merge "${PR_URL}" --auto --squash + fi From 09acf0c3fec60b8348ccbfd439c3d26ac39c305a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:08:41 -0500 Subject: [PATCH 36/77] docs(upstream): upstream digest (#45) docs(upstream): upstream digest 2026-03-03 Co-authored-by: github-actions[bot] --- doc/upstream.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index dadeea1..f83b4a2 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -36,16 +36,17 @@ Bugs fixed in this fork that remain open upstream. ## Open upstream PRs -| PR | Description | Status | -| ----------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------ | -| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | -| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | -| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | -| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | -| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | -| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | -| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | -| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | +| PR | Description | Status | +| ----------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------ | +| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | +| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | +| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | +| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | +| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | +| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | +| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | +| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | +| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with a selection. | open | ## Upstream issues @@ -161,3 +162,4 @@ addressed, `open` = not yet triaged. | [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | | [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | | [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | +| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | feature request: make icons virtual text | From 71b51746afa970d3bac7d335a4b822167ecc27ff Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:18:20 -0500 Subject: [PATCH 37/77] ci(digest): auto-approve digest PRs via PAT to satisfy review requirement (#46) Problem: the main branch ruleset requires 1 approving review, which blocks auto-merge. The GITHUB_TOKEN cannot approve its own PR. Solution: after creating the PR, approve it using DIGEST_PAT (a fine-grained PAT stored as a repo secret), then enable auto-merge. The approval comes from a different actor than the bot, satisfying require_last_push_approval. --- .github/workflows/upstream-digest.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index f3482cc..bb7d8f7 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -43,5 +43,6 @@ jobs: --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ --base main \ --head "${BRANCH}") + GH_TOKEN="${{ secrets.DIGEST_PAT }}" gh pr review "${PR_URL}" --approve gh pr merge "${PR_URL}" --auto --squash fi From 502580332453a500b687e4f2e3ec59165b23d578 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Tue, 3 Mar 2026 15:19:25 -0500 Subject: [PATCH 38/77] docs(upstream): remove #735 and #736 for digest re-test --- doc/upstream.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index f83b4a2..5754760 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -46,7 +46,6 @@ Bugs fixed in this fork that remain open upstream. | [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | | [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | | [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | -| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with a selection. | open | ## Upstream issues @@ -162,4 +161,3 @@ addressed, `open` = not yet triaged. | [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | | [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | | [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | -| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | feature request: make icons virtual text | From b7c65a1d4b9c14a9fe85a836ac08985b3567240c Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:22:20 -0500 Subject: [PATCH 39/77] ci(digest): remove PAT approval step (#48) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ci(digest): remove PAT approval step — auto-approve handles it --- .github/workflows/upstream-digest.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index bb7d8f7..f3482cc 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -43,6 +43,5 @@ jobs: --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ --base main \ --head "${BRANCH}") - GH_TOKEN="${{ secrets.DIGEST_PAT }}" gh pr review "${PR_URL}" --approve gh pr merge "${PR_URL}" --auto --squash fi From 0c930bda2b0cf9493a7073dedfc28ac598d96250 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:29:03 -0500 Subject: [PATCH 40/77] ci(digest): create digest PR with PAT so CI triggers (#50) Problem: GITHUB_TOKEN-created PRs suppress pull_request workflow triggers, so CI never runs and auto-merge stalls indefinitely. Solution: use DIGEST_PAT to create the PR. A PAT-created PR is treated as a real user action, triggering CI normally. Auto-approve handles the review requirement, auto-merge fires when checks pass. --- .github/workflows/upstream-digest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index f3482cc..2e51558 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -38,7 +38,7 @@ jobs: git commit -m "docs(upstream): upstream digest $(date +%Y-%m-%d)" git push --force origin "${BRANCH}" if ! gh pr list --head "${BRANCH}" --state open --json number --jq '.[0].number' | grep -q .; then - PR_URL=$(gh pr create \ + PR_URL=$(GH_TOKEN="${{ secrets.DIGEST_PAT }}" gh pr create \ --title "docs(upstream): upstream digest" \ --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ --base main \ From 9ad67b05a629decc4cf09974b7bad4b392ac88fb Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:35:25 -0500 Subject: [PATCH 41/77] ci(digest): run CI on push to ci/upstream-digest branch (#53) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: GITHUB_TOKEN-created PRs suppress pull_request triggers, so CI never runs and auto-merge stalls. Solution: add ci/upstream-digest to the push trigger in test and quality workflows. CI runs on the branch push before the PR exists; check results attach to the commit SHA so the PR sees them as passing. The digest workflow reverts to GITHUB_TOKEN for PR creation — no PAT needed, no contribution inflation. --- .github/workflows/quality.yaml | 2 +- .github/workflows/test.yaml | 2 +- .github/workflows/upstream-digest.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/quality.yaml b/.github/workflows/quality.yaml index 8381400..f1c28fb 100644 --- a/.github/workflows/quality.yaml +++ b/.github/workflows/quality.yaml @@ -5,7 +5,7 @@ on: pull_request: branches: [main] push: - branches: [main] + branches: [main, ci/upstream-digest] jobs: changes: diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6910389..7950fc7 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -4,7 +4,7 @@ on: pull_request: branches: [main] push: - branches: [main] + branches: [main, ci/upstream-digest] jobs: test: diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index 2e51558..f3482cc 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -38,7 +38,7 @@ jobs: git commit -m "docs(upstream): upstream digest $(date +%Y-%m-%d)" git push --force origin "${BRANCH}" if ! gh pr list --head "${BRANCH}" --state open --json number --jq '.[0].number' | grep -q .; then - PR_URL=$(GH_TOKEN="${{ secrets.DIGEST_PAT }}" gh pr create \ + PR_URL=$(gh pr create \ --title "docs(upstream): upstream digest" \ --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ --base main \ From 280b3f0f624de6f3fc7c54c0304ef32a764a0aa9 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:43:49 -0500 Subject: [PATCH 42/77] ci(digest): push with PAT to trigger CI and auto-approve as barrettruth (#56) ci(digest): push branch with PAT so CI triggers Problem: GITHUB_TOKEN suppresses all downstream workflow triggers including push events, so CI never runs on the digest branch. Solution: push with DIGEST_PAT (triggers CI as a real user push), then reset the remote to GITHUB_TOKEN for PR creation. Admin bypass on the ruleset handles the review requirement. --- .github/workflows/upstream-digest.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index f3482cc..39a8813 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -36,12 +36,14 @@ jobs: git checkout -b "${BRANCH}" git add doc/upstream.md git commit -m "docs(upstream): upstream digest $(date +%Y-%m-%d)" + git remote set-url origin "https://x-access-token:${{ secrets.DIGEST_PAT }}@github.com/barrettruth/canola.nvim.git" git push --force origin "${BRANCH}" - if ! gh pr list --head "${BRANCH}" --state open --json number --jq '.[0].number' | grep -q .; then - PR_URL=$(gh pr create \ + if ! GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" gh pr list --head "${BRANCH}" --state open --json number --jq '.[0].number' | grep -q .; then + PR_URL=$(GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" gh pr create \ --title "docs(upstream): upstream digest" \ --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ --base main \ --head "${BRANCH}") - gh pr merge "${PR_URL}" --auto --squash + GH_TOKEN="${{ secrets.DIGEST_PAT }}" gh pr review "${PR_URL}" --approve + GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" gh pr merge "${PR_URL}" --auto --squash fi From 22d9f521d7d32d1e9fcff3f134e61ffcbf8f0ab7 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:48:18 -0500 Subject: [PATCH 43/77] ci(digest): unset checkout extraheader so PAT push triggers CI (#59) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: actions/checkout sets an http.extraheader with GITHUB_TOKEN that overrides any credentials in the remote URL, so git push uses GITHUB_TOKEN regardless of the URL — suppressing CI triggers. Solution: unset the extraheader before pushing, forcing git to use the DIGEST_PAT embedded in the remote URL. --- .github/workflows/upstream-digest.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index 39a8813..ff0c23b 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -36,6 +36,7 @@ jobs: git checkout -b "${BRANCH}" git add doc/upstream.md git commit -m "docs(upstream): upstream digest $(date +%Y-%m-%d)" + git config --unset http.https://github.com/.extraheader git remote set-url origin "https://x-access-token:${{ secrets.DIGEST_PAT }}@github.com/barrettruth/canola.nvim.git" git push --force origin "${BRANCH}" if ! GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" gh pr list --head "${BRANCH}" --state open --json number --jq '.[0].number' | grep -q .; then From 6af0172eb3f6055026b107c48941dc71156c141e Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 15:52:27 -0500 Subject: [PATCH 44/77] ci(digest): approve with GITHUB_TOKEN not PAT (#61) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit require_last_push_approval blocks barrettruth from approving their own push. The bot (GITHUB_TOKEN) approves instead — different actor from the PAT pusher, satisfying the rule. --- .github/workflows/upstream-digest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index ff0c23b..180cd29 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -45,6 +45,6 @@ jobs: --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ --base main \ --head "${BRANCH}") - GH_TOKEN="${{ secrets.DIGEST_PAT }}" gh pr review "${PR_URL}" --approve + gh pr review "${PR_URL}" --approve GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" gh pr merge "${PR_URL}" --auto --squash fi From 244db7531cc3bad629f119114c8fda85b3b8c689 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:01:15 -0500 Subject: [PATCH 45/77] ci(digest): drop explicit approve, rely on admin bypass (#64) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GITHUB_TOKEN has admin-level bypass on the ruleset. When gh pr merge --auto is called, the bypass satisfies the review requirement automatically — no explicit approve step needed. The self-review error is gone. PAT still handles the push so CI triggers. --- .github/workflows/upstream-digest.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index 180cd29..df155e2 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -45,6 +45,5 @@ jobs: --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ --base main \ --head "${BRANCH}") - gh pr review "${PR_URL}" --approve - GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" gh pr merge "${PR_URL}" --auto --squash + gh pr merge "${PR_URL}" --auto --squash fi From ad03b3771a5cd05f62cd51549b3e4a58b60256b1 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:07:53 -0500 Subject: [PATCH 46/77] ci(digest): approve with DIGEST_PAT after disabling require_last_push_approval (#66) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit require_last_push_approval blocked barrettruth from approving their own push. Disabled that restriction in the ruleset — 1 approval is still required for all PRs, but the approver can now be the pusher. DIGEST_PAT (barrettruth) approves, CI runs via PAT push, auto-merge fires when checks pass. --- .github/workflows/upstream-digest.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yml index df155e2..2ebfc22 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yml @@ -45,5 +45,6 @@ jobs: --body "Automated weekly digest of new upstream activity. Triage by updating statuses and notes." \ --base main \ --head "${BRANCH}") + GH_TOKEN="${{ secrets.DIGEST_PAT }}" gh pr review "${PR_URL}" --approve gh pr merge "${PR_URL}" --auto --squash fi From 9b656387fb295fa1742dad3fb793cfa41eac252a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 21:08:58 +0000 Subject: [PATCH 47/77] docs(upstream): upstream digest (#67) docs(upstream): upstream digest 2026-03-03 Co-authored-by: github-actions[bot] --- doc/upstream.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/upstream.md b/doc/upstream.md index 5754760..f83b4a2 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -46,6 +46,7 @@ Bugs fixed in this fork that remain open upstream. | [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | | [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | | [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | +| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with a selection. | open | ## Upstream issues @@ -161,3 +162,4 @@ addressed, `open` = not yet triaged. | [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | | [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | | [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | +| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | feature request: make icons virtual text | From aee5ea10c6dd3fb00e301ad714b07e007bb339cd Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Wed, 4 Mar 2026 13:49:06 -0500 Subject: [PATCH 48/77] ci: scripts and format (#68) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci(digest): approve with DIGEST_PAT after disabling require_last_push_approval require_last_push_approval blocked barrettruth from approving their own push. Disabled that restriction in the ruleset — 1 approval is still required for all PRs, but the approver can now be the pusher. DIGEST_PAT (barrettruth) approves, CI runs via PAT push, auto-merge fires when checks pass. * ci: format + scripts --- .../{upstream-digest.yml => upstream-digest.yaml} | 2 +- .luarc.json | 3 ++- .styluaignore | 1 + README.md | 3 ++- scripts/ci.sh | 7 +++++++ 5 files changed, 13 insertions(+), 3 deletions(-) rename .github/workflows/{upstream-digest.yml => upstream-digest.yaml} (98%) create mode 100644 .styluaignore create mode 100755 scripts/ci.sh diff --git a/.github/workflows/upstream-digest.yml b/.github/workflows/upstream-digest.yaml similarity index 98% rename from .github/workflows/upstream-digest.yml rename to .github/workflows/upstream-digest.yaml index 2ebfc22..17020d4 100644 --- a/.github/workflows/upstream-digest.yml +++ b/.github/workflows/upstream-digest.yaml @@ -2,7 +2,7 @@ name: upstream digest on: schedule: - - cron: "0 9 * * 1" + - cron: '0 9 * * 1' workflow_dispatch: permissions: diff --git a/.luarc.json b/.luarc.json index c0448ca..78a7d8a 100644 --- a/.luarc.json +++ b/.luarc.json @@ -4,7 +4,8 @@ "pathStrict": true }, "workspace": { - "checkThirdParty": false + "checkThirdParty": false, + "ignoreDir": [".direnv"] }, "type": { "checkTableShape": true diff --git a/.styluaignore b/.styluaignore new file mode 100644 index 0000000..9b42106 --- /dev/null +++ b/.styluaignore @@ -0,0 +1 @@ +.direnv/ diff --git a/README.md b/README.md index 02e14d7..771c6a7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ A refined [oil.nvim](https://github.com/stevearc/oil.nvim) — edit your filesystem like a buffer, with bug fixes and community PRs that haven't landed upstream. -[Upstream tracker](doc/upstream.md) — full PR and issue triage against [oil.nvim](https://github.com/stevearc/oil.nvim) +[Upstream tracker](doc/upstream.md) — full PR and issue triage against +[oil.nvim](https://github.com/stevearc/oil.nvim) https://user-images.githubusercontent.com/506791/209727111-6b4a11f4-634a-4efa-9461-80e9717cea94.mp4 diff --git a/scripts/ci.sh b/scripts/ci.sh new file mode 100755 index 0000000..3e9356d --- /dev/null +++ b/scripts/ci.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu + +nix develop --command stylua --check lua spec +git ls-files '*.lua' | xargs nix develop --command selene --display-style quiet +nix develop --command prettier --check . +nix develop --command busted From c96dbf8d46056785310843f908c43cc954a39066 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Wed, 4 Mar 2026 14:10:07 -0500 Subject: [PATCH 49/77] Ci/digest final (#69) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci(digest): approve with DIGEST_PAT after disabling require_last_push_approval require_last_push_approval blocked barrettruth from approving their own push. Disabled that restriction in the ruleset — 1 approval is still required for all PRs, but the approver can now be the pusher. DIGEST_PAT (barrettruth) approves, CI runs via PAT push, auto-merge fires when checks pass. * ci: format + scripts * ci: nix --- flake.nix | 5 ++++- scripts/ci.sh | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index aebd6d8..fb5faf0 100644 --- a/flake.nix +++ b/flake.nix @@ -13,9 +13,12 @@ ... }: let - forEachSystem = f: nixpkgs.lib.genAttrs (import systems) (system: f nixpkgs.legacyPackages.${system}); + forEachSystem = + f: nixpkgs.lib.genAttrs (import systems) (system: f nixpkgs.legacyPackages.${system}); in { + formatter = forEachSystem (pkgs: pkgs.nixfmt-tree); + devShells = forEachSystem (pkgs: { default = pkgs.mkShell { packages = [ diff --git a/scripts/ci.sh b/scripts/ci.sh index 3e9356d..7714909 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -4,4 +4,6 @@ set -eu nix develop --command stylua --check lua spec git ls-files '*.lua' | xargs nix develop --command selene --display-style quiet nix develop --command prettier --check . +nix fmt +git diff --exit-code -- '*.nix' nix develop --command busted From 67ad0632a626c61d4d90c1a2601315d46615c584 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Thu, 5 Mar 2026 13:45:12 -0500 Subject: [PATCH 50/77] Remove acknowledgements section from README Removed acknowledgements for canola.nvim and its maintainers. --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 771c6a7..74e8a90 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,4 @@ Drew Neil: ## Acknowledgements -canola.nvim is a fork of [oil.nvim](https://github.com/stevearc/oil.nvim), -created by [Steven Arcangeli](https://github.com/stevearc). Maintained by -[Barrett Ruth](https://github.com/barrettruth). +- [stevearc](https://github.com/stevearc): [oil.nvim](https://github.com/stevearc/oil.nvim) From 0d3088f57ec94b6149f948208162e083b8ef3742 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:50:10 -0500 Subject: [PATCH 51/77] refactor: rename oil to canola across entire codebase (#70) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: the codebase still used the upstream \`oil\` naming everywhere — URL schemes, the \`:Oil\` command, highlight groups, user events, module paths, filetypes, buffer/window variables, LuaCATS type annotations, vimdoc help tags, syntax groups, and internal identifiers. Solution: mechanical rename of every reference. URL schemes now use \`canola://\` (plus \`canola-ssh://\`, \`canola-s3://\`, \`canola-sss://\`, \`canola-trash://\`, \`canola-test://\`). The \`:Canola\` command replaces \`:Oil\`. All highlight groups, user events, augroups, namespaces, filetypes, require paths, type annotations, help tags, and identifiers follow suit. The \`upstream\` remote to \`stevearc/oil.nvim\` has been removed and the \`vim.g.oil\` deprecation shim dropped. --- .github/ISSUE_TEMPLATE/bug_report.yaml | 4 +- README.md | 17 +- doc/canola.txt | 456 +++++++-------- flake.nix | 2 +- lua/{oil => canola}/actions.lua | 128 ++-- lua/{oil => canola}/adapters/files.lua | 44 +- .../adapters/files/permissions.lua | 0 lua/{oil => canola}/adapters/s3.lua | 50 +- lua/{oil => canola}/adapters/s3/s3fs.lua | 16 +- lua/{oil => canola}/adapters/ssh.lua | 60 +- .../adapters/ssh/connection.lua | 26 +- lua/{oil => canola}/adapters/ssh/sshfs.lua | 26 +- lua/{oil => canola}/adapters/test.lua | 18 +- lua/canola/adapters/trash.lua | 9 + .../adapters/trash/freedesktop.lua | 54 +- lua/{oil => canola}/adapters/trash/mac.lua | 22 +- .../adapters/trash/windows.lua | 58 +- .../trash/windows/powershell-connection.lua | 10 +- .../trash/windows/powershell-trash.lua | 10 +- lua/{oil => canola}/cache.lua | 28 +- lua/{oil => canola}/clipboard.lua | 36 +- lua/{oil => canola}/columns.lua | 62 +- lua/{oil => canola}/config.lua | 190 +++--- lua/{oil => canola}/constants.lua | 4 +- lua/{oil => canola}/fs.lua | 10 +- lua/{oil => canola}/git.lua | 4 +- lua/{oil => canola}/init.lua | 551 +++++++++--------- lua/{oil => canola}/keymap_util.lua | 12 +- lua/{oil => canola}/layout.lua | 10 +- lua/{oil => canola}/loading.lua | 2 +- lua/{oil => canola}/log.lua | 8 +- lua/{oil => canola}/lsp/helpers.lua | 10 +- lua/{oil => canola}/lsp/workspace.lua | 2 +- lua/{oil => canola}/mutator/confirmation.lua | 23 +- lua/{oil => canola}/mutator/init.lua | 94 +-- lua/{oil => canola}/mutator/parser.lua | 46 +- lua/{oil => canola}/mutator/progress.lua | 20 +- lua/{oil => canola}/mutator/trie.lua | 20 +- lua/{oil => canola}/pathutil.lua | 0 lua/{oil => canola}/ringbuf.lua | 2 +- lua/{oil => canola}/shell.lua | 0 lua/{oil => canola}/util.lua | 110 ++-- lua/{oil => canola}/view.lua | 154 ++--- lua/oil/adapters/trash.lua | 9 - .../extensions/{oil.lua => canola.lua} | 4 +- perf/bootstrap.lua | 26 +- plugin/canola.lua | 3 + plugin/oil.lua | 3 - spec/altbuf_spec.lua | 96 +-- spec/close_spec.lua | 32 +- spec/config_spec.lua | 16 +- spec/files_spec.lua | 44 +- spec/manual_progress.lua | 4 +- spec/move_rename_spec.lua | 40 +- spec/mutator_spec.lua | 132 ++--- spec/parser_spec.lua | 42 +- spec/path_spec.lua | 2 +- spec/preview_spec.lua | 12 +- spec/regression_spec.lua | 58 +- spec/select_spec.lua | 40 +- spec/test_util.lua | 40 +- spec/tmpdir.lua | 4 +- spec/trash_spec.lua | 6 +- spec/url_spec.lua | 27 +- spec/util_spec.lua | 2 +- spec/win_options_spec.lua | 32 +- syntax/canola.vim | 7 + syntax/canola_preview.vim | 15 + syntax/oil.vim | 7 - syntax/oil_preview.vim | 15 - 70 files changed, 1571 insertions(+), 1555 deletions(-) rename lua/{oil => canola}/actions.lua (80%) rename lua/{oil => canola}/adapters/files.lua (94%) rename lua/{oil => canola}/adapters/files/permissions.lua (100%) rename lua/{oil => canola}/adapters/s3.lua (91%) rename lua/{oil => canola}/adapters/s3/s3fs.lua (91%) rename lua/{oil => canola}/adapters/ssh.lua (91%) rename lua/{oil => canola}/adapters/ssh/connection.lua (94%) rename lua/{oil => canola}/adapters/ssh/sshfs.lua (92%) rename lua/{oil => canola}/adapters/test.lua (83%) create mode 100644 lua/canola/adapters/trash.lua rename lua/{oil => canola}/adapters/trash/freedesktop.lua (95%) rename lua/{oil => canola}/adapters/trash/mac.lua (93%) rename lua/{oil => canola}/adapters/trash/windows.lua (90%) rename lua/{oil => canola}/adapters/trash/windows/powershell-connection.lua (94%) rename lua/{oil => canola}/adapters/trash/windows/powershell-trash.lua (88%) rename lua/{oil => canola}/cache.lua (91%) rename lua/{oil => canola}/clipboard.lua (93%) rename lua/{oil => canola}/columns.lua (82%) rename lua/{oil => canola}/config.lua (70%) rename lua/{oil => canola}/constants.lua (63%) rename lua/{oil => canola}/fs.lua (97%) rename lua/{oil => canola}/git.lua (97%) rename lua/{oil => canola}/init.lua (70%) rename lua/{oil => canola}/keymap_util.lua (94%) rename lua/{oil => canola}/layout.lua (95%) rename lua/{oil => canola}/loading.lua (98%) rename lua/{oil => canola}/log.lua (92%) rename lua/{oil => canola}/lsp/helpers.lua (95%) rename lua/{oil => canola}/lsp/workspace.lua (99%) rename lua/{oil => canola}/mutator/confirmation.lua (91%) rename lua/{oil => canola}/mutator/init.lua (88%) rename lua/{oil => canola}/mutator/parser.lua (90%) rename lua/{oil => canola}/mutator/progress.lua (92%) rename lua/{oil => canola}/mutator/trie.lua (91%) rename lua/{oil => canola}/pathutil.lua (100%) rename lua/{oil => canola}/ringbuf.lua (96%) rename lua/{oil => canola}/shell.lua (100%) rename lua/{oil => canola}/util.lua (91%) rename lua/{oil => canola}/view.lua (88%) delete mode 100644 lua/oil/adapters/trash.lua rename lua/resession/extensions/{oil.lua => canola.lua} (76%) create mode 100644 plugin/canola.lua delete mode 100644 plugin/oil.lua create mode 100644 syntax/canola.vim create mode 100644 syntax/canola_preview.vim delete mode 100644 syntax/oil.vim delete mode 100644 syntax/oil_preview.vim diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 8784517..61ca0f8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -50,7 +50,7 @@ body: - type: textarea attributes: label: 'Health check' - description: 'Output of `:checkhealth oil`' + description: 'Output of `:checkhealth canola`' render: text - type: textarea @@ -71,7 +71,7 @@ body: { 'barrettruth/canola.nvim', init = function() - vim.g.oil = {} + vim.g.canola = {} end, }, }, diff --git a/README.md b/README.md index 74e8a90..b736772 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,9 @@ luarocks install canola.nvim **Q: How do I migrate from `stevearc/oil.nvim`?** -Change the plugin source and replace `setup()` with `vim.g.oil` in `init`. The -configuration table is identical — only the entry point changes. For example, -with [lazy.nvim](https://github.com/folke/lazy.nvim): +Change the plugin source and replace `setup()` with `vim.g.canola` in `init`. +The configuration table is identical — only the entry point changes. For +example, with [lazy.nvim](https://github.com/folke/lazy.nvim): Before (`stevearc/oil.nvim`): @@ -57,7 +57,7 @@ Before (`stevearc/oil.nvim`): 'stevearc/oil.nvim', opts = { ... }, config = function(_, opts) - require('oil').setup(opts) + require('canola').setup(opts) end, } ``` @@ -68,16 +68,16 @@ After (`barrettruth/canola.nvim`): { 'barrettruth/canola.nvim', init = function() - vim.g.oil = { ... } + vim.g.canola = { ... } end, } ``` `init` runs before the plugin loads; `config` runs after. oil.nvim reads -`vim.g.oil` at load time, so `init` is the correct hook. Do not use `config`, +`vim.g.canola` at load time, so `init` is the correct hook. Do not use `config`, `opts`, or `lazy` — oil.nvim loads itself when you open a directory. -**Q: Why "oil"?** +**Q: Why "canola"?** From the [vim-vinegar](https://github.com/tpope/vim-vinegar) README, a quote by Drew Neil: @@ -100,4 +100,5 @@ Drew Neil: ## Acknowledgements -- [stevearc](https://github.com/stevearc): [oil.nvim](https://github.com/stevearc/oil.nvim) +- [stevearc](https://github.com/stevearc): + [oil.nvim](https://github.com/stevearc/oil.nvim) diff --git a/doc/canola.txt b/doc/canola.txt index b861fdb..2553b66 100644 --- a/doc/canola.txt +++ b/doc/canola.txt @@ -1,38 +1,38 @@ *canola.txt* -*Canola* *canola* *canola.nvim* *Oil* *oil* *oil.nvim* +*Canola* *canola* *canola.nvim* -------------------------------------------------------------------------------- -CONTENTS *oil-contents* +CONTENTS *canola-contents* - 1. Introduction |oil-introduction| - 2. Requirements |oil-requirements| - 3. Config |oil-config| - 4. Options |oil-options| - 5. Api |oil-api| - 6. Columns |oil-columns| - 7. Actions |oil-actions| - 8. Highlights |oil-highlights| - 9. Adapters |oil-adapters| - 10. Recipes |oil-recipes| - 11. Events |oil-events| - 12. Trash |oil-trash| + 1. Introduction |canola-introduction| + 2. Requirements |canola-requirements| + 3. Config |canola-config| + 4. Options |canola-options| + 5. Api |canola-api| + 6. Columns |canola-columns| + 7. Actions |canola-actions| + 8. Highlights |canola-highlights| + 9. Adapters |canola-adapters| + 10. Recipes |canola-recipes| + 11. Events |canola-events| + 12. Trash |canola-trash| -------------------------------------------------------------------------------- -INTRODUCTION *oil-introduction* +INTRODUCTION *canola-introduction* -oil.nvim is a file explorer for Neovim in the style of vim-vinegar. It lets +canola.nvim is a file explorer for Neovim in the style of vim-vinegar. It lets you edit your filesystem like a normal buffer: create files and directories by typing new lines, delete them by removing lines, rename or move them by -changing the text. When you save the buffer, oil diffs it against the original +changing the text. When you save the buffer, canola diffs it against the original listing and performs the corresponding filesystem operations. -Open a directory with `nvim .`, `:edit `, or `:Oil `. Use `` +Open a directory with `nvim .`, `:edit `, or `:Canola `. Use `` to open a file or descend into a directory, and `-` to go up. Treat the listing like any other buffer — edit freely, then `:w` to apply changes. -To open oil in a floating window, use `:Oil --float `. +To open canola in a floating window, use `:Canola --float `. To mimic vim-vinegar's parent-directory keymap: >lua - vim.keymap.set("n", "-", "Oil", { desc = "Open parent directory" }) + vim.keymap.set("n", "-", "Canola", { desc = "Open parent directory" }) < File operations work across adapters. You can copy files between your local @@ -40,54 +40,54 @@ machine and a remote server over SSH, or between local directories and S3 buckets, using the same buffer-editing workflow. -------------------------------------------------------------------------------- -REQUIREMENTS *oil-requirements* +REQUIREMENTS *canola-requirements* - Neovim 0.8+ - (optional) mini.icons or nvim-web-devicons for file icons -------------------------------------------------------------------------------- -CONFIG *oil-config* +CONFIG *canola-config* -Oil can be configured in two ways: +Canola can be configured in two ways: 1. The traditional `setup()` call: >lua - require("oil").setup({ + require("canola").setup({ -- your opts here }) < -2. Declarative configuration via `vim.g.oil`, which does not require calling +2. Declarative configuration via `vim.g.canola`, which does not require calling `setup()`: >lua - vim.g.oil = { + vim.g.canola = { -- your opts here } < - When `vim.g.oil` is set, oil initializes automatically during plugin + When `vim.g.canola` is set, canola initializes automatically during plugin loading. If `setup()` is called with explicit opts, those take precedence - over `vim.g.oil`. + over `vim.g.canola`. The full list of options with their defaults: >lua - require("oil").setup({ - -- Oil will take over directory buffers (e.g. `vim .` or `:e src/`) + require("canola").setup({ + -- Canola will take over directory buffers (e.g. `vim .` or `:e src/`) -- Set to false if you want some other plugin (e.g. netrw) to open when you edit directories. default_file_explorer = true, -- Id is automatically added at the beginning, and name at the end - -- See :help oil-columns + -- See :help canola-columns columns = { "icon", -- "permissions", -- "size", -- "mtime", }, - -- Buffer-local options to use for oil buffers + -- Buffer-local options to use for canola buffers buf_options = { buflisted = false, bufhidden = "hide", }, - -- Window-local options to use for oil buffers + -- Window-local options to use for canola buffers win_options = { wrap = false, signcolumn = "no", @@ -98,16 +98,16 @@ The full list of options with their defaults: conceallevel = 3, concealcursor = "nvic", }, - -- Send deleted files to the trash instead of permanently deleting them (:help oil-trash) + -- Send deleted files to the trash instead of permanently deleting them (:help canola-trash) delete_to_trash = false, - -- Skip the confirmation popup for simple operations (:help oil.skip_confirm_for_simple_edits) + -- Skip the confirmation popup for simple operations (:help canola.skip_confirm_for_simple_edits) skip_confirm_for_simple_edits = false, -- Selecting a new/moved/renamed file or directory will prompt you to save changes first -- (:help prompt_save_on_select_new_entry) prompt_save_on_select_new_entry = true, - -- Oil will automatically delete hidden buffers after this delay + -- Canola will automatically delete hidden buffers after this delay -- You can set the delay to false to disable cleanup entirely - -- Note that the cleanup process only starts when none of the oil buffers are currently displayed + -- Note that the cleanup process only starts when none of the canola buffers are currently displayed cleanup_delay_ms = 2000, lsp_file_methods = { -- Enable or disable LSP file operations @@ -118,17 +118,17 @@ The full list of options with their defaults: -- Set to "unmodified" to only save unmodified buffers autosave_changes = false, }, - -- Constrain the cursor to the editable parts of the oil buffer + -- Constrain the cursor to the editable parts of the canola buffer -- Set to `false` to disable, or "name" to keep it on the file names constrain_cursor = "editable", - -- Set to true to watch the filesystem for changes and reload oil + -- Set to true to watch the filesystem for changes and reload canola watch_for_changes = false, - -- Keymaps in oil buffer. Can be any value that `vim.keymap.set` accepts OR a table of keymap + -- Keymaps in canola buffer. Can be any value that `vim.keymap.set` accepts OR a table of keymap -- options with a `callback` (e.g. { callback = function() ... end, desc = "", mode = "n" }) -- Additionally, if it is a string that matches "actions.", - -- it will use the mapping at require("oil.actions"). + -- it will use the mapping at require("canola.actions"). -- Set to `false` to remove a keymap - -- See :help oil-actions for a list of all available actions + -- See :help canola-actions for a list of all available actions keymaps = { ["g?"] = { "actions.show_help", mode = "n" }, [""] = "actions.select", @@ -168,7 +168,7 @@ The full list of options with their defaults: case_insensitive = false, sort = { -- sort order can be "asc" or "desc" - -- see :help oil-columns to see which columns are sortable + -- see :help canola-columns to see which columns are sortable { "type", "asc" }, { "name", "asc" }, }, @@ -196,7 +196,7 @@ The full list of options with their defaults: return false end, }, - -- Configuration for the floating window in oil.open_float + -- Configuration for the floating window in canola.open_float float = { -- Padding around the floating window padding = 2, @@ -207,7 +207,7 @@ The full list of options with their defaults: win_options = { winblend = 0, }, - -- optionally override the oil buffers window title with custom function: fun(winid: integer): string + -- optionally override the canola buffers window title with custom function: fun(winid: integer): string get_win_title = nil, -- preview_split: Split direction: "auto", "left", "right", "above", "below". preview_split = "auto", @@ -279,12 +279,12 @@ The full list of options with their defaults: < -------------------------------------------------------------------------------- -OPTIONS *oil-options* +OPTIONS *canola-options* -skip_confirm_for_simple_edits *oil.skip_confirm_for_simple_edits* +skip_confirm_for_simple_edits *canola.skip_confirm_for_simple_edits* type: `boolean` default: `false` - Before performing filesystem operations, Oil displays a confirmation popup to ensure + Before performing filesystem operations, Canola displays a confirmation popup to ensure that all operations are intentional. When this option is `true`, the popup will be skipped if the operations: * contain no deletes @@ -292,7 +292,7 @@ skip_confirm_for_simple_edits *oil.skip_confirm_for_simple_edit * contain at most one copy or move * contain at most five creates -prompt_save_on_select_new_entry *oil.prompt_save_on_select_new_entry* +prompt_save_on_select_new_entry *canola.prompt_save_on_select_new_entry* type: `boolean` default: `true` There are two cases where this option is relevant: 1. You copy a file to a new location, then you select it and make edits before @@ -301,126 +301,126 @@ prompt_save_on_select_new_entry *oil.prompt_save_on_select_new_entr changes before saving. In case 1, when you edit the file you are actually editing the original file because - oil has not yet moved/copied it to its new location. This means that the original + canola has not yet moved/copied it to its new location. This means that the original file will, perhaps unexpectedly, also be changed by any edits you make. Case 2 is similar; when you edit the directory you are again actually editing the original location of the directory. If you add new files, those files will be created in both the original location and the copied directory. - When this option is `true`, Oil will prompt you to save before entering a file or - directory that is pending within oil, but does not exist on disk. + When this option is `true`, Canola will prompt you to save before entering a file or + directory that is pending within canola, but does not exist on disk. -------------------------------------------------------------------------------- -API *oil-api* +API *canola-api* -get_entry_on_line({bufnr}, {lnum}): nil|oil.Entry *oil.get_entry_on_line* +get_entry_on_line({bufnr}, {lnum}): nil|canola.Entry *canola.get_entry_on_line* Get the entry on a specific line (1-indexed) Parameters: {bufnr} `integer` {lnum} `integer` -get_cursor_entry(): nil|oil.Entry *oil.get_cursor_entry* +get_cursor_entry(): nil|canola.Entry *canola.get_cursor_entry* Get the entry currently under the cursor -discard_all_changes() *oil.discard_all_changes* - Discard all changes made to oil buffers +discard_all_changes() *canola.discard_all_changes* + Discard all changes made to canola buffers -set_columns({cols}) *oil.set_columns* - Change the display columns for oil +set_columns({cols}) *canola.set_columns* + Change the display columns for canola Parameters: - {cols} `oil.ColumnSpec[]` + {cols} `canola.ColumnSpec[]` -set_sort({sort}) *oil.set_sort* - Change the sort order for oil +set_sort({sort}) *canola.set_sort* + Change the sort order for canola Parameters: - {sort} `oil.SortSpec[]` List of columns plus direction. See :help oil- + {sort} `canola.SortSpec[]` List of columns plus direction. See :help canola- columns to see which ones are sortable. Examples: >lua - require("oil").set_sort({ { "type", "asc" }, { "size", "desc" } }) + require("canola").set_sort({ { "type", "asc" }, { "size", "desc" } }) < -set_is_hidden_file({is_hidden_file}) *oil.set_is_hidden_file* - Change how oil determines if the file is hidden +set_is_hidden_file({is_hidden_file}) *canola.set_is_hidden_file* + Change how canola determines if the file is hidden Parameters: - {is_hidden_file} `fun(filename: string, bufnr: integer, entry: oil.Entry): boolean` + {is_hidden_file} `fun(filename: string, bufnr: integer, entry: canola.Entry): boolean` Return true if the file/dir should be hidden -toggle_hidden() *oil.toggle_hidden* +toggle_hidden() *canola.toggle_hidden* Toggle hidden files and directories -get_current_dir({bufnr}): nil|string *oil.get_current_dir* +get_current_dir({bufnr}): nil|string *canola.get_current_dir* Get the current directory Parameters: {bufnr} `nil|integer` -open_float({dir}, {opts}, {cb}) *oil.open_float* - Open oil browser in a floating window +open_float({dir}, {opts}, {cb}) *canola.open_float* + Open canola browser in a floating window Parameters: {dir} `nil|string` When nil, open the parent of the current buffer, or the cwd if current buffer is not a file - {opts} `nil|oil.OpenOpts` - {preview} `nil|oil.OpenPreviewOpts` When present, open the preview - window after opening oil + {opts} `nil|canola.OpenOpts` + {preview} `nil|canola.OpenPreviewOpts` When present, open the preview + window after opening canola {vertical} `nil|boolean` Open the buffer in a vertical split {horizontal} `nil|boolean` Open the buffer in a horizontal split {split} `nil|"aboveleft"|"belowright"|"topleft"|"botright"` S plit modifier - {cb} `nil|fun()` Called after the oil buffer is ready + {cb} `nil|fun()` Called after the canola buffer is ready -toggle_float({dir}, {opts}, {cb}) *oil.toggle_float* - Open oil browser in a floating window, or close it if open +toggle_float({dir}, {opts}, {cb}) *canola.toggle_float* + Open canola browser in a floating window, or close it if open Parameters: {dir} `nil|string` When nil, open the parent of the current buffer, or the cwd if current buffer is not a file - {opts} `nil|oil.OpenOpts` - {preview} `nil|oil.OpenPreviewOpts` When present, open the preview - window after opening oil + {opts} `nil|canola.OpenOpts` + {preview} `nil|canola.OpenPreviewOpts` When present, open the preview + window after opening canola {vertical} `nil|boolean` Open the buffer in a vertical split {horizontal} `nil|boolean` Open the buffer in a horizontal split {split} `nil|"aboveleft"|"belowright"|"topleft"|"botright"` S plit modifier - {cb} `nil|fun()` Called after the oil buffer is ready + {cb} `nil|fun()` Called after the canola buffer is ready -open({dir}, {opts}, {cb}) *oil.open* - Open oil browser for a directory +open({dir}, {opts}, {cb}) *canola.open* + Open canola browser for a directory Parameters: {dir} `nil|string` When nil, open the parent of the current buffer, or the cwd if current buffer is not a file - {opts} `nil|oil.OpenOpts` - {preview} `nil|oil.OpenPreviewOpts` When present, open the preview - window after opening oil + {opts} `nil|canola.OpenOpts` + {preview} `nil|canola.OpenPreviewOpts` When present, open the preview + window after opening canola {vertical} `nil|boolean` Open the buffer in a vertical split {horizontal} `nil|boolean` Open the buffer in a horizontal split {split} `nil|"aboveleft"|"belowright"|"topleft"|"botright"` S plit modifier - {cb} `nil|fun()` Called after the oil buffer is ready + {cb} `nil|fun()` Called after the canola buffer is ready -close({opts}) *oil.close* - Restore the buffer that was present when oil was opened +close({opts}) *canola.close* + Restore the buffer that was present when canola was opened Parameters: - {opts} `nil|oil.CloseOpts` - {exit_if_last_buf} `nil|boolean` Exit vim if this oil buffer is the + {opts} `nil|canola.CloseOpts` + {exit_if_last_buf} `nil|boolean` Exit vim if this canola buffer is the last open buffer -open_preview({opts}, {callback}) *oil.open_preview* +open_preview({opts}, {callback}) *canola.open_preview* Preview the entry under the cursor in a split Parameters: - {opts} `nil|oil.OpenPreviewOpts` + {opts} `nil|canola.OpenPreviewOpts` {vertical} `nil|boolean` Open the buffer in a vertical split {horizontal} `nil|boolean` Open the buffer in a horizontal split {split} `nil|"aboveleft"|"belowright"|"topleft"|"botright"` Split @@ -428,17 +428,17 @@ open_preview({opts}, {callback}) *oil.open_previe {callback} `nil|fun(err: nil|string)` Called once the preview window has been opened -select({opts}, {callback}) *oil.select* +select({opts}, {callback}) *canola.select* Select the entry under the cursor Parameters: - {opts} `nil|oil.SelectOpts` + {opts} `nil|canola.SelectOpts` {vertical} `nil|boolean` Open the buffer in a vertical split {horizontal} `nil|boolean` Open the buffer in a horizontal split {split} `nil|"aboveleft"|"belowright"|"topleft"|"botright"` Split modifier {tab} `nil|boolean` Open the buffer in a new tab - {close} `nil|boolean` Close the original oil buffer once + {close} `nil|boolean` Close the original canola buffer once selection is made {handle_buffer_callback} `nil|fun(buf_id: integer)` If defined, all other buffer related options here would be ignored. This @@ -447,7 +447,7 @@ select({opts}, {callback}) *oil.selec {callback} `nil|fun(err: nil|string)` Called once all entries have been opened -save({opts}, {cb}) *oil.save* +save({opts}, {cb}) *canola.save* Save all changes Parameters: @@ -459,14 +459,14 @@ save({opts}, {cb}) *oil.sav Note: If you provide your own callback function, there will be no notification for errors. -setup({opts}) *oil.setup* - Initialize oil +setup({opts}) *canola.setup* + Initialize canola Parameters: - {opts} `oil.setupOpts|nil` + {opts} `canola.setupOpts|nil` -------------------------------------------------------------------------------- -COLUMNS *oil-columns* +COLUMNS *canola-columns* Columns can be specified as a string to use default arguments (e.g. `"icon"`), or as a table to pass parameters (e.g. `{"size", highlight = "Special"}`) @@ -563,23 +563,23 @@ birthtime *column-birthtim {format} `string` Format string (see :help strftime) -------------------------------------------------------------------------------- -ACTIONS *oil-actions* +ACTIONS *canola-actions* -The `keymaps` option in `oil.setup` allow you to create mappings using all the same parameters as |vim.keymap.set|. +The `keymaps` option in `canola.setup` allow you to create mappings using all the same parameters as |vim.keymap.set|. >lua keymaps = { -- Mappings can be a string ["~"] = "edit $HOME", -- Mappings can be a function ["gd"] = function() - require("oil").set_columns({ "icon", "permissions", "size", "mtime" }) + require("canola").set_columns({ "icon", "permissions", "size", "mtime" }) end, -- You can pass additional opts to vim.keymap.set by using -- a table with the mapping as the first element. ["ff"] = { function() require("telescope.builtin").find_files({ - cwd = require("oil").get_current_dir() + cwd = require("canola").get_current_dir() }) end, mode = "n", @@ -603,10 +603,10 @@ The `keymaps` option in `oil.setup` allow you to create mappings using all the s Below are the actions that can be used in the `keymaps` section of config options. You can refer to them as strings (e.g. "actions.") or you can use the functions directly with -`require("oil.actions").action_name.callback()` +`require("canola.actions").action_name.callback()` cd *actions.cd* - :cd to the current oil directory + :cd to the current canola directory Parameters: {scope} `nil|"tab"|"win"` Scope of the directory change (e.g. use |:tcd| @@ -617,20 +617,20 @@ change_sort *actions.change_sor Change the sort order Parameters: - {sort} `oil.SortSpec[]` List of columns plus direction (see - |oil.set_sort|) instead of interactive selection + {sort} `canola.SortSpec[]` List of columns plus direction (see + |canola.set_sort|) instead of interactive selection close *actions.close* - Close oil and restore original buffer + Close canola and restore original buffer Parameters: - {exit_if_last_buf} `boolean` Exit vim if oil is closed as the last buffer + {exit_if_last_buf} `boolean` Exit vim if canola is closed as the last buffer close_float *actions.close_float* - Close oil if the window is floating, otherwise do nothing + Close canola if the window is floating, otherwise do nothing Parameters: - {exit_if_last_buf} `boolean` Exit vim if oil is closed as the last buffer + {exit_if_last_buf} `boolean` Exit vim if canola is closed as the last buffer copy_to_system_clipboard *actions.copy_to_system_clipboard* Copy the entry under the cursor to the system clipboard @@ -644,7 +644,7 @@ open_cmdline *actions.open_cmdlin {shorten_path} `boolean` Use relative paths when possible open_cwd *actions.open_cwd* - Open oil in Neovim's current working directory + Open canola in Neovim's current working directory open_external *actions.open_external* Open the entry under the cursor in an external program @@ -656,7 +656,7 @@ parent *actions.paren Navigate to the parent path paste_from_system_clipboard *actions.paste_from_system_clipboard* - Paste the system clipboard into the current oil directory + Paste the system clipboard into the current canola directory Parameters: {delete_original} `boolean` Delete the original file after copying @@ -694,7 +694,7 @@ select *actions.selec Open the entry under the cursor Parameters: - {close} `boolean` Close the original oil buffer once selection is + {close} `boolean` Close the original canola buffer once selection is made {horizontal} `boolean` Open the buffer in a horizontal split {split} `"aboveleft"|"belowright"|"topleft"|"botright"` Split @@ -703,7 +703,7 @@ select *actions.selec {vertical} `boolean` Open the buffer in a vertical split send_to_qflist *actions.send_to_qflist* - Sends files in the current oil directory to the quickfix list, replacing the + Sends files in the current canola directory to the quickfix list, replacing the previous entries. Parameters: @@ -731,109 +731,109 @@ yank_entry *actions.yank_entr mods argument -------------------------------------------------------------------------------- -HIGHLIGHTS *oil-highlights* +HIGHLIGHTS *canola-highlights* -OilEmpty *hl-OilEmpty* +CanolaEmpty *hl-CanolaEmpty* Empty column values -OilHidden *hl-OilHidden* - Hidden entry in an oil buffer +CanolaHidden *hl-CanolaHidden* + Hidden entry in an canola buffer -OilDir *hl-OilDir* - Directory names in an oil buffer +CanolaDir *hl-CanolaDir* + Directory names in an canola buffer -OilDirHidden *hl-OilDirHidden* - Hidden directory names in an oil buffer +CanolaDirHidden *hl-CanolaDirHidden* + Hidden directory names in an canola buffer -OilDirIcon *hl-OilDirIcon* +CanolaDirIcon *hl-CanolaDirIcon* Icon for directories -OilFileIcon *hl-OilFileIcon* +CanolaFileIcon *hl-CanolaFileIcon* Icon for files -OilSocket *hl-OilSocket* - Socket files in an oil buffer +CanolaSocket *hl-CanolaSocket* + Socket files in an canola buffer -OilSocketHidden *hl-OilSocketHidden* - Hidden socket files in an oil buffer +CanolaSocketHidden *hl-CanolaSocketHidden* + Hidden socket files in an canola buffer -OilLink *hl-OilLink* - Soft links in an oil buffer +CanolaLink *hl-CanolaLink* + Soft links in an canola buffer -OilOrphanLink *hl-OilOrphanLink* - Orphaned soft links in an oil buffer +CanolaOrphanLink *hl-CanolaOrphanLink* + Orphaned soft links in an canola buffer -OilLinkHidden *hl-OilLinkHidden* - Hidden soft links in an oil buffer +CanolaLinkHidden *hl-CanolaLinkHidden* + Hidden soft links in an canola buffer -OilOrphanLinkHidden *hl-OilOrphanLinkHidden* - Hidden orphaned soft links in an oil buffer +CanolaOrphanLinkHidden *hl-CanolaOrphanLinkHidden* + Hidden orphaned soft links in an canola buffer -OilLinkTarget *hl-OilLinkTarget* +CanolaLinkTarget *hl-CanolaLinkTarget* The target of a soft link -OilOrphanLinkTarget *hl-OilOrphanLinkTarget* +CanolaOrphanLinkTarget *hl-CanolaOrphanLinkTarget* The target of an orphaned soft link -OilLinkTargetHidden *hl-OilLinkTargetHidden* +CanolaLinkTargetHidden *hl-CanolaLinkTargetHidden* The target of a hidden soft link -OilOrphanLinkTargetHidden *hl-OilOrphanLinkTargetHidden* +CanolaOrphanLinkTargetHidden *hl-CanolaOrphanLinkTargetHidden* The target of an hidden orphaned soft link -OilFile *hl-OilFile* - Normal files in an oil buffer +CanolaFile *hl-CanolaFile* + Normal files in an canola buffer -OilFileHidden *hl-OilFileHidden* - Hidden normal files in an oil buffer +CanolaFileHidden *hl-CanolaFileHidden* + Hidden normal files in an canola buffer -OilExecutable *hl-OilExecutable* - Executable files in an oil buffer +CanolaExecutable *hl-CanolaExecutable* + Executable files in an canola buffer -OilExecutableHidden *hl-OilExecutableHidden* - Hidden executable files in an oil buffer +CanolaExecutableHidden *hl-CanolaExecutableHidden* + Hidden executable files in an canola buffer -OilCreate *hl-OilCreate* - Create action in the oil preview window +CanolaCreate *hl-CanolaCreate* + Create action in the canola preview window -OilDelete *hl-OilDelete* - Delete action in the oil preview window +CanolaDelete *hl-CanolaDelete* + Delete action in the canola preview window -OilMove *hl-OilMove* - Move action in the oil preview window +CanolaMove *hl-CanolaMove* + Move action in the canola preview window -OilCopy *hl-OilCopy* - Copy action in the oil preview window +CanolaCopy *hl-CanolaCopy* + Copy action in the canola preview window -OilChange *hl-OilChange* - Change action in the oil preview window +CanolaChange *hl-CanolaChange* + Change action in the canola preview window -OilRestore *hl-OilRestore* - Restore (from the trash) action in the oil preview window +CanolaRestore *hl-CanolaRestore* + Restore (from the trash) action in the canola preview window -OilPurge *hl-OilPurge* - Purge (Permanently delete a file from trash) action in the oil preview +CanolaPurge *hl-CanolaPurge* + Purge (Permanently delete a file from trash) action in the canola preview window -OilTrash *hl-OilTrash* - Trash (delete a file to trash) action in the oil preview window +CanolaTrash *hl-CanolaTrash* + Trash (delete a file to trash) action in the canola preview window -OilTrashSourcePath *hl-OilTrashSourcePath* +CanolaTrashSourcePath *hl-CanolaTrashSourcePath* Virtual text that shows the original path of file in the trash -------------------------------------------------------------------------------- -ADAPTERS *oil-adapters* +ADAPTERS *canola-adapters* -Oil performs all filesystem interaction through an adapter abstraction. This -means oil can view and modify files in places beyond the local filesystem, as +Canola performs all filesystem interaction through an adapter abstraction. This +means canola can view and modify files in places beyond the local filesystem, as long as the destination has an adapter implementation. File operations work across adapters — you can copy files between local and remote with the same buffer-editing workflow. -SSH *oil-adapter-ssh* +SSH *canola-adapter-ssh* Browse files over SSH, much like netrw. Open a buffer with: > - nvim oil-ssh://[username@]hostname[:port]/[path] + nvim canola-ssh://[username@]hostname[:port]/[path] < This is the same URL format that netrw uses. @@ -841,36 +841,36 @@ SSH *oil-adapter-ss server to have `/bin/sh` as well as standard unix commands (`ls`, `rm`, `mv`, `mkdir`, `chmod`, `cp`, `touch`, `ln`, `echo`). -S3 *oil-adapter-s3* +S3 *canola-adapter-s3* Browse files stored in AWS S3. Make sure `aws` is configured correctly, then open a buffer with: > - nvim oil-s3://[bucket]/[path] + nvim canola-s3://[bucket]/[path] < Older versions of Neovim (0.11 and earlier) don't support numbers in the - URL scheme, so use `oil-sss` instead of `oil-s3`. + URL scheme, so use `canola-sss` instead of `canola-s3`. -Trash *oil-adapter-trash* +Trash *canola-adapter-trash* - See |oil-trash| for details on the built-in trash adapter. + See |canola-trash| for details on the built-in trash adapter. -------------------------------------------------------------------------------- -RECIPES *oil-recipes* +RECIPES *canola-recipes* Toggle file detail view ~ - *oil-recipe-toggle-detail-view* + *canola-recipe-toggle-detail-view* >lua local detail = false - require("oil").setup({ + require("canola").setup({ keymaps = { ["gd"] = { desc = "Toggle file detail view", callback = function() detail = not detail if detail then - require("oil").set_columns({ "icon", "permissions", "size", "mtime" }) + require("canola").set_columns({ "icon", "permissions", "size", "mtime" }) else - require("oil").set_columns({ "icon" }) + require("canola").set_columns({ "icon" }) end end, }, @@ -879,11 +879,11 @@ Toggle file detail view ~ < Show CWD in the winbar ~ - *oil-recipe-cwd-winbar* + *canola-recipe-cwd-winbar* >lua - function _G.get_oil_winbar() + function _G.get_canola_winbar() local bufnr = vim.api.nvim_win_get_buf(vim.g.statusline_winid) - local dir = require("oil").get_current_dir(bufnr) + local dir = require("canola").get_current_dir(bufnr) if dir then return vim.fn.fnamemodify(dir, ":~") else @@ -891,15 +891,15 @@ Show CWD in the winbar ~ end end - require("oil").setup({ + require("canola").setup({ win_options = { - winbar = "%!v:lua.get_oil_winbar()", + winbar = "%!v:lua.get_canola_winbar()", }, }) < Hide gitignored files and show git tracked hidden files ~ - *oil-recipe-git-is-hidden* + *canola-recipe-git-is-hidden* >lua local function parse_output(proc) local result = proc:wait() @@ -939,17 +939,17 @@ Hide gitignored files and show git tracked hidden files ~ end local git_status = new_git_status() - local refresh = require("oil.actions").refresh + local refresh = require("canola.actions").refresh local orig_refresh = refresh.callback refresh.callback = function(...) git_status = new_git_status() orig_refresh(...) end - require("oil").setup({ + require("canola").setup({ view_options = { is_hidden_file = function(name, bufnr) - local dir = require("oil").get_current_dir(bufnr) + local dir = require("canola").get_current_dir(bufnr) local is_dotfile = vim.startswith(name, ".") and name ~= ".." if not dir then return is_dotfile @@ -964,21 +964,21 @@ Hide gitignored files and show git tracked hidden files ~ }) < -Open Telescope file finder in the current oil directory ~ - *oil-recipe-telescope* +Open Telescope file finder in the current canola directory ~ + *canola-recipe-telescope* When using `get_current_dir()` in a keymap that also opens another plugin's UI (like Telescope), capture the directory in a local variable before the call that changes the buffer context. >lua - require("oil").setup({ + require("canola").setup({ keymaps = { ["ff"] = { desc = "Find files in the current directory", callback = function() - local dir = require("oil").get_current_dir() + local dir = require("canola").get_current_dir() if not dir then - vim.notify("Could not get oil directory", vim.log.levels.WARN) + vim.notify("Could not get canola directory", vim.log.levels.WARN) return end require("telescope.builtin").find_files({ cwd = dir }) @@ -987,9 +987,9 @@ that changes the buffer context. ["fg"] = { desc = "Live grep in the current directory", callback = function() - local dir = require("oil").get_current_dir() + local dir = require("canola").get_current_dir() if not dir then - vim.notify("Could not get oil directory", vim.log.levels.WARN) + vim.notify("Could not get canola directory", vim.log.levels.WARN) return end require("telescope.builtin").live_grep({ cwd = dir }) @@ -1003,18 +1003,18 @@ If you need the directory after an operation that might change the current buffer, pass the buffer number explicitly: >lua local bufnr = vim.api.nvim_get_current_buf() -- ... some operation that changes the current buffer ... - local dir = require("oil").get_current_dir(bufnr) + local dir = require("canola").get_current_dir(bufnr) < Add custom column for file extension ~ - *oil-recipe-extension-column* + *canola-recipe-extension-column* >lua - local oil_cfg = require "oil.config" - local oil_constant = require "oil.constants" - local oil_column = require "oil.columns" + local canola_cfg = require "canola.config" + local canola_constant = require "canola.constants" + local canola_column = require "canola.columns" - local FIELD_TYPE = oil_constant.FIELD_TYPE - local FIELD_NAME = oil_constant.FIELD_NAME + local FIELD_TYPE = canola_constant.FIELD_TYPE + local FIELD_NAME = canola_constant.FIELD_NAME local function adjust_number(int) return string.format("%03d%s", #int, int) @@ -1024,7 +1024,7 @@ Add custom column for file extension ~ return vim.fn.fnamemodify(output, ":e") end - oil_column.register("extension", { + canola_column.register("extension", { render = function(entry, _) local field_type = entry[FIELD_TYPE] local name = entry[FIELD_NAME] @@ -1044,8 +1044,8 @@ Add custom column for file extension ~ end, create_sort_value_factory = function(num_entries) if - oil_cfg.view_options.natural_order == false - or (oil_cfg.view_options.natural_order == "fast" and num_entries > 5000) + canola_cfg.view_options.natural_order == false + or (canola_cfg.view_options.natural_order == "fast" and num_entries > 5000) then return function(entry) return format(entry[FIELD_NAME]:lower()) @@ -1066,7 +1066,7 @@ Add custom column for file extension ~ end, }) - require("oil").setup({ + require("canola").setup({ columns = { "size", "extension", @@ -1083,15 +1083,15 @@ Add custom column for file extension ~ < Disable dimming of hidden files ~ - *oil-recipe-no-hidden-dimming* + *canola-recipe-no-hidden-dimming* -By default, hidden files (toggled with `g.`) are dimmed via the `OilHidden` +By default, hidden files (toggled with `g.`) are dimmed via the `CanolaHidden` highlight group, which links to `Comment`. To make hidden files look identical to their visible counterparts, relink each hidden group to its non-hidden variant after calling `setup()`: >lua - for _, hl in ipairs(require("oil")._get_highlights()) do - local base = hl.name:match("^(Oil.+)Hidden$") + for _, hl in ipairs(require("canola")._get_highlights()) do + local base = hl.name:match("^(Canola.+)Hidden$") if base then vim.api.nvim_set_hl(0, hl.name, { link = base }) end @@ -1099,62 +1099,62 @@ variant after calling `setup()`: < -------------------------------------------------------------------------------- -EVENTS *oil-events* +EVENTS *canola-events* -Oil emits the following |User| autocmd events. Listen for them with +Canola emits the following |User| autocmd events. Listen for them with |nvim_create_autocmd|: >lua vim.api.nvim_create_autocmd("User", { - pattern = "OilEnter", + pattern = "CanolaEnter", callback = function(args) - vim.print("Entered oil buffer: " .. args.data.buf) + vim.print("Entered canola buffer: " .. args.data.buf) end, }) < -OilEnter *OilEnter* - Fired once per oil buffer, after the initial directory listing has been +CanolaEnter *CanolaEnter* + Fired once per canola buffer, after the initial directory listing has been rendered and the buffer is ready. The `args.data.buf` field contains the buffer number. Use this event for one-time buffer setup such as setting keymaps or window options. -OilReadPost *OilReadPost* +CanolaReadPost *CanolaReadPost* Fired after every successful buffer render, including the initial render and all subsequent re-renders (e.g. after directory changes, refreshes, or mutations). The `args.data.buf` field contains the buffer number. Use this event for logic that must run each time the directory listing updates. -OilMutationComplete *OilMutationComplete* +CanolaMutationComplete *CanolaMutationComplete* Fired after all pending mutations (create, delete, rename, move, copy) have been executed and the affected buffers have been re-rendered. No additional data fields. Use this event for post-mutation side effects such as refreshing external status indicators. -------------------------------------------------------------------------------- -TRASH *oil-trash* +TRASH *canola-trash* -Oil has built-in support for using the system trash. When +Canola has built-in support for using the system trash. When `delete_to_trash = true`, any deleted files will be sent to the trash instead of being permanently deleted. You can browse the trash for a directory using the `toggle_trash` action (bound to `g\` by default). You can view all files -in the trash with `:Oil --trash /`. +in the trash with `:Canola --trash /`. To restore files, simply move them from the trash to the desired destination, the same as any other file operation. If you delete files from the trash they will be permanently deleted (purged). Linux: - Oil supports the FreeDesktop trash specification. + Canola supports the FreeDesktop trash specification. https://specifications.freedesktop.org/trash/1.0/ All features should work. Mac: - Oil has limited support for MacOS due to the proprietary nature of the + Canola has limited support for MacOS due to the proprietary nature of the implementation. The trash bin can only be viewed as a single dir (instead of being able to see files that were trashed from a directory). Windows: - Oil supports the Windows Recycle Bin. All features should work. + Canola supports the Windows Recycle Bin. All features should work. ================================================================================ vim:tw=80:ts=2:ft=help:norl:syntax=help: diff --git a/flake.nix b/flake.nix index fb5faf0..76ef696 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "oil.nvim — Neovim file explorer: edit your filesystem like a buffer"; + description = "canola.nvim — refined fork of oil.nvim"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; diff --git a/lua/oil/actions.lua b/lua/canola/actions.lua similarity index 80% rename from lua/oil/actions.lua rename to lua/canola/actions.lua index 143a454..b3d7942 100644 --- a/lua/oil/actions.lua +++ b/lua/canola/actions.lua @@ -1,12 +1,12 @@ -local oil = require('oil') -local util = require('oil.util') +local canola = require('canola') +local util = require('canola.util') local M = {} M.show_help = { callback = function() - local config = require('oil.config') - require('oil.keymap_util').show_help(config.keymaps) + local config = require('canola.config') + require('canola.keymap_util').show_help(config.keymaps) end, desc = 'Show default keymaps', } @@ -17,7 +17,7 @@ M.select = { opts = opts or {} local callback = opts.callback opts.callback = nil - oil.select(opts, callback) + canola.select(opts, callback) end, parameters = { vertical = { @@ -38,7 +38,7 @@ M.select = { }, close = { type = 'boolean', - desc = 'Close the original oil buffer once selection is made', + desc = 'Close the original canola buffer once selection is made', }, }, } @@ -47,7 +47,7 @@ M.select_vsplit = { desc = 'Open the entry under the cursor in a vertical split', deprecated = true, callback = function() - oil.select({ vertical = true }) + canola.select({ vertical = true }) end, } @@ -55,7 +55,7 @@ M.select_split = { desc = 'Open the entry under the cursor in a horizontal split', deprecated = true, callback = function() - oil.select({ horizontal = true }) + canola.select({ horizontal = true }) end, } @@ -63,7 +63,7 @@ M.select_tab = { desc = 'Open the entry under the cursor in a new tab', deprecated = true, callback = function() - oil.select({ tab = true }) + canola.select({ tab = true }) end, } @@ -84,25 +84,25 @@ M.preview = { }, }, callback = function(opts) - local entry = oil.get_cursor_entry() + local entry = canola.get_cursor_entry() if not entry then vim.notify('Could not find entry under cursor', vim.log.levels.ERROR) return end local winid = util.get_preview_win() if winid then - local cur_id = vim.w[winid].oil_entry_id + local cur_id = vim.w[winid].canola_entry_id if entry.id == cur_id then vim.api.nvim_win_close(winid, true) if util.is_floating_win() then - local layout = require('oil.layout') + local layout = require('canola.layout') local win_opts = layout.get_fullscreen_win_opts() vim.api.nvim_win_set_config(0, win_opts) end return end end - oil.open_preview(opts) + canola.open_preview(opts) end, } @@ -162,35 +162,35 @@ M.preview_scroll_right = { M.parent = { desc = 'Navigate to the parent path', - callback = oil.open, + callback = canola.open, } M.close = { - desc = 'Close oil and restore original buffer', + desc = 'Close canola and restore original buffer', callback = function(opts) opts = opts or {} - oil.close(opts) + canola.close(opts) end, parameters = { exit_if_last_buf = { type = 'boolean', - desc = 'Exit vim if oil is closed as the last buffer', + desc = 'Exit vim if canola is closed as the last buffer', }, }, } M.close_float = { - desc = 'Close oil if the window is floating, otherwise do nothing', + desc = 'Close canola if the window is floating, otherwise do nothing', callback = function(opts) - if vim.w.is_oil_win then + if vim.w.is_canola_win then opts = opts or {} - oil.close(opts) + canola.close(opts) end end, parameters = { exit_if_last_buf = { type = 'boolean', - desc = 'Exit vim if oil is closed as the last buffer', + desc = 'Exit vim if canola is closed as the last buffer', }, }, } @@ -198,7 +198,7 @@ M.close_float = { ---@param cmd string ---@param silent? boolean local function cd(cmd, silent) - local dir = oil.get_current_dir() + local dir = canola.get_current_dir() if dir then vim.cmd({ cmd = cmd, args = { dir } }) if not silent then @@ -210,7 +210,7 @@ local function cd(cmd, silent) end M.cd = { - desc = ':cd to the current oil directory', + desc = ':cd to the current canola directory', callback = function(opts) opts = opts or {} local cmd = 'cd' @@ -234,7 +234,7 @@ M.cd = { } M.tcd = { - desc = ':tcd to the current oil directory', + desc = ':tcd to the current canola directory', deprecated = true, callback = function() cd('tcd') @@ -242,31 +242,31 @@ M.tcd = { } M.open_cwd = { - desc = "Open oil in Neovim's current working directory", + desc = "Open canola in Neovim's current working directory", callback = function() - oil.open(vim.fn.getcwd()) + canola.open(vim.fn.getcwd()) end, } M.toggle_hidden = { desc = 'Toggle hidden files and directories', callback = function() - require('oil.view').toggle_hidden() + require('canola.view').toggle_hidden() end, } M.open_terminal = { desc = 'Open a terminal in the current directory', callback = function() - local config = require('oil.config') + local config = require('canola.config') local bufname = vim.api.nvim_buf_get_name(0) local adapter = config.get_adapter_by_scheme(bufname) if not adapter then return end if adapter.name == 'files' then - local dir = oil.get_current_dir() - assert(dir, 'Oil buffer with files adapter must have current directory') + local dir = canola.get_current_dir() + assert(dir, 'Canola buffer with files adapter must have current directory') local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_current_buf(bufnr) if vim.fn.has('nvim-0.11') == 1 then @@ -278,8 +278,8 @@ M.open_terminal = { elseif adapter.name == 'ssh' then local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_current_buf(bufnr) - local url = require('oil.adapters.ssh').parse_url(bufname) - local cmd = require('oil.adapters.ssh.connection').create_ssh_command(url) + local url = require('canola.adapters.ssh').parse_url(bufname) + local cmd = require('canola.adapters.ssh.connection').create_ssh_command(url) local term_id if vim.fn.has('nvim-0.11') == 1 then term_id = vim.fn.jobstart(cmd, { term = true }) @@ -324,8 +324,8 @@ end M.open_external = { desc = 'Open the entry under the cursor in an external program', callback = function() - local entry = oil.get_cursor_entry() - local dir = oil.get_current_dir() + local entry = canola.get_cursor_entry() + local dir = canola.get_current_dir() if not entry or not dir then return end @@ -381,9 +381,9 @@ M.open_cmdline = { opts = vim.tbl_deep_extend('keep', opts or {}, { shorten_path = true, }) - local config = require('oil.config') - local fs = require('oil.fs') - local entry = oil.get_cursor_entry() + local config = require('canola.config') + local fs = require('canola.fs') + local entry = canola.get_cursor_entry() if not entry then return end @@ -421,8 +421,8 @@ M.yank_entry = { desc = 'Yank the filepath of the entry under the cursor to a register', callback = function(opts) opts = opts or {} - local entry = oil.get_cursor_entry() - local dir = oil.get_current_dir() + local entry = canola.get_cursor_entry() + local dir = canola.get_current_dir() if not entry or not dir then return end @@ -448,8 +448,8 @@ M.copy_entry_path = { desc = 'Yank the filepath of the entry under the cursor to a register', deprecated = true, callback = function() - local entry = oil.get_cursor_entry() - local dir = oil.get_current_dir() + local entry = canola.get_cursor_entry() + local dir = canola.get_current_dir() if not entry or not dir then return end @@ -461,7 +461,7 @@ M.copy_entry_filename = { desc = 'Yank the filename of the entry under the cursor to a register', deprecated = true, callback = function() - local entry = oil.get_cursor_entry() + local entry = canola.get_cursor_entry() if not entry then return end @@ -472,14 +472,14 @@ M.copy_entry_filename = { M.copy_to_system_clipboard = { desc = 'Copy the entry under the cursor to the system clipboard', callback = function() - require('oil.clipboard').copy_to_system_clipboard() + require('canola.clipboard').copy_to_system_clipboard() end, } M.paste_from_system_clipboard = { - desc = 'Paste the system clipboard into the current oil directory', + desc = 'Paste the system clipboard into the current canola directory', callback = function(opts) - require('oil.clipboard').paste_from_system_clipboard(opts and opts.delete_original) + require('canola.clipboard').paste_from_system_clipboard(opts and opts.delete_original) end, parameters = { delete_original = { @@ -493,8 +493,8 @@ M.open_cmdline_dir = { desc = 'Open vim cmdline with current directory as an argument', deprecated = true, callback = function() - local fs = require('oil.fs') - local dir = oil.get_current_dir() + local fs = require('canola.fs') + local dir = canola.get_current_dir() if dir then open_cmdline_with_path(fs.shorten_path(dir)) end @@ -507,24 +507,24 @@ M.change_sort = { opts = opts or {} if opts.sort then - oil.set_sort(opts.sort) + canola.set_sort(opts.sort) return end local sort_cols = { 'name', 'size', 'atime', 'mtime', 'ctime', 'birthtime' } - vim.ui.select(sort_cols, { prompt = 'Sort by', kind = 'oil_sort_col' }, function(col) + vim.ui.select(sort_cols, { prompt = 'Sort by', kind = 'canola_sort_col' }, function(col) if not col then return end vim.ui.select( { 'ascending', 'descending' }, - { prompt = 'Sort order', kind = 'oil_sort_order' }, + { prompt = 'Sort order', kind = 'canola_sort_order' }, function(order) if not order then return end order = order == 'ascending' and 'asc' or 'desc' - oil.set_sort({ + canola.set_sort({ { 'type', 'asc' }, { col, order }, }) @@ -534,8 +534,8 @@ M.change_sort = { end, parameters = { sort = { - type = 'oil.SortSpec[]', - desc = 'List of columns plus direction (see |oil.set_sort|) instead of interactive selection', + type = 'canola.SortSpec[]', + desc = 'List of columns plus direction (see |canola.set_sort|) instead of interactive selection', }, }, } @@ -543,19 +543,19 @@ M.change_sort = { M.toggle_trash = { desc = 'Jump to and from the trash for the current directory', callback = function() - local fs = require('oil.fs') + local fs = require('canola.fs') local bufname = vim.api.nvim_buf_get_name(0) local scheme, path = util.parse_url(bufname) local bufnr = vim.api.nvim_get_current_buf() local url - if scheme == 'oil://' then - url = 'oil-trash://' .. path - elseif scheme == 'oil-trash://' then - url = 'oil://' .. path + if scheme == 'canola://' then + url = 'canola-trash://' .. path + elseif scheme == 'canola-trash://' then + url = 'canola://' .. path -- The non-linux trash implementations don't support per-directory trash, -- so jump back to the stored source buffer. if not fs.is_linux then - local src_bufnr = vim.b.oil_trash_toggle_src + local src_bufnr = vim.b.canola_trash_toggle_src if src_bufnr and vim.api.nvim_buf_is_valid(src_bufnr) then url = vim.api.nvim_buf_get_name(src_bufnr) end @@ -565,12 +565,12 @@ M.toggle_trash = { return end vim.cmd.edit({ args = { url } }) - vim.b.oil_trash_toggle_src = bufnr + vim.b.canola_trash_toggle_src = bufnr end, } M.send_to_qflist = { - desc = 'Sends files in the current oil directory to the quickfix list, replacing the previous entries.', + desc = 'Sends files in the current canola directory to the quickfix list, replacing the previous entries.', callback = function(opts) opts = vim.tbl_deep_extend('keep', opts or {}, { target = 'qflist', @@ -600,7 +600,7 @@ M.send_to_qflist = { } M.add_to_qflist = { - desc = 'Adds files in the current oil directory to the quickfix list, keeping the previous entries.', + desc = 'Adds files in the current canola directory to the quickfix list, keeping the previous entries.', deprecated = true, callback = function() util.send_to_quickfix({ @@ -611,7 +611,7 @@ M.add_to_qflist = { } M.send_to_loclist = { - desc = 'Sends files in the current oil directory to the location list, replacing the previous entries.', + desc = 'Sends files in the current canola directory to the location list, replacing the previous entries.', deprecated = true, callback = function() util.send_to_quickfix({ @@ -622,7 +622,7 @@ M.send_to_loclist = { } M.add_to_loclist = { - desc = 'Adds files in the current oil directory to the location list, keeping the previous entries.', + desc = 'Adds files in the current canola directory to the location list, keeping the previous entries.', deprecated = true, callback = function() util.send_to_quickfix({ diff --git a/lua/oil/adapters/files.lua b/lua/canola/adapters/files.lua similarity index 94% rename from lua/oil/adapters/files.lua rename to lua/canola/adapters/files.lua index e6331ba..3bb8a89 100644 --- a/lua/oil/adapters/files.lua +++ b/lua/canola/adapters/files.lua @@ -1,12 +1,12 @@ -local cache = require('oil.cache') -local columns = require('oil.columns') -local config = require('oil.config') -local constants = require('oil.constants') -local fs = require('oil.fs') -local git = require('oil.git') -local log = require('oil.log') -local permissions = require('oil.adapters.files.permissions') -local util = require('oil.util') +local cache = require('canola.cache') +local columns = require('canola.columns') +local config = require('canola.config') +local constants = require('canola.constants') +local fs = require('canola.fs') +local git = require('canola.git') +local log = require('canola.log') +local permissions = require('canola.adapters.files.permissions') +local util = require('canola.util') local uv = vim.uv or vim.loop local M = {} @@ -35,11 +35,11 @@ local function read_link_data(path, cb) ) end ----@class (exact) oil.FilesAdapter: oil.Adapter ----@field to_short_os_path fun(path: string, entry_type: nil|oil.EntryType): string +---@class (exact) canola.FilesAdapter: canola.Adapter +---@field to_short_os_path fun(path: string, entry_type: nil|canola.EntryType): string ---@param path string ----@param entry_type nil|oil.EntryType +---@param entry_type nil|canola.EntryType ---@return string M.to_short_os_path = function(path, entry_type) local shortpath = fs.shorten_path(fs.posix_to_os_path(path)) @@ -226,7 +226,7 @@ local function columns_require_stat(column_defs) end ---@param name string ----@return nil|oil.ColumnDefinition +---@return nil|canola.ColumnDefinition M.get_column = function(name) return file_columns[name] end @@ -284,7 +284,7 @@ M.normalize_url = function(url, callback) end ---@param url string ----@param entry oil.Entry +---@param entry canola.Entry ---@param cb fun(path: nil|string) M.get_entry_path = function(url, entry, cb) if entry.id then @@ -303,7 +303,7 @@ M.get_entry_path = function(url, entry, cb) end ---@param parent_dir string ----@param entry oil.InternalEntry +---@param entry canola.InternalEntry ---@param require_stat boolean ---@param cb fun(err?: string) local function fetch_entry_metadata(parent_dir, entry, require_stat, cb) @@ -315,7 +315,7 @@ local function fetch_entry_metadata(parent_dir, entry, require_stat, cb) end -- Sometimes fs_readdir entries don't have a type, so we need to stat them. - -- See https://github.com/stevearc/oil.nvim/issues/543 + -- See https://github.com/stevearc/canola.nvim/issues/543 if not require_stat and not entry[FIELD_TYPE] then require_stat = true end @@ -364,7 +364,7 @@ local function fetch_entry_metadata(parent_dir, entry, require_stat, cb) end -- On windows, sometimes the entry type from fs_readdir is "link" but the actual type is not. --- See https://github.com/stevearc/oil.nvim/issues/535 +-- See https://github.com/stevearc/canola.nvim/issues/535 if fs.is_windows then local old_fetch_metadata = fetch_entry_metadata fetch_entry_metadata = function(parent_dir, entry, require_stat, cb) @@ -393,7 +393,7 @@ end ---@param url string ---@param column_defs string[] ----@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param cb fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) local function list_windows_drives(url, column_defs, cb) local _, path = util.parse_url(url) assert(path) @@ -440,7 +440,7 @@ end ---@param url string ---@param column_defs string[] ----@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param cb fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) M.list = function(url, column_defs, cb) local _, path = util.parse_url(url) assert(path) @@ -518,7 +518,7 @@ M.is_modifiable = function(bufnr) return uv.fs_access(dir, 'W') == true end ----@param action oil.Action +---@param action canola.Action ---@return string M.render_action = function(action) if action.type == 'create' then @@ -560,7 +560,7 @@ M.render_action = function(action) end end ----@param action oil.Action +---@param action canola.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) if action.type == 'create' then @@ -619,7 +619,7 @@ M.perform_action = function(action, cb) end if config.delete_to_trash then - require('oil.adapters.trash').delete_to_trash(path, cb) + require('canola.adapters.trash').delete_to_trash(path, cb) else fs.recursive_delete(action.entry_type, path, cb) end diff --git a/lua/oil/adapters/files/permissions.lua b/lua/canola/adapters/files/permissions.lua similarity index 100% rename from lua/oil/adapters/files/permissions.lua rename to lua/canola/adapters/files/permissions.lua diff --git a/lua/oil/adapters/s3.lua b/lua/canola/adapters/s3.lua similarity index 91% rename from lua/oil/adapters/s3.lua rename to lua/canola/adapters/s3.lua index 81557c7..bc3e614 100644 --- a/lua/oil/adapters/s3.lua +++ b/lua/canola/adapters/s3.lua @@ -1,37 +1,37 @@ -local config = require('oil.config') -local constants = require('oil.constants') -local files = require('oil.adapters.files') -local fs = require('oil.fs') -local loading = require('oil.loading') -local pathutil = require('oil.pathutil') -local s3fs = require('oil.adapters.s3.s3fs') -local util = require('oil.util') +local config = require('canola.config') +local constants = require('canola.constants') +local files = require('canola.adapters.files') +local fs = require('canola.fs') +local loading = require('canola.loading') +local pathutil = require('canola.pathutil') +local s3fs = require('canola.adapters.s3.s3fs') +local util = require('canola.util') local M = {} local FIELD_META = constants.FIELD_META ----@class (exact) oil.s3Url +---@class (exact) canola.s3Url ---@field scheme string ---@field bucket nil|string ---@field path nil|string ----@param oil_url string ----@return oil.s3Url -M.parse_url = function(oil_url) - local scheme, url = util.parse_url(oil_url) - assert(scheme and url, string.format("Malformed input url '%s'", oil_url)) +---@param canola_url string +---@return canola.s3Url +M.parse_url = function(canola_url) + local scheme, url = util.parse_url(canola_url) + assert(scheme and url, string.format("Malformed input url '%s'", canola_url)) local ret = { scheme = scheme } local bucket, path = url:match('^([^/]+)/?(.*)$') ret.bucket = bucket ret.path = path ~= '' and path or nil if not ret.bucket and ret.path then - error(string.format('Parsing error for s3 url: %s', oil_url)) + error(string.format('Parsing error for s3 url: %s', canola_url)) end - ---@cast ret oil.s3Url + ---@cast ret canola.s3Url return ret end ----@param url oil.s3Url +---@param url canola.s3Url ---@return string local function url_to_str(url) local pieces = { url.scheme } @@ -47,7 +47,7 @@ local function url_to_str(url) return table.concat(pieces, '') end ----@param url oil.s3Url +---@param url canola.s3Url ---@param is_folder boolean ---@return string local function url_to_s3(url, is_folder) @@ -67,7 +67,7 @@ local function url_to_s3(url, is_folder) return table.concat(pieces, '') end ----@param url oil.s3Url +---@param url canola.s3Url ---@return boolean local function is_bucket(url) assert(url.bucket and url.bucket ~= '') @@ -138,7 +138,7 @@ s3_columns.birthtime = { } ---@param name string ----@return nil|oil.ColumnDefinition +---@return nil|canola.ColumnDefinition M.get_column = function(name) return s3_columns[name] end @@ -166,7 +166,7 @@ end ---@param url string ---@param column_defs string[] ----@param callback fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param callback fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) M.list = function(url, column_defs, callback) if vim.fn.executable('aws') ~= 1 then callback('`aws` is not executable. Can you run `aws s3 ls`?') @@ -184,7 +184,7 @@ M.is_modifiable = function(bufnr) return true end ----@param action oil.Action +---@param action canola.Action ---@return string M.render_action = function(action) local is_folder = action.entry_type == 'directory' @@ -216,7 +216,7 @@ M.render_action = function(action) end end ----@param action oil.Action +---@param action canola.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) local is_folder = action.entry_type == 'directory' @@ -325,7 +325,7 @@ M.read_file = function(bufnr) local basename = pathutil.basename(bufname) local cache_dir = vim.fn.stdpath('cache') assert(type(cache_dir) == 'string') - local tmpdir = fs.join(cache_dir, 'oil') + local tmpdir = fs.join(cache_dir, 'canola') fs.mkdirp(tmpdir) local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, 's3_XXXXXX')) if fd then @@ -363,7 +363,7 @@ M.write_file = function(bufnr) local url = M.parse_url(bufname) local cache_dir = vim.fn.stdpath('cache') assert(type(cache_dir) == 'string') - local tmpdir = fs.join(cache_dir, 'oil') + local tmpdir = fs.join(cache_dir, 'canola') local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, 's3_XXXXXXXX')) if fd then vim.loop.fs_close(fd) diff --git a/lua/oil/adapters/s3/s3fs.lua b/lua/canola/adapters/s3/s3fs.lua similarity index 91% rename from lua/oil/adapters/s3/s3fs.lua rename to lua/canola/adapters/s3/s3fs.lua index a81f10c..d527166 100644 --- a/lua/oil/adapters/s3/s3fs.lua +++ b/lua/canola/adapters/s3/s3fs.lua @@ -1,8 +1,8 @@ -local cache = require('oil.cache') -local config = require('oil.config') -local constants = require('oil.constants') -local shell = require('oil.shell') -local util = require('oil.util') +local cache = require('canola.cache') +local config = require('canola.config') +local constants = require('canola.constants') +local shell = require('canola.shell') +local util = require('canola.util') local M = {} @@ -10,7 +10,7 @@ local FIELD_META = constants.FIELD_META ---@param line string ---@return string Name of entry ----@return oil.EntryType +---@return canola.EntryType ---@return table Metadata for entry local function parse_ls_line_bucket(line) local date, name = line:match('^(%d+%-%d+%-%d+%s%d+:%d+:%d+)%s+(.*)$') @@ -24,7 +24,7 @@ end ---@param line string ---@return string Name of entry ----@return oil.EntryType +---@return canola.EntryType ---@return table Metadata for entry local function parse_ls_line_file(line) local name = line:match('^%s+PRE%s+(.*)/$') @@ -52,7 +52,7 @@ end ---@param url string ---@param path string ----@param callback fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param callback fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) function M.list_dir(url, path, callback) local cmd = create_s3_command({ 'ls', path, '--color=off', '--no-cli-pager' }) shell.run(cmd, function(err, lines) diff --git a/lua/oil/adapters/ssh.lua b/lua/canola/adapters/ssh.lua similarity index 91% rename from lua/oil/adapters/ssh.lua rename to lua/canola/adapters/ssh.lua index b78d02f..4654b32 100644 --- a/lua/oil/adapters/ssh.lua +++ b/lua/canola/adapters/ssh.lua @@ -1,19 +1,19 @@ -local config = require('oil.config') -local constants = require('oil.constants') -local files = require('oil.adapters.files') -local fs = require('oil.fs') -local loading = require('oil.loading') -local pathutil = require('oil.pathutil') -local permissions = require('oil.adapters.files.permissions') -local shell = require('oil.shell') -local sshfs = require('oil.adapters.ssh.sshfs') -local util = require('oil.util') +local config = require('canola.config') +local constants = require('canola.constants') +local files = require('canola.adapters.files') +local fs = require('canola.fs') +local loading = require('canola.loading') +local pathutil = require('canola.pathutil') +local permissions = require('canola.adapters.files.permissions') +local shell = require('canola.shell') +local sshfs = require('canola.adapters.ssh.sshfs') +local util = require('canola.util') local M = {} local FIELD_NAME = constants.FIELD_NAME local FIELD_META = constants.FIELD_META ----@class (exact) oil.sshUrl +---@class (exact) canola.sshUrl ---@field scheme string ---@field host string ---@field user nil|string @@ -27,11 +27,11 @@ local function scp(args, ...) shell.run(cmd, ...) end ----@param oil_url string ----@return oil.sshUrl -M.parse_url = function(oil_url) - local scheme, url = util.parse_url(oil_url) - assert(scheme and url, string.format("Malformed input url '%s'", oil_url)) +---@param canola_url string +---@return canola.sshUrl +M.parse_url = function(canola_url) + local scheme, url = util.parse_url(canola_url) + assert(scheme and url, string.format("Malformed input url '%s'", canola_url)) local ret = { scheme = scheme } local username, rem = url:match('^([^@%s]+)@(.*)$') ret.user = username @@ -47,14 +47,14 @@ M.parse_url = function(oil_url) ret.path = path end if not ret.host or not ret.path then - error(string.format('Malformed SSH url: %s', oil_url)) + error(string.format('Malformed SSH url: %s', canola_url)) end - ---@cast ret oil.sshUrl + ---@cast ret canola.sshUrl return ret end ----@param url oil.sshUrl +---@param url canola.sshUrl ---@return string local function url_to_str(url) local pieces = { url.scheme } @@ -71,7 +71,7 @@ local function url_to_str(url) return table.concat(pieces, '') end ----@param url oil.sshUrl +---@param url canola.sshUrl ---@return string local function url_to_scp(url) local pieces = { 'scp://' } @@ -89,8 +89,8 @@ local function url_to_scp(url) return table.concat(pieces, '') end ----@param url1 oil.sshUrl ----@param url2 oil.sshUrl +---@param url1 canola.sshUrl +---@param url2 canola.sshUrl ---@return boolean local function url_hosts_equal(url1, url2) return url1.host == url2.host and url1.port == url2.port and url1.user == url2.user @@ -99,7 +99,7 @@ end local _connections = {} ---@param url string ---@param allow_retry nil|boolean ----@return oil.sshFs +---@return canola.sshFs local function get_connection(url, allow_retry) local res = M.parse_url(url) res.scheme = config.adapter_to_scheme.ssh @@ -178,7 +178,7 @@ ssh_columns.size = { } ---@param name string ----@return nil|oil.ColumnDefinition +---@return nil|canola.ColumnDefinition M.get_column = function(name) return ssh_columns[name] end @@ -223,7 +223,7 @@ end ---@param url string ---@param column_defs string[] ----@param callback fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param callback fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) M.list = function(url, column_defs, callback) local res = M.parse_url(url) @@ -256,7 +256,7 @@ M.is_modifiable = function(bufnr) return bit.band(rwx, 2) ~= 0 end ----@param action oil.Action +---@param action canola.Action ---@return string M.render_action = function(action) if action.type == 'create' then @@ -285,7 +285,7 @@ M.render_action = function(action) end end ----@param action oil.Action +---@param action canola.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) if action.type == 'create' then @@ -367,7 +367,7 @@ M.read_file = function(bufnr) local basename = pathutil.basename(bufname) local cache_dir = vim.fn.stdpath('cache') assert(type(cache_dir) == 'string') - local tmpdir = fs.join(cache_dir, 'oil') + local tmpdir = fs.join(cache_dir, 'canola') fs.mkdirp(tmpdir) local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, 'ssh_XXXXXX')) if fd then @@ -407,7 +407,7 @@ M.write_file = function(bufnr) local scp_url = url_to_scp(url) local cache_dir = vim.fn.stdpath('cache') assert(type(cache_dir) == 'string') - local tmpdir = fs.join(cache_dir, 'oil') + local tmpdir = fs.join(cache_dir, 'canola') local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, 'ssh_XXXXXXXX')) if fd then vim.loop.fs_close(fd) @@ -441,7 +441,7 @@ M.goto_file = function() url.path = vim.fs.dirname(fullpath) local parurl = url_to_str(url) - ---@cast M oil.Adapter + ---@cast M canola.Adapter util.adapter_list_all(M, parurl, {}, function(err, entries) if err then vim.notify(string.format("Error finding file '%s': %s", fname, err), vim.log.levels.ERROR) diff --git a/lua/oil/adapters/ssh/connection.lua b/lua/canola/adapters/ssh/connection.lua similarity index 94% rename from lua/oil/adapters/ssh/connection.lua rename to lua/canola/adapters/ssh/connection.lua index 6dbaa49..d5bcd06 100644 --- a/lua/oil/adapters/ssh/connection.lua +++ b/lua/canola/adapters/ssh/connection.lua @@ -1,22 +1,22 @@ -local config = require('oil.config') -local layout = require('oil.layout') -local util = require('oil.util') +local config = require('canola.config') +local layout = require('canola.layout') +local util = require('canola.util') ----@class (exact) oil.sshCommand +---@class (exact) canola.sshCommand ---@field cmd string|string[] ---@field cb fun(err?: string, output?: string[]) ---@field running? boolean ----@class (exact) oil.sshConnection ----@field new fun(url: oil.sshUrl): oil.sshConnection ----@field create_ssh_command fun(url: oil.sshUrl): string[] +---@class (exact) canola.sshConnection +---@field new fun(url: canola.sshUrl): canola.sshConnection +---@field create_ssh_command fun(url: canola.sshUrl): string[] ---@field meta {user?: string, groups?: string[]} ---@field connection_error nil|string ---@field connected boolean ---@field private term_bufnr integer ---@field private jid integer ---@field private term_winid nil|integer ----@field private commands oil.sshCommand[] +---@field private commands canola.sshCommand[] ---@field private _stdout string[] local SSHConnection = {} @@ -61,7 +61,7 @@ local function get_last_lines(bufnr, num_lines) return lines end ----@param url oil.sshUrl +---@param url canola.sshUrl ---@return string[] function SSHConnection.create_ssh_command(url) local host = url.host @@ -79,8 +79,8 @@ function SSHConnection.create_ssh_command(url) return command end ----@param url oil.sshUrl ----@return oil.sshConnection +---@param url canola.sshUrl +---@return canola.sshConnection function SSHConnection.new(url) local command = SSHConnection.create_ssh_command(url) vim.list_extend(command, { @@ -142,7 +142,7 @@ function SSHConnection.new(url) self:_set_connection_error('SSH connection terminated gracefully') else self:_set_connection_error( - 'Unknown SSH error\nTo see more, run :lua require("oil.adapters.ssh").open_terminal()' + 'Unknown SSH error\nTo see more, run :lua require("canola.adapters.ssh").open_terminal()' ) end end, 20) @@ -176,7 +176,7 @@ function SSHConnection.new(url) end end) - ---@cast self oil.sshConnection + ---@cast self canola.sshConnection return self end diff --git a/lua/oil/adapters/ssh/sshfs.lua b/lua/canola/adapters/ssh/sshfs.lua similarity index 92% rename from lua/oil/adapters/ssh/sshfs.lua rename to lua/canola/adapters/ssh/sshfs.lua index 7d250f2..c8602de 100644 --- a/lua/oil/adapters/ssh/sshfs.lua +++ b/lua/canola/adapters/ssh/sshfs.lua @@ -1,12 +1,12 @@ -local SSHConnection = require('oil.adapters.ssh.connection') -local cache = require('oil.cache') -local constants = require('oil.constants') -local permissions = require('oil.adapters.files.permissions') -local util = require('oil.util') +local SSHConnection = require('canola.adapters.ssh.connection') +local cache = require('canola.cache') +local constants = require('canola.constants') +local permissions = require('canola.adapters.files.permissions') +local util = require('canola.util') ----@class (exact) oil.sshFs ----@field new fun(url: oil.sshUrl): oil.sshFs ----@field conn oil.sshConnection +---@class (exact) canola.sshFs +---@field new fun(url: canola.sshUrl): canola.sshFs +---@field conn canola.sshConnection local SSHFS = {} local FIELD_TYPE = constants.FIELD_TYPE @@ -23,7 +23,7 @@ local typechar_map = { } ---@param line string ---@return string Name of entry ----@return oil.EntryType +---@return canola.EntryType ---@return table Metadata for entry local function parse_ls_line(line) local typechar, perms, refcount, user, group, rem = @@ -74,10 +74,10 @@ local function shellescape(str) return "'" .. str:gsub("'", "'\\''") .. "'" end ----@param url oil.sshUrl ----@return oil.sshFs +---@param url canola.sshUrl +---@return canola.sshFs function SSHFS.new(url) - ---@type oil.sshFs + ---@type canola.sshFs return setmetatable({ conn = SSHConnection.new(url), }, { @@ -144,7 +144,7 @@ local dir_meta = {} ---@param url string ---@param path string ----@param callback fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param callback fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) function SSHFS:list_dir(url, path, callback) local path_postfix = '' if path ~= '' then diff --git a/lua/oil/adapters/test.lua b/lua/canola/adapters/test.lua similarity index 83% rename from lua/oil/adapters/test.lua rename to lua/canola/adapters/test.lua index 2e80e9a..bcc42ed 100644 --- a/lua/oil/adapters/test.lua +++ b/lua/canola/adapters/test.lua @@ -1,5 +1,5 @@ -local cache = require('oil.cache') -local util = require('oil.util') +local cache = require('canola.cache') +local util = require('canola.util') local M = {} ---@param url string @@ -12,7 +12,7 @@ local dir_listing = {} ---@param url string ---@param column_defs string[] ----@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param cb fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) M.list = function(url, column_defs, cb) local _, path = util.parse_url(url) local entries = dir_listing[path] or {} @@ -29,8 +29,8 @@ M.test_clear = function() end ---@param path string ----@param entry_type oil.EntryType ----@return oil.InternalEntry +---@param entry_type canola.EntryType +---@return canola.InternalEntry M.test_set = function(path, entry_type) if path == '/' then return {} @@ -49,12 +49,12 @@ M.test_set = function(path, entry_type) entry_type = entry_type, } table.insert(dir_listing[parent], entry) - local parent_url = 'oil-test://' .. parent + local parent_url = 'canola-test://' .. parent return cache.create_and_store_entry(parent_url, entry.name, entry.entry_type) end ---@param name string ----@return nil|oil.ColumnDefinition +---@return nil|canola.ColumnDefinition M.get_column = function(name) return nil end @@ -65,7 +65,7 @@ M.is_modifiable = function(bufnr) return true end ----@param action oil.Action +---@param action canola.Action ---@return string M.render_action = function(action) if action.type == 'create' or action.type == 'delete' then @@ -77,7 +77,7 @@ M.render_action = function(action) end end ----@param action oil.Action +---@param action canola.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) cb() diff --git a/lua/canola/adapters/trash.lua b/lua/canola/adapters/trash.lua new file mode 100644 index 0000000..42b82d5 --- /dev/null +++ b/lua/canola/adapters/trash.lua @@ -0,0 +1,9 @@ +local fs = require('canola.fs') + +if fs.is_mac then + return require('canola.adapters.trash.mac') +elseif fs.is_windows then + return require('canola.adapters.trash.windows') +else + return require('canola.adapters.trash.freedesktop') +end diff --git a/lua/oil/adapters/trash/freedesktop.lua b/lua/canola/adapters/trash/freedesktop.lua similarity index 95% rename from lua/oil/adapters/trash/freedesktop.lua rename to lua/canola/adapters/trash/freedesktop.lua index 1e1d34d..65bf090 100644 --- a/lua/oil/adapters/trash/freedesktop.lua +++ b/lua/canola/adapters/trash/freedesktop.lua @@ -1,11 +1,11 @@ -- Based on the FreeDesktop.org trash specification -- https://specifications.freedesktop.org/trash/1.0/ -local cache = require('oil.cache') -local config = require('oil.config') -local constants = require('oil.constants') -local files = require('oil.adapters.files') -local fs = require('oil.fs') -local util = require('oil.util') +local cache = require('canola.cache') +local config = require('canola.config') +local constants = require('canola.constants') +local files = require('canola.adapters.files') +local fs = require('canola.fs') +local util = require('canola.util') local uv = vim.uv or vim.loop local FIELD_META = constants.FIELD_META @@ -127,12 +127,12 @@ M.normalize_url = function(url, callback) end ---@param url string ----@param entry oil.Entry +---@param entry canola.Entry ---@param cb fun(path: string) M.get_entry_path = function(url, entry, cb) local internal_entry = assert(cache.get_entry_by_id(entry.id)) local meta = assert(internal_entry[FIELD_META]) - ---@type oil.TrashInfo + ---@type canola.TrashInfo local trash_info = meta.trash_info if not trash_info then -- This is a subpath in the trash @@ -143,10 +143,10 @@ M.get_entry_path = function(url, entry, cb) if meta.stat.type == 'directory' then path = util.addslash(path) end - cb('oil://' .. path) + cb('canola://' .. path) end ----@class oil.TrashInfo +---@class canola.TrashInfo ---@field trash_file string ---@field info_file string ---@field original_path string @@ -154,7 +154,7 @@ end ---@field stat uv.aliases.fs_stat_table ---@param info_file string ----@param cb fun(err?: string, info?: oil.TrashInfo) +---@param cb fun(err?: string, info?: canola.TrashInfo) local function read_trash_info(info_file, cb) if not vim.endswith(info_file, '.trashinfo') then return cb('File is not .trashinfo') @@ -210,7 +210,7 @@ local function read_trash_info(info_file, cb) cb('.trashinfo file points to non-existant file') else trash_info.stat = trash_stat - ---@cast trash_info oil.TrashInfo + ---@cast trash_info canola.TrashInfo cb(nil, trash_info) end end) @@ -222,7 +222,7 @@ end ---@param url string ---@param column_defs string[] ----@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param cb fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) M.list = function(url, column_defs, cb) cb = vim.schedule_wrap(cb) local _, path = util.parse_url(url) @@ -357,7 +357,7 @@ file_columns.mtime = { if not meta then return nil end - ---@type oil.TrashInfo + ---@type canola.TrashInfo local trash_info = meta.trash_info local time = trash_info and trash_info.deletion_date or meta.stat and meta.stat.mtime.sec if not time then @@ -380,7 +380,7 @@ file_columns.mtime = { get_sort_value = function(entry) local meta = entry[FIELD_META] - ---@type nil|oil.TrashInfo + ---@type nil|canola.TrashInfo local trash_info = meta and meta.trash_info if trash_info then return trash_info.deletion_date @@ -402,14 +402,14 @@ file_columns.mtime = { } ---@param name string ----@return nil|oil.ColumnDefinition +---@return nil|canola.ColumnDefinition M.get_column = function(name) return file_columns[name] end M.supported_cross_adapter_actions = { files = 'move' } ----@param action oil.Action +---@param action canola.Action ---@return boolean M.filter_action = function(action) if action.type == 'create' then @@ -432,7 +432,7 @@ M.filter_action = function(action) end end ----@param err oil.ParseError +---@param err canola.ParseError ---@return boolean M.filter_error = function(err) if err.message == 'Duplicate filename' then @@ -441,13 +441,13 @@ M.filter_error = function(err) return true end ----@param action oil.Action +---@param action canola.Action ---@return string M.render_action = function(action) if action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) local meta = entry[FIELD_META] - ---@type oil.TrashInfo + ---@type canola.TrashInfo local trash_info = assert(meta).trash_info local short_path = fs.shorten_path(trash_info.original_path) return string.format(' PURGE %s', short_path) @@ -488,7 +488,7 @@ M.render_action = function(action) end end ----@param trash_info oil.TrashInfo +---@param trash_info canola.TrashInfo ---@param cb fun(err?: string) local function purge(trash_info, cb) fs.recursive_delete('file', trash_info.info_file, function(err) @@ -525,7 +525,7 @@ local function write_info_file(path, info_path, cb) end ---@param path string ----@param cb fun(err?: string, trash_info?: oil.TrashInfo) +---@param cb fun(err?: string, trash_info?: canola.TrashInfo) local function create_trash_info(path, cb) local trash_dir = get_write_trash_dir(path) local basename = vim.fs.basename(path) @@ -542,7 +542,7 @@ local function create_trash_info(path, cb) if info_err then return cb(info_err) end - ---@type oil.TrashInfo + ---@type canola.TrashInfo local trash_info = { original_path = path, trash_file = dest_path, @@ -555,13 +555,13 @@ local function create_trash_info(path, cb) end) end ----@param action oil.Action +---@param action canola.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) if action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) local meta = entry[FIELD_META] - ---@type oil.TrashInfo + ---@type canola.TrashInfo local trash_info = assert(meta).trash_info purge(trash_info, cb) elseif action.type == 'move' then @@ -576,7 +576,7 @@ M.perform_action = function(action, cb) assert(dest_path) local entry = assert(cache.get_entry_by_url(action.src_url)) local meta = entry[FIELD_META] - ---@type oil.TrashInfo + ---@type canola.TrashInfo local trash_info = assert(meta).trash_info fs.recursive_move(action.entry_type, trash_info.trash_file, dest_path, function(err) if err then @@ -607,7 +607,7 @@ M.perform_action = function(action, cb) assert(dest_path) local entry = assert(cache.get_entry_by_url(action.src_url)) local meta = entry[FIELD_META] - ---@type oil.TrashInfo + ---@type canola.TrashInfo local trash_info = assert(meta).trash_info fs.recursive_copy(action.entry_type, trash_info.trash_file, dest_path, cb) else diff --git a/lua/oil/adapters/trash/mac.lua b/lua/canola/adapters/trash/mac.lua similarity index 93% rename from lua/oil/adapters/trash/mac.lua rename to lua/canola/adapters/trash/mac.lua index e1c052d..3bf35ed 100644 --- a/lua/oil/adapters/trash/mac.lua +++ b/lua/canola/adapters/trash/mac.lua @@ -1,8 +1,8 @@ -local cache = require('oil.cache') -local config = require('oil.config') -local files = require('oil.adapters.files') -local fs = require('oil.fs') -local util = require('oil.util') +local cache = require('canola.cache') +local config = require('canola.config') +local files = require('canola.adapters.files') +local fs = require('canola.fs') +local util = require('canola.util') local uv = vim.uv or vim.loop @@ -29,20 +29,20 @@ M.normalize_url = function(url, callback) end ---@param url string ----@param entry oil.Entry +---@param entry canola.Entry ---@param cb fun(path: string) M.get_entry_path = function(url, entry, cb) local trash_dir = get_trash_dir() local path = fs.join(trash_dir, entry.name) if entry.type == 'directory' then - path = 'oil://' .. path + path = 'canola://' .. path end cb(path) end ---@param url string ---@param column_defs string[] ----@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param cb fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) M.list = function(url, column_defs, cb) cb = vim.schedule_wrap(cb) local _, path = util.parse_url(url) @@ -106,14 +106,14 @@ M.is_modifiable = function(bufnr) end ---@param name string ----@return nil|oil.ColumnDefinition +---@return nil|canola.ColumnDefinition M.get_column = function(name) return nil end M.supported_cross_adapter_actions = { files = 'move' } ----@param action oil.Action +---@param action canola.Action ---@return string M.render_action = function(action) if action.type == 'create' then @@ -143,7 +143,7 @@ M.render_action = function(action) end end ----@param action oil.Action +---@param action canola.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) local trash_dir = get_trash_dir() diff --git a/lua/oil/adapters/trash/windows.lua b/lua/canola/adapters/trash/windows.lua similarity index 90% rename from lua/oil/adapters/trash/windows.lua rename to lua/canola/adapters/trash/windows.lua index c761f82..b0b2dcf 100644 --- a/lua/oil/adapters/trash/windows.lua +++ b/lua/canola/adapters/trash/windows.lua @@ -1,11 +1,11 @@ -local util = require('oil.util') +local util = require('canola.util') local uv = vim.uv or vim.loop -local cache = require('oil.cache') -local config = require('oil.config') -local constants = require('oil.constants') -local files = require('oil.adapters.files') -local fs = require('oil.fs') -local powershell_trash = require('oil.adapters.trash.windows.powershell-trash') +local cache = require('canola.cache') +local config = require('canola.config') +local constants = require('canola.constants') +local files = require('canola.adapters.files') +local fs = require('canola.fs') +local powershell_trash = require('canola.adapters.trash.windows.powershell-trash') local FIELD_META = constants.FIELD_META local FIELD_TYPE = constants.FIELD_TYPE @@ -36,7 +36,7 @@ local win_addslash = function(path) end end ----@class oil.WindowsTrashInfo +---@class canola.WindowsTrashInfo ---@field trash_file string ---@field original_path string ---@field deletion_date integer @@ -44,7 +44,7 @@ end ---@param url string ---@param column_defs string[] ----@param cb fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun()) +---@param cb fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun()) M.list = function(url, column_defs, cb) local _, path = util.parse_url(url) path = fs.posix_to_os_path(assert(path)) @@ -70,11 +70,11 @@ M.list = function(url, column_defs, cb) ) local displayed_entries = vim.tbl_map( ---@param entry {IsFolder: boolean, DeletionDate: integer, Name: string, Path: string, OriginalPath: string} - ---@return {[1]:nil, [2]:string, [3]:string, [4]:{stat: uv_fs_t, trash_info: oil.WindowsTrashInfo, display_name: string}} + ---@return {[1]:nil, [2]:string, [3]:string, [4]:{stat: uv_fs_t, trash_info: canola.WindowsTrashInfo, display_name: string}} function(entry) local parent = win_addslash(assert(vim.fn.fnamemodify(entry.OriginalPath, ':h'))) - --- @type oil.InternalEntry + --- @type canola.InternalEntry local cache_entry if path == parent or show_all_files then local deleted_file_tail = assert(vim.fn.fnamemodify(entry.Path, ':t')) @@ -96,7 +96,7 @@ M.list = function(url, column_defs, cb) end cache_entry[FIELD_META] = { stat = nil, - ---@type oil.WindowsTrashInfo + ---@type canola.WindowsTrashInfo trash_info = { trash_file = entry.Path, original_path = entry.OriginalPath, @@ -142,7 +142,7 @@ file_columns.mtime = { if not meta then return nil end - ---@type oil.WindowsTrashInfo + ---@type canola.WindowsTrashInfo local trash_info = meta.trash_info local time = trash_info and trash_info.deletion_date if not time then @@ -165,7 +165,7 @@ file_columns.mtime = { get_sort_value = function(entry) local meta = entry[FIELD_META] - ---@type nil|oil.WindowsTrashInfo + ---@type nil|canola.WindowsTrashInfo local trash_info = meta and meta.trash_info if trash_info and trash_info.deletion_date then return trash_info.deletion_date @@ -187,12 +187,12 @@ file_columns.mtime = { } ---@param name string ----@return nil|oil.ColumnDefinition +---@return nil|canola.ColumnDefinition M.get_column = function(name) return file_columns[name] end ----@param action oil.Action +---@param action canola.Action ---@return boolean M.filter_action = function(action) if action.type == 'create' then @@ -232,11 +232,11 @@ M.normalize_url = function(url, callback) end ---@param url string ----@param entry oil.Entry +---@param entry canola.Entry ---@param cb fun(path: string) M.get_entry_path = function(url, entry, cb) local internal_entry = assert(cache.get_entry_by_id(entry.id)) - local meta = internal_entry[FIELD_META] --[[@as {stat: uv_fs_t, trash_info: oil.WindowsTrashInfo, display_name: string}]] + local meta = internal_entry[FIELD_META] --[[@as {stat: uv_fs_t, trash_info: canola.WindowsTrashInfo, display_name: string}]] local trash_info = meta and meta.trash_info if not trash_info then -- This is a subpath in the trash @@ -248,10 +248,10 @@ M.get_entry_path = function(url, entry, cb) if entry.type == 'directory' then path = win_addslash(path) end - cb('oil://' .. path) + cb('canola://' .. path) end ----@param err oil.ParseError +---@param err canola.ParseError ---@return boolean M.filter_error = function(err) if err.message == 'Duplicate filename' then @@ -260,13 +260,13 @@ M.filter_error = function(err) return true end ----@param action oil.Action +---@param action canola.Action ---@return string M.render_action = function(action) if action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) local meta = entry[FIELD_META] - ---@type oil.WindowsTrashInfo + ---@type canola.WindowsTrashInfo local trash_info = assert(meta).trash_info local short_path = fs.shorten_path(trash_info.original_path) return string.format(' PURGE %s', short_path) @@ -307,8 +307,8 @@ M.render_action = function(action) end end ----@param trash_info oil.WindowsTrashInfo ----@param cb fun(err?: string, raw_entries: oil.WindowsRawEntry[]?) +---@param trash_info canola.WindowsTrashInfo +---@param cb fun(err?: string, raw_entries: canola.WindowsRawEntry[]?) local purge = function(trash_info, cb) fs.recursive_delete('file', trash_info.info_file, function(err) if err then @@ -320,7 +320,7 @@ end ---@param path string ---@param type string ----@param cb fun(err?: string, trash_info?: oil.TrashInfo) +---@param cb fun(err?: string, trash_info?: canola.TrashInfo) local function create_trash_info_and_copy(path, type, cb) local temp_path = path .. 'temp' -- create a temporary copy on the same location @@ -344,12 +344,12 @@ local function create_trash_info_and_copy(path, type, cb) ) end ----@param action oil.Action +---@param action canola.Action ---@param cb fun(err: nil|string) M.perform_action = function(action, cb) if action.type == 'delete' then local entry = assert(cache.get_entry_by_url(action.url)) - local meta = entry[FIELD_META] --[[@as {stat: uv_fs_t, trash_info: oil.WindowsTrashInfo, display_name: string}]] + local meta = entry[FIELD_META] --[[@as {stat: uv_fs_t, trash_info: canola.WindowsTrashInfo, display_name: string}]] local trash_info = meta and meta.trash_info purge(trash_info, cb) @@ -365,7 +365,7 @@ M.perform_action = function(action, cb) assert(dest_path) dest_path = fs.posix_to_os_path(dest_path) local entry = assert(cache.get_entry_by_url(action.src_url)) - local meta = entry[FIELD_META] --[[@as {stat: uv_fs_t, trash_info: oil.WindowsTrashInfo, display_name: string}]] + local meta = entry[FIELD_META] --[[@as {stat: uv_fs_t, trash_info: canola.WindowsTrashInfo, display_name: string}]] local trash_info = meta and meta.trash_info fs.recursive_move(action.entry_type, trash_info.trash_file, dest_path, function(err) if err then @@ -389,7 +389,7 @@ M.perform_action = function(action, cb) assert(dest_path) dest_path = fs.posix_to_os_path(dest_path) local entry = assert(cache.get_entry_by_url(action.src_url)) - local meta = entry[FIELD_META] --[[@as {stat: uv_fs_t, trash_info: oil.WindowsTrashInfo, display_name: string}]] + local meta = entry[FIELD_META] --[[@as {stat: uv_fs_t, trash_info: canola.WindowsTrashInfo, display_name: string}]] local trash_info = meta and meta.trash_info fs.recursive_copy(action.entry_type, trash_info.trash_file, dest_path, cb) else diff --git a/lua/oil/adapters/trash/windows/powershell-connection.lua b/lua/canola/adapters/trash/windows/powershell-connection.lua similarity index 94% rename from lua/oil/adapters/trash/windows/powershell-connection.lua rename to lua/canola/adapters/trash/windows/powershell-connection.lua index d897fe8..d97fa4f 100644 --- a/lua/oil/adapters/trash/windows/powershell-connection.lua +++ b/lua/canola/adapters/trash/windows/powershell-connection.lua @@ -1,18 +1,18 @@ ----@class (exact) oil.PowershellCommand +---@class (exact) canola.PowershellCommand ---@field cmd string ---@field cb fun(err?: string, output?: string) ---@field running? boolean ----@class oil.PowershellConnection +---@class canola.PowershellConnection ---@field private jid integer ---@field private execution_error? string ----@field private commands oil.PowershellCommand[] +---@field private commands canola.PowershellCommand[] ---@field private stdout string[] ---@field private is_reading_data boolean local PowershellConnection = {} ---@param init_command? string ----@return oil.PowershellConnection +---@return canola.PowershellConnection function PowershellConnection.new(init_command) local self = setmetatable({ commands = {}, @@ -22,7 +22,7 @@ function PowershellConnection.new(init_command) self:_init(init_command) - ---@type oil.PowershellConnection + ---@type canola.PowershellConnection return self end diff --git a/lua/oil/adapters/trash/windows/powershell-trash.lua b/lua/canola/adapters/trash/windows/powershell-trash.lua similarity index 88% rename from lua/oil/adapters/trash/windows/powershell-trash.lua rename to lua/canola/adapters/trash/windows/powershell-trash.lua index edc9ee6..55ff69a 100644 --- a/lua/oil/adapters/trash/windows/powershell-trash.lua +++ b/lua/canola/adapters/trash/windows/powershell-trash.lua @@ -1,7 +1,7 @@ -- A wrapper around trash operations using windows powershell -local Powershell = require('oil.adapters.trash.windows.powershell-connection') +local Powershell = require('canola.adapters.trash.windows.powershell-connection') ----@class oil.WindowsRawEntry +---@class canola.WindowsRawEntry ---@field IsFolder boolean ---@field DeletionDate integer ---@field Name string @@ -30,10 +30,10 @@ $data = @(foreach ($i in $folder.items()) ConvertTo-Json $data -Compress ]] ----@type nil|oil.PowershellConnection +---@type nil|canola.PowershellConnection local list_entries_powershell ----@param cb fun(err?: string, raw_entries?: oil.WindowsRawEntry[]) +---@param cb fun(err?: string, raw_entries?: canola.WindowsRawEntry[]) M.list_raw_entries = function(cb) if not list_entries_powershell then list_entries_powershell = Powershell.new(list_entries_init) @@ -63,7 +63,7 @@ $path = Get-Item '%s' $folder.ParseName($path.FullName).InvokeVerb('delete') ]] ----@type nil|oil.PowershellConnection +---@type nil|canola.PowershellConnection local delete_to_trash_powershell ---@param path string diff --git a/lua/oil/cache.lua b/lua/canola/cache.lua similarity index 91% rename from lua/oil/cache.lua rename to lua/canola/cache.lua index 800c97a..20160c7 100644 --- a/lua/oil/cache.lua +++ b/lua/canola/cache.lua @@ -1,5 +1,5 @@ -local constants = require('oil.constants') -local util = require('oil.util') +local constants = require('canola.constants') +local util = require('canola.util') local M = {} local FIELD_ID = constants.FIELD_ID @@ -8,11 +8,11 @@ local FIELD_META = constants.FIELD_META local next_id = 1 --- Map> ----@type table> +-- Map> +---@type table> local url_directory = {} ----@type table +---@type table local entries_by_id = {} ---@type table @@ -42,8 +42,8 @@ end ---@param parent_url string ---@param name string ----@param type oil.EntryType ----@return oil.InternalEntry +---@param type canola.EntryType +---@return canola.InternalEntry M.create_entry = function(parent_url, name, type) parent_url = util.addslash(parent_url) local parent = tmp_url_directory[parent_url] or url_directory[parent_url] @@ -58,7 +58,7 @@ M.create_entry = function(parent_url, name, type) end ---@param parent_url string ----@param entry oil.InternalEntry +---@param entry canola.InternalEntry M.store_entry = function(parent_url, entry) parent_url = util.addslash(parent_url) local parent = url_directory[parent_url] @@ -85,8 +85,8 @@ end ---@param parent_url string ---@param name string ----@param type oil.EntryType ----@return oil.InternalEntry +---@param type canola.EntryType +---@return canola.InternalEntry M.create_and_store_entry = function(parent_url, name, type) local entry = M.create_entry(parent_url, name, type) M.store_entry(parent_url, entry) @@ -115,13 +115,13 @@ M.end_update_url = function(parent_url) end ---@param id integer ----@return nil|oil.InternalEntry +---@return nil|canola.InternalEntry M.get_entry_by_id = function(id) return entries_by_id[id] end ---@param url string ----@return nil|oil.InternalEntry +---@return nil|canola.InternalEntry M.get_entry_by_url = function(url) local scheme, path = util.parse_url(url) assert(path) @@ -141,13 +141,13 @@ M.get_parent_url = function(id) end ---@param url string ----@return table +---@return table M.list_url = function(url) url = util.addslash(url) return url_directory[url] or {} end ----@param action oil.Action +---@param action canola.Action M.perform_action = function(action) if action.type == 'create' then local scheme, path = util.parse_url(action.url) diff --git a/lua/oil/clipboard.lua b/lua/canola/clipboard.lua similarity index 93% rename from lua/oil/clipboard.lua rename to lua/canola/clipboard.lua index 84df407..a5bad24 100644 --- a/lua/oil/clipboard.lua +++ b/lua/canola/clipboard.lua @@ -1,11 +1,11 @@ -local cache = require('oil.cache') -local columns = require('oil.columns') -local config = require('oil.config') -local fs = require('oil.fs') -local oil = require('oil') -local parser = require('oil.mutator.parser') -local util = require('oil.util') -local view = require('oil.view') +local cache = require('canola.cache') +local canola = require('canola') +local columns = require('canola.columns') +local config = require('canola.config') +local fs = require('canola.fs') +local parser = require('canola.mutator.parser') +local util = require('canola.util') +local view = require('canola.view') local M = {} @@ -35,9 +35,9 @@ local function is_linux_desktop_gnome() end ---@param winid integer ----@param entry oil.InternalEntry ----@param column_defs oil.ColumnSpec[] ----@param adapter oil.Adapter +---@param entry canola.InternalEntry +---@param column_defs canola.ColumnSpec[] +---@param adapter canola.Adapter ---@param bufnr integer local function write_pasted(winid, entry, column_defs, adapter, bufnr) local col_width = {} @@ -52,7 +52,7 @@ local function write_pasted(winid, entry, column_defs, adapter, bufnr) end ---@param parent_url string ----@param entry oil.InternalEntry +---@param entry canola.InternalEntry local function remove_entry_from_parent_buffer(parent_url, entry) local bufnr = vim.fn.bufadd(parent_url) assert(vim.api.nvim_buf_is_loaded(bufnr), 'Expected parent buffer to be loaded during paste') @@ -77,7 +77,7 @@ end ---@param delete_original? boolean local function paste_paths(paths, delete_original) local bufnr = vim.api.nvim_get_current_buf() - local scheme = 'oil://' + local scheme = 'canola://' local adapter = assert(config.get_adapter_by_scheme(scheme)) local column_defs = columns.get_supported_columns(scheme) local winid = vim.api.nvim_get_current_win() @@ -140,7 +140,7 @@ local function paste_paths(paths, delete_original) for parent_url, _ in pairs(parent_urls) do local new_bufnr = vim.api.nvim_create_buf(false, false) vim.api.nvim_buf_set_name(new_bufnr, parent_url) - oil.load_oil_buffer(new_bufnr) + canola.load_canola_buffer(new_bufnr) util.run_after_load(new_bufnr, complete_loading) end end @@ -162,7 +162,7 @@ local function range_from_selection() end M.copy_to_system_clipboard = function() - local dir = oil.get_current_dir() + local dir = canola.get_current_dir() if not dir then vim.notify('System clipboard only works for local files', vim.log.levels.ERROR) return @@ -180,13 +180,13 @@ M.copy_to_system_clipboard = function() end local start_row, end_row = range_from_selection() for i = start_row, end_row do - table.insert(entries, oil.get_entry_on_line(0, i)) + table.insert(entries, canola.get_entry_on_line(0, i)) end -- leave visual mode vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'n', true) else - table.insert(entries, oil.get_cursor_entry()) + table.insert(entries, canola.get_cursor_entry()) end -- This removes holes in the list-like table @@ -298,7 +298,7 @@ end ---@param delete_original? boolean Delete the source file after pasting M.paste_from_system_clipboard = function(delete_original) - local dir = oil.get_current_dir() + local dir = canola.get_current_dir() if not dir then return end diff --git a/lua/oil/columns.lua b/lua/canola/columns.lua similarity index 82% rename from lua/oil/columns.lua rename to lua/canola/columns.lua index ef95fdd..f616240 100644 --- a/lua/oil/columns.lua +++ b/lua/canola/columns.lua @@ -1,6 +1,6 @@ -local config = require('oil.config') -local constants = require('oil.constants') -local util = require('oil.util') +local config = require('canola.config') +local constants = require('canola.constants') +local util = require('canola.util') local M = {} local FIELD_NAME = constants.FIELD_NAME @@ -9,33 +9,33 @@ local FIELD_META = constants.FIELD_META local all_columns = {} ----@alias oil.ColumnSpec string|{[1]: string, [string]: any} +---@alias canola.ColumnSpec string|{[1]: string, [string]: any} ----@class (exact) oil.ColumnDefinition ----@field render fun(entry: oil.InternalEntry, conf: nil|table, bufnr: integer): nil|oil.TextChunk +---@class (exact) canola.ColumnDefinition +---@field render fun(entry: canola.InternalEntry, conf: nil|table, bufnr: integer): nil|canola.TextChunk ---@field parse fun(line: string, conf: nil|table): nil|string, nil|string ----@field compare? fun(entry: oil.InternalEntry, parsed_value: any): boolean ----@field render_action? fun(action: oil.ChangeAction): string ----@field perform_action? fun(action: oil.ChangeAction, callback: fun(err: nil|string)) ----@field get_sort_value? fun(entry: oil.InternalEntry): number|string ----@field create_sort_value_factory? fun(num_entries: integer): fun(entry: oil.InternalEntry): number|string +---@field compare? fun(entry: canola.InternalEntry, parsed_value: any): boolean +---@field render_action? fun(action: canola.ChangeAction): string +---@field perform_action? fun(action: canola.ChangeAction, callback: fun(err: nil|string)) +---@field get_sort_value? fun(entry: canola.InternalEntry): number|string +---@field create_sort_value_factory? fun(num_entries: integer): fun(entry: canola.InternalEntry): number|string ---@param name string ----@param column oil.ColumnDefinition +---@param column canola.ColumnDefinition M.register = function(name, column) all_columns[name] = column end ----@param adapter oil.Adapter ----@param defn oil.ColumnSpec ----@return nil|oil.ColumnDefinition +---@param adapter canola.Adapter +---@param defn canola.ColumnSpec +---@return nil|canola.ColumnDefinition M.get_column = function(adapter, defn) local name = util.split_config(defn) return all_columns[name] or adapter.get_column(name) end ----@param adapter_or_scheme string|oil.Adapter ----@return oil.ColumnSpec[] +---@param adapter_or_scheme string|canola.Adapter +---@return canola.ColumnSpec[] M.get_supported_columns = function(adapter_or_scheme) local adapter if type(adapter_or_scheme) == 'string' then @@ -53,15 +53,15 @@ M.get_supported_columns = function(adapter_or_scheme) return ret end -local EMPTY = { '-', 'OilEmpty' } +local EMPTY = { '-', 'CanolaEmpty' } M.EMPTY = EMPTY ----@param adapter oil.Adapter ----@param col_def oil.ColumnSpec ----@param entry oil.InternalEntry +---@param adapter canola.Adapter +---@param col_def canola.ColumnSpec +---@param entry canola.InternalEntry ---@param bufnr integer ----@return oil.TextChunk +---@return canola.TextChunk M.render_col = function(adapter, col_def, entry, bufnr) local name, conf = util.split_config(col_def) local column = M.get_column(adapter, name) @@ -90,9 +90,9 @@ M.render_col = function(adapter, col_def, entry, bufnr) return chunk end ----@param adapter oil.Adapter +---@param adapter canola.Adapter ---@param line string ----@param col_def oil.ColumnSpec +---@param col_def canola.ColumnSpec ---@return nil|string ---@return nil|string M.parse_col = function(adapter, line, col_def) @@ -108,9 +108,9 @@ M.parse_col = function(adapter, line, col_def) end end ----@param adapter oil.Adapter +---@param adapter canola.Adapter ---@param col_name string ----@param entry oil.InternalEntry +---@param entry canola.InternalEntry ---@param parsed_value any ---@return boolean M.compare = function(adapter, col_name, entry, parsed_value) @@ -122,8 +122,8 @@ M.compare = function(adapter, col_name, entry, parsed_value) end end ----@param adapter oil.Adapter ----@param action oil.ChangeAction +---@param adapter canola.Adapter +---@param action canola.ChangeAction ---@return string M.render_change_action = function(adapter, action) local column = M.get_column(adapter, action.column) @@ -137,8 +137,8 @@ M.render_change_action = function(adapter, action) end end ----@param adapter oil.Adapter ----@param action oil.ChangeAction +---@param adapter canola.Adapter +---@param action canola.ChangeAction ---@param callback fun(err: nil|string) M.perform_change_action = function(adapter, action, callback) local column = M.get_column(adapter, action.column) @@ -205,7 +205,7 @@ local default_type_icons = { directory = 'dir', socket = 'sock', } ----@param entry oil.InternalEntry +---@param entry canola.InternalEntry ---@return boolean local function is_entry_directory(entry) local type = entry[FIELD_TYPE] diff --git a/lua/oil/config.lua b/lua/canola/config.lua similarity index 70% rename from lua/oil/config.lua rename to lua/canola/config.lua index 7383920..607f4c0 100644 --- a/lua/oil/config.lua +++ b/lua/canola/config.lua @@ -1,21 +1,21 @@ local default_config = { - -- Oil will take over directory buffers (e.g. `vim .` or `:e src/`) + -- Canola will take over directory buffers (e.g. `vim .` or `:e src/`) -- Set to false if you want some other plugin (e.g. netrw) to open when you edit directories. default_file_explorer = true, -- Id is automatically added at the beginning, and name at the end - -- See :help oil-columns + -- See :help canola-columns columns = { 'icon', -- "permissions", -- "size", -- "mtime", }, - -- Buffer-local options to use for oil buffers + -- Buffer-local options to use for canola buffers buf_options = { buflisted = false, bufhidden = 'hide', }, - -- Window-local options to use for oil buffers + -- Window-local options to use for canola buffers win_options = { wrap = false, signcolumn = 'no', @@ -26,16 +26,16 @@ local default_config = { conceallevel = 3, concealcursor = 'nvic', }, - -- Send deleted files to the trash instead of permanently deleting them (:help oil-trash) + -- Send deleted files to the trash instead of permanently deleting them (:help canola-trash) delete_to_trash = false, - -- Skip the confirmation popup for simple operations (:help oil.skip_confirm_for_simple_edits) + -- Skip the confirmation popup for simple operations (:help canola.skip_confirm_for_simple_edits) skip_confirm_for_simple_edits = false, -- Selecting a new/moved/renamed file or directory will prompt you to save changes first -- (:help prompt_save_on_select_new_entry) prompt_save_on_select_new_entry = true, - -- Oil will automatically delete hidden buffers after this delay + -- Canola will automatically delete hidden buffers after this delay -- You can set the delay to false to disable cleanup entirely - -- Note that the cleanup process only starts when none of the oil buffers are currently displayed + -- Note that the cleanup process only starts when none of the canola buffers are currently displayed cleanup_delay_ms = 2000, lsp_file_methods = { -- Enable or disable LSP file operations @@ -46,17 +46,17 @@ local default_config = { -- Set to "unmodified" to only save unmodified buffers autosave_changes = false, }, - -- Constrain the cursor to the editable parts of the oil buffer + -- Constrain the cursor to the editable parts of the canola buffer -- Set to `false` to disable, or "name" to keep it on the file names constrain_cursor = 'editable', - -- Set to true to watch the filesystem for changes and reload oil + -- Set to true to watch the filesystem for changes and reload canola watch_for_changes = false, - -- Keymaps in oil buffer. Can be any value that `vim.keymap.set` accepts OR a table of keymap + -- Keymaps in canola buffer. Can be any value that `vim.keymap.set` accepts OR a table of keymap -- options with a `callback` (e.g. { callback = function() ... end, desc = "", mode = "n" }) -- Additionally, if it is a string that matches "actions.", - -- it will use the mapping at require("oil.actions"). + -- it will use the mapping at require("canola.actions"). -- Set to `false` to remove a keymap - -- See :help oil-actions for a list of all available actions + -- See :help canola-actions for a list of all available actions keymaps = { ['g?'] = { 'actions.show_help', mode = 'n' }, [''] = 'actions.select', @@ -96,7 +96,7 @@ local default_config = { case_insensitive = false, sort = { -- sort order can be "asc" or "desc" - -- see :help oil-columns to see which columns are sortable + -- see :help canola-columns to see which columns are sortable { 'type', 'asc' }, { 'name', 'asc' }, }, @@ -124,7 +124,7 @@ local default_config = { return false end, }, - -- Configuration for the floating window in oil.open_float + -- Configuration for the floating window in canola.open_float float = { -- Padding around the floating window padding = 2, @@ -135,7 +135,7 @@ local default_config = { win_options = { winblend = 0, }, - -- optionally override the oil buffers window title with custom function: fun(winid: integer): string + -- optionally override the canola buffers window title with custom function: fun(winid: integer): string get_win_title = nil, -- preview_split: Split direction: "auto", "left", "right", "above", "below". preview_split = 'auto', @@ -209,177 +209,177 @@ local default_config = { -- write their own adapters, and so there's no real reason to edit these config options. For that -- reason, I'm taking them out of the section above so they won't show up in the autogen docs. --- not "oil-s3://" on older neovim versions, since it doesn't open buffers correctly with a number +-- not "canola-s3://" on older neovim versions, since it doesn't open buffers correctly with a number -- in the name -local oil_s3_string = vim.fn.has('nvim-0.12') == 1 and 'oil-s3://' or 'oil-sss://' +local canola_s3_string = vim.fn.has('nvim-0.12') == 1 and 'canola-s3://' or 'canola-sss://' default_config.adapters = { - ['oil://'] = 'files', - ['oil-ssh://'] = 'ssh', - [oil_s3_string] = 's3', - ['oil-trash://'] = 'trash', + ['canola://'] = 'files', + ['canola-ssh://'] = 'ssh', + [canola_s3_string] = 's3', + ['canola-trash://'] = 'trash', } default_config.adapter_aliases = {} -- We want the function in the default config for documentation generation, but if we nil it out -- here we can get some performance wins default_config.view_options.highlight_filename = nil ----@class oil.Config +---@class canola.Config ---@field adapters table Hidden from SetupOpts ---@field adapter_aliases table Hidden from SetupOpts ---@field silence_scp_warning? boolean Undocumented option ---@field default_file_explorer boolean ----@field columns oil.ColumnSpec[] +---@field columns canola.ColumnSpec[] ---@field buf_options table ---@field win_options table ---@field delete_to_trash boolean ---@field skip_confirm_for_simple_edits boolean ---@field prompt_save_on_select_new_entry boolean ---@field cleanup_delay_ms integer ----@field lsp_file_methods oil.LspFileMethods +---@field lsp_file_methods canola.LspFileMethods ---@field constrain_cursor false|"name"|"editable" ---@field watch_for_changes boolean ---@field keymaps table ---@field use_default_keymaps boolean ----@field view_options oil.ViewOptions +---@field view_options canola.ViewOptions ---@field new_file_mode integer ---@field new_dir_mode integer ---@field extra_scp_args string[] ---@field extra_s3_args string[] ----@field git oil.GitOptions ----@field float oil.FloatWindowConfig ----@field preview_win oil.PreviewWindowConfig ----@field confirmation oil.ConfirmationWindowConfig ----@field progress oil.ProgressWindowConfig ----@field ssh oil.SimpleWindowConfig ----@field keymaps_help oil.SimpleWindowConfig +---@field git canola.GitOptions +---@field float canola.FloatWindowConfig +---@field preview_win canola.PreviewWindowConfig +---@field confirmation canola.ConfirmationWindowConfig +---@field progress canola.ProgressWindowConfig +---@field ssh canola.SimpleWindowConfig +---@field keymaps_help canola.SimpleWindowConfig local M = {} -- For backwards compatibility ----@alias oil.setupOpts oil.SetupOpts +---@alias canola.setupOpts canola.SetupOpts ----@class (exact) oil.SetupOpts ----@field default_file_explorer? boolean Oil will take over directory buffers (e.g. `vim .` or `:e src/`). Set to false if you still want to use netrw. ----@field columns? oil.ColumnSpec[] The columns to display. See :help oil-columns. ----@field buf_options? table Buffer-local options to use for oil buffers ----@field win_options? table Window-local options to use for oil buffers ----@field delete_to_trash? boolean Send deleted files to the trash instead of permanently deleting them (:help oil-trash). ----@field skip_confirm_for_simple_edits? boolean Skip the confirmation popup for simple operations (:help oil.skip_confirm_for_simple_edits). +---@class (exact) canola.SetupOpts +---@field default_file_explorer? boolean Canola will take over directory buffers (e.g. `vim .` or `:e src/`). Set to false if you still want to use netrw. +---@field columns? canola.ColumnSpec[] The columns to display. See :help canola-columns. +---@field buf_options? table Buffer-local options to use for canola buffers +---@field win_options? table Window-local options to use for canola buffers +---@field delete_to_trash? boolean Send deleted files to the trash instead of permanently deleting them (:help canola-trash). +---@field skip_confirm_for_simple_edits? boolean Skip the confirmation popup for simple operations (:help canola.skip_confirm_for_simple_edits). ---@field prompt_save_on_select_new_entry? boolean Selecting a new/moved/renamed file or directory will prompt you to save changes first (:help prompt_save_on_select_new_entry). ----@field cleanup_delay_ms? integer Oil will automatically delete hidden buffers after this delay. You can set the delay to false to disable cleanup entirely. Note that the cleanup process only starts when none of the oil buffers are currently displayed. ----@field lsp_file_methods? oil.SetupLspFileMethods Configure LSP file operation integration. ----@field constrain_cursor? false|"name"|"editable" Constrain the cursor to the editable parts of the oil buffer. Set to `false` to disable, or "name" to keep it on the file names. ----@field watch_for_changes? boolean Set to true to watch the filesystem for changes and reload oil. +---@field cleanup_delay_ms? integer Canola will automatically delete hidden buffers after this delay. You can set the delay to false to disable cleanup entirely. Note that the cleanup process only starts when none of the canola buffers are currently displayed. +---@field lsp_file_methods? canola.SetupLspFileMethods Configure LSP file operation integration. +---@field constrain_cursor? false|"name"|"editable" Constrain the cursor to the editable parts of the canola buffer. Set to `false` to disable, or "name" to keep it on the file names. +---@field watch_for_changes? boolean Set to true to watch the filesystem for changes and reload canola. ---@field keymaps? table ---@field use_default_keymaps? boolean Set to false to disable all of the above keymaps ----@field view_options? oil.SetupViewOptions Configure which files are shown and how they are shown. +---@field view_options? canola.SetupViewOptions Configure which files are shown and how they are shown. ---@field new_file_mode? integer Permission mode for new files in decimal (default 420 = 0644) ---@field new_dir_mode? integer Permission mode for new directories in decimal (default 493 = 0755) ---@field extra_scp_args? string[] Extra arguments to pass to SCP when moving/copying files over SSH ---@field extra_s3_args? string[] Extra arguments to pass to aws s3 when moving/copying files using aws s3 ----@field git? oil.SetupGitOptions EXPERIMENTAL support for performing file operations with git ----@field float? oil.SetupFloatWindowConfig Configuration for the floating window in oil.open_float ----@field preview_win? oil.SetupPreviewWindowConfig Configuration for the file preview window ----@field confirmation? oil.SetupConfirmationWindowConfig Configuration for the floating action confirmation window ----@field progress? oil.SetupProgressWindowConfig Configuration for the floating progress window ----@field ssh? oil.SetupSimpleWindowConfig Configuration for the floating SSH window ----@field keymaps_help? oil.SetupSimpleWindowConfig Configuration for the floating keymaps help window +---@field git? canola.SetupGitOptions EXPERIMENTAL support for performing file operations with git +---@field float? canola.SetupFloatWindowConfig Configuration for the floating window in canola.open_float +---@field preview_win? canola.SetupPreviewWindowConfig Configuration for the file preview window +---@field confirmation? canola.SetupConfirmationWindowConfig Configuration for the floating action confirmation window +---@field progress? canola.SetupProgressWindowConfig Configuration for the floating progress window +---@field ssh? canola.SetupSimpleWindowConfig Configuration for the floating SSH window +---@field keymaps_help? canola.SetupSimpleWindowConfig Configuration for the floating keymaps help window ----@class (exact) oil.LspFileMethods +---@class (exact) canola.LspFileMethods ---@field enabled boolean ---@field timeout_ms integer ---@field autosave_changes boolean|"unmodified" Set to true to autosave buffers that are updated with LSP willRenameFiles. Set to "unmodified" to only save unmodified buffers. ----@class (exact) oil.SetupLspFileMethods +---@class (exact) canola.SetupLspFileMethods ---@field enabled? boolean Enable or disable LSP file operations ---@field timeout_ms? integer Time to wait for LSP file operations to complete before skipping. ---@field autosave_changes? boolean|"unmodified" Set to true to autosave buffers that are updated with LSP willRenameFiles. Set to "unmodified" to only save unmodified buffers. ----@class (exact) oil.ViewOptions +---@class (exact) canola.ViewOptions ---@field show_hidden boolean ----@field is_hidden_file fun(name: string, bufnr: integer, entry: oil.Entry): boolean ----@field is_always_hidden fun(name: string, bufnr: integer, entry: oil.Entry): boolean +---@field is_hidden_file fun(name: string, bufnr: integer, entry: canola.Entry): boolean +---@field is_always_hidden fun(name: string, bufnr: integer, entry: canola.Entry): boolean ---@field natural_order boolean|"fast" ---@field case_insensitive boolean ----@field sort oil.SortSpec[] ----@field highlight_filename? fun(entry: oil.Entry, is_hidden: boolean, is_link_target: boolean, is_link_orphan: boolean, bufnr: integer): string|nil +---@field sort canola.SortSpec[] +---@field highlight_filename? fun(entry: canola.Entry, is_hidden: boolean, is_link_target: boolean, is_link_orphan: boolean, bufnr: integer): string|nil ----@class (exact) oil.SetupViewOptions +---@class (exact) canola.SetupViewOptions ---@field show_hidden? boolean Show files and directories that start with "." ---@field is_hidden_file? fun(name: string, bufnr: integer): boolean This function defines what is considered a "hidden" file ---@field is_always_hidden? fun(name: string, bufnr: integer): boolean This function defines what will never be shown, even when `show_hidden` is set ---@field natural_order? boolean|"fast" Sort file names with numbers in a more intuitive order for humans. Can be slow for large directories. ---@field case_insensitive? boolean Sort file and directory names case insensitive ----@field sort? oil.SortSpec[] Sort order for the file list ----@field highlight_filename? fun(entry: oil.Entry, is_hidden: boolean, is_link_target: boolean, is_link_orphan: boolean): string|nil Customize the highlight group for the file name +---@field sort? canola.SortSpec[] Sort order for the file list +---@field highlight_filename? fun(entry: canola.Entry, is_hidden: boolean, is_link_target: boolean, is_link_orphan: boolean): string|nil Customize the highlight group for the file name ----@class (exact) oil.SortSpec +---@class (exact) canola.SortSpec ---@field [1] string ---@field [2] "asc"|"desc" ----@class (exact) oil.GitOptions +---@class (exact) canola.GitOptions ---@field add fun(path: string): boolean ---@field mv fun(src_path: string, dest_path: string): boolean ---@field rm fun(path: string): boolean ----@class (exact) oil.SetupGitOptions +---@class (exact) canola.SetupGitOptions ---@field add? fun(path: string): boolean Return true to automatically git add a new file ---@field mv? fun(src_path: string, dest_path: string): boolean Return true to automatically git mv a moved file ---@field rm? fun(path: string): boolean Return true to automatically git rm a deleted file ----@class (exact) oil.WindowDimensionDualConstraint +---@class (exact) canola.WindowDimensionDualConstraint ---@field [1] number ---@field [2] number ----@alias oil.WindowDimension number|oil.WindowDimensionDualConstraint +---@alias canola.WindowDimension number|canola.WindowDimensionDualConstraint ----@class (exact) oil.WindowConfig ----@field max_width oil.WindowDimension ----@field min_width oil.WindowDimension +---@class (exact) canola.WindowConfig +---@field max_width canola.WindowDimension +---@field min_width canola.WindowDimension ---@field width? number ----@field max_height oil.WindowDimension ----@field min_height oil.WindowDimension +---@field max_height canola.WindowDimension +---@field min_height canola.WindowDimension ---@field height? number ---@field border string|string[] ---@field win_options table ----@class (exact) oil.SetupWindowConfig ----@field max_width? oil.WindowDimension Width dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%). Can be a single value or a list of mixed integer/float types. max_width = {100, 0.8} means "the lesser of 100 columns or 80% of total" ----@field min_width? oil.WindowDimension Width dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%). Can be a single value or a list of mixed integer/float types. min_width = {40, 0.4} means "the greater of 40 columns or 40% of total" +---@class (exact) canola.SetupWindowConfig +---@field max_width? canola.WindowDimension Width dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%). Can be a single value or a list of mixed integer/float types. max_width = {100, 0.8} means "the lesser of 100 columns or 80% of total" +---@field min_width? canola.WindowDimension Width dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%). Can be a single value or a list of mixed integer/float types. min_width = {40, 0.4} means "the greater of 40 columns or 40% of total" ---@field width? number Define an integer/float for the exact width of the preview window ----@field max_height? oil.WindowDimension Height dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%). Can be a single value or a list of mixed integer/float types. max_height = {80, 0.9} means "the lesser of 80 columns or 90% of total" ----@field min_height? oil.WindowDimension Height dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%). Can be a single value or a list of mixed integer/float types. min_height = {5, 0.1} means "the greater of 5 columns or 10% of total" +---@field max_height? canola.WindowDimension Height dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%). Can be a single value or a list of mixed integer/float types. max_height = {80, 0.9} means "the lesser of 80 columns or 90% of total" +---@field min_height? canola.WindowDimension Height dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%). Can be a single value or a list of mixed integer/float types. min_height = {5, 0.1} means "the greater of 5 columns or 10% of total" ---@field height? number Define an integer/float for the exact height of the preview window ---@field border? string|string[] Window border ---@field win_options? table ----@alias oil.PreviewMethod +---@alias canola.PreviewMethod ---| '"load"' # Load the previewed file into a buffer ---| '"scratch"' # Put the text into a scratch buffer to avoid LSP attaching ---| '"fast_scratch"' # Put only the visible text into a scratch buffer ----@class (exact) oil.PreviewWindowConfig +---@class (exact) canola.PreviewWindowConfig ---@field update_on_cursor_moved boolean ----@field preview_method oil.PreviewMethod +---@field preview_method canola.PreviewMethod ---@field disable_preview fun(filename: string): boolean ---@field win_options table ----@class (exact) oil.ConfirmationWindowConfig : oil.WindowConfig +---@class (exact) canola.ConfirmationWindowConfig : canola.WindowConfig ----@class (exact) oil.SetupPreviewWindowConfig +---@class (exact) canola.SetupPreviewWindowConfig ---@field update_on_cursor_moved? boolean Whether the preview window is automatically updated when the cursor is moved ---@field disable_preview? fun(filename: string): boolean A function that returns true to disable preview on a file e.g. to avoid lag ----@field preview_method? oil.PreviewMethod How to open the preview window +---@field preview_method? canola.PreviewMethod How to open the preview window ---@field win_options? table Window-local options to use for preview window buffers ----@class (exact) oil.SetupConfirmationWindowConfig : oil.SetupWindowConfig +---@class (exact) canola.SetupConfirmationWindowConfig : canola.SetupWindowConfig ----@class (exact) oil.ProgressWindowConfig : oil.WindowConfig +---@class (exact) canola.ProgressWindowConfig : canola.WindowConfig ---@field minimized_border string|string[] ----@class (exact) oil.SetupProgressWindowConfig : oil.SetupWindowConfig +---@class (exact) canola.SetupProgressWindowConfig : canola.SetupWindowConfig ---@field minimized_border? string|string[] The border for the minimized progress window ----@class (exact) oil.FloatWindowConfig +---@class (exact) canola.FloatWindowConfig ---@field padding integer ---@field max_width integer ---@field max_height integer @@ -389,7 +389,7 @@ local M = {} ---@field preview_split "auto"|"left"|"right"|"above"|"below" ---@field override fun(conf: table): table ----@class (exact) oil.SetupFloatWindowConfig +---@class (exact) canola.SetupFloatWindowConfig ---@field padding? integer ---@field max_width? integer ---@field max_height? integer @@ -399,14 +399,14 @@ local M = {} ---@field preview_split? "auto"|"left"|"right"|"above"|"below" Direction that the preview command will split the window ---@field override? fun(conf: table): table ----@class (exact) oil.SimpleWindowConfig +---@class (exact) canola.SimpleWindowConfig ---@field border string|string[] ----@class (exact) oil.SetupSimpleWindowConfig +---@class (exact) canola.SetupSimpleWindowConfig ---@field border? string|string[] Window border M.setup = function(opts) - opts = opts or vim.g.oil or {} + opts = opts or vim.g.canola or {} local new_conf = vim.tbl_deep_extend('keep', opts, default_config) if not new_conf.use_default_keymaps then @@ -452,7 +452,7 @@ M.setup = function(opts) new_conf.lsp_file_methods.autosave_changes = new_conf.lsp_rename_autosave new_conf.lsp_rename_autosave = nil vim.notify_once( - 'oil config value lsp_rename_autosave has moved to lsp_file_methods.autosave_changes.\nCompatibility will be removed on 2024-09-01.', + 'canola config value lsp_rename_autosave has moved to lsp_file_methods.autosave_changes.\nCompatibility will be removed on 2024-09-01.', vim.log.levels.WARN ) end @@ -474,7 +474,7 @@ M.setup = function(opts) end ---@param scheme nil|string ----@return nil|oil.Adapter +---@return nil|canola.Adapter M.get_adapter_by_scheme = function(scheme) if not scheme then return nil @@ -494,7 +494,7 @@ M.get_adapter_by_scheme = function(scheme) return nil end local ok - ok, adapter = pcall(require, string.format('oil.adapters.%s', name)) + ok, adapter = pcall(require, string.format('canola.adapters.%s', name)) if ok then adapter.name = name M._adapter_by_scheme[scheme] = adapter diff --git a/lua/oil/constants.lua b/lua/canola/constants.lua similarity index 63% rename from lua/oil/constants.lua rename to lua/canola/constants.lua index 3f5a38a..9427837 100644 --- a/lua/oil/constants.lua +++ b/lua/canola/constants.lua @@ -2,9 +2,9 @@ local M = {} ---Store entries as a list-like table for maximum space efficiency and retrieval speed. ---We use the constants below to index into the table. ----@alias oil.InternalEntry {[1]: integer, [2]: string, [3]: oil.EntryType, [4]: nil|table} +---@alias canola.InternalEntry {[1]: integer, [2]: string, [3]: canola.EntryType, [4]: nil|table} --- Indexes into oil.InternalEntry +-- Indexes into canola.InternalEntry M.FIELD_ID = 1 M.FIELD_NAME = 2 M.FIELD_TYPE = 3 diff --git a/lua/oil/fs.lua b/lua/canola/fs.lua similarity index 97% rename from lua/oil/fs.lua rename to lua/canola/fs.lua index 6cb084c..e7daa77 100644 --- a/lua/oil/fs.lua +++ b/lua/canola/fs.lua @@ -1,4 +1,4 @@ -local log = require('oil.log') +local log = require('canola.log') local M = {} local uv = vim.uv or vim.loop @@ -170,7 +170,7 @@ M.mkdirp = function(dir, mode) end ---@param dir string ----@param cb fun(err: nil|string, entries: nil|{type: oil.EntryType, name: string}) +---@param cb fun(err: nil|string, entries: nil|{type: canola.EntryType, name: string}) M.listdir = function(dir, cb) ---@diagnostic disable-next-line: param-type-mismatch, discard-returns uv.fs_opendir(dir, function(open_err, fd) @@ -205,7 +205,7 @@ M.listdir = function(dir, cb) end, 10000) end ----@param entry_type oil.EntryType +---@param entry_type canola.EntryType ---@param path string ---@param cb fun(err: nil|string) M.recursive_delete = function(entry_type, path, cb) @@ -285,7 +285,7 @@ local move_undofile = vim.schedule_wrap(function(src_path, dest_path, copy) ) end) ----@param entry_type oil.EntryType +---@param entry_type canola.EntryType ---@param src_path string ---@param dest_path string ---@param cb fun(err: nil|string) @@ -357,7 +357,7 @@ M.recursive_copy = function(entry_type, src_path, dest_path, cb) end) end ----@param entry_type oil.EntryType +---@param entry_type canola.EntryType ---@param src_path string ---@param dest_path string ---@param cb fun(err: nil|string) diff --git a/lua/oil/git.lua b/lua/canola/git.lua similarity index 97% rename from lua/oil/git.lua rename to lua/canola/git.lua index 9fab6e4..747c123 100644 --- a/lua/oil/git.lua +++ b/lua/canola/git.lua @@ -1,5 +1,5 @@ -- integration with git operations -local fs = require('oil.fs') +local fs = require('canola.fs') local M = {} @@ -75,7 +75,7 @@ M.rm = function(path, cb) end end ----@param entry_type oil.EntryType +---@param entry_type canola.EntryType ---@param src_path string ---@param dest_path string ---@param cb fun(err: nil|string) diff --git a/lua/oil/init.lua b/lua/canola/init.lua similarity index 70% rename from lua/oil/init.lua rename to lua/canola/init.lua index d3e6223..81837fa 100644 --- a/lua/oil/init.lua +++ b/lua/canola/init.lua @@ -1,44 +1,44 @@ local M = {} ----@class (exact) oil.Entry +---@class (exact) canola.Entry ---@field name string ----@field type oil.EntryType +---@field type canola.EntryType ---@field id nil|integer Will be nil if it hasn't been persisted to disk yet ---@field parsed_name nil|string ---@field meta nil|table ----@alias oil.EntryType uv.aliases.fs_types ----@alias oil.HlRange { [1]: string, [2]: integer, [3]: integer } A tuple of highlight group name, col_start, col_end ----@alias oil.HlTuple { [1]: string, [2]: string } A tuple of text, highlight group ----@alias oil.HlRangeTuple { [1]: string, [2]: oil.HlRange[] } A tuple of text, internal highlights ----@alias oil.TextChunk string|oil.HlTuple|oil.HlRangeTuple ----@alias oil.CrossAdapterAction "copy"|"move" +---@alias canola.EntryType uv.aliases.fs_types +---@alias canola.HlRange { [1]: string, [2]: integer, [3]: integer } A tuple of highlight group name, col_start, col_end +---@alias canola.HlTuple { [1]: string, [2]: string } A tuple of text, highlight group +---@alias canola.HlRangeTuple { [1]: string, [2]: canola.HlRange[] } A tuple of text, internal highlights +---@alias canola.TextChunk string|canola.HlTuple|canola.HlRangeTuple +---@alias canola.CrossAdapterAction "copy"|"move" ----@class (exact) oil.Adapter +---@class (exact) canola.Adapter ---@field name string The unique name of the adapter (this will be set automatically) ----@field list fun(path: string, column_defs: string[], cb: fun(err?: string, entries?: oil.InternalEntry[], fetch_more?: fun())) Async function to list a directory. +---@field list fun(path: string, column_defs: string[], cb: fun(err?: string, entries?: canola.InternalEntry[], fetch_more?: fun())) Async function to list a directory. ---@field is_modifiable fun(bufnr: integer): boolean Return true if this directory is modifiable (allows for directories with read-only permissions). ----@field get_column fun(name: string): nil|oil.ColumnDefinition If the adapter has any adapter-specific columns, return them when fetched by name. +---@field get_column fun(name: string): nil|canola.ColumnDefinition If the adapter has any adapter-specific columns, return them when fetched by name. ---@field get_parent? fun(bufname: string): string Get the parent url of the given buffer ----@field normalize_url fun(url: string, callback: fun(url: string)) Before oil opens a url it will be normalized. This allows for link following, path normalizing, and converting an oil file url to the actual path of a file. ----@field get_entry_path? fun(url: string, entry: oil.Entry, callback: fun(path: string)) Similar to normalize_url, but used when selecting an entry ----@field render_action? fun(action: oil.Action): string Render a mutation action for display in the preview window. Only needed if adapter is modifiable. ----@field perform_action? fun(action: oil.Action, cb: fun(err: nil|string)) Perform a mutation action. Only needed if adapter is modifiable. +---@field normalize_url fun(url: string, callback: fun(url: string)) Before canola opens a url it will be normalized. This allows for link following, path normalizing, and converting an canola file url to the actual path of a file. +---@field get_entry_path? fun(url: string, entry: canola.Entry, callback: fun(path: string)) Similar to normalize_url, but used when selecting an entry +---@field render_action? fun(action: canola.Action): string Render a mutation action for display in the preview window. Only needed if adapter is modifiable. +---@field perform_action? fun(action: canola.Action, cb: fun(err: nil|string)) Perform a mutation action. Only needed if adapter is modifiable. ---@field read_file? fun(bufnr: integer) Used for adapters that deal with remote/virtual files. Read the contents of the file into a buffer. ---@field write_file? fun(bufnr: integer) Used for adapters that deal with remote/virtual files. Write the contents of a buffer to the destination. ----@field supported_cross_adapter_actions? table Mapping of adapter name to enum for all other adapters that can be used as a src or dest for move/copy actions. ----@field filter_action? fun(action: oil.Action): boolean When present, filter out actions as they are created ----@field filter_error? fun(action: oil.ParseError): boolean When present, filter out errors from parsing a buffer +---@field supported_cross_adapter_actions? table Mapping of adapter name to enum for all other adapters that can be used as a src or dest for move/copy actions. +---@field filter_action? fun(action: canola.Action): boolean When present, filter out actions as they are created +---@field filter_error? fun(action: canola.ParseError): boolean When present, filter out errors from parsing a buffer ---Get the entry on a specific line (1-indexed) ---@param bufnr integer ---@param lnum integer ----@return nil|oil.Entry +---@return nil|canola.Entry M.get_entry_on_line = function(bufnr, lnum) - local columns = require('oil.columns') - local parser = require('oil.mutator.parser') - local util = require('oil.util') - if vim.bo[bufnr].filetype ~= 'oil' then + local columns = require('canola.columns') + local parser = require('canola.mutator.parser') + local util = require('canola.util') + if vim.bo[bufnr].filetype ~= 'canola' then return nil end local adapter = util.get_adapter(bufnr) @@ -87,22 +87,22 @@ M.get_entry_on_line = function(bufnr, lnum) end ---Get the entry currently under the cursor ----@return nil|oil.Entry +---@return nil|canola.Entry M.get_cursor_entry = function() local lnum = vim.api.nvim_win_get_cursor(0)[1] return M.get_entry_on_line(0, lnum) end ----Discard all changes made to oil buffers +---Discard all changes made to canola buffers M.discard_all_changes = function() - local view = require('oil.view') + local view = require('canola.view') for _, bufnr in ipairs(view.get_all_buffers()) do if vim.bo[bufnr].modified then view.render_buffer_async(bufnr, {}, function(err) if err then vim.notify( string.format( - 'Error rendering oil buffer %s: %s', + 'Error rendering canola buffer %s: %s', vim.api.nvim_buf_get_name(bufnr), err ), @@ -114,38 +114,38 @@ M.discard_all_changes = function() end end ----Change the display columns for oil ----@param cols oil.ColumnSpec[] +---Change the display columns for canola +---@param cols canola.ColumnSpec[] M.set_columns = function(cols) - require('oil.view').set_columns(cols) + require('canola.view').set_columns(cols) end ----Change the sort order for oil ----@param sort oil.SortSpec[] List of columns plus direction. See :help oil-columns to see which ones are sortable. +---Change the sort order for canola +---@param sort canola.SortSpec[] List of columns plus direction. See :help canola-columns to see which ones are sortable. ---@example ---- require("oil").set_sort({ { "type", "asc" }, { "size", "desc" } }) +--- require("canola").set_sort({ { "type", "asc" }, { "size", "desc" } }) M.set_sort = function(sort) - require('oil.view').set_sort(sort) + require('canola.view').set_sort(sort) end ----Change how oil determines if the file is hidden ----@param is_hidden_file fun(filename: string, bufnr: integer, entry: oil.Entry): boolean Return true if the file/dir should be hidden +---Change how canola determines if the file is hidden +---@param is_hidden_file fun(filename: string, bufnr: integer, entry: canola.Entry): boolean Return true if the file/dir should be hidden M.set_is_hidden_file = function(is_hidden_file) - require('oil.view').set_is_hidden_file(is_hidden_file) + require('canola.view').set_is_hidden_file(is_hidden_file) end ---Toggle hidden files and directories M.toggle_hidden = function() - require('oil.view').toggle_hidden() + require('canola.view').toggle_hidden() end ---Get the current directory ---@param bufnr? integer ---@return nil|string M.get_current_dir = function(bufnr) - local config = require('oil.config') - local fs = require('oil.fs') - local util = require('oil.util') + local config = require('canola.config') + local fs = require('canola.fs') + local util = require('canola.util') local buf_name = vim.api.nvim_buf_get_name(bufnr or 0) local scheme, path = util.parse_url(buf_name) if config.adapters[scheme] == 'files' then @@ -154,19 +154,19 @@ M.get_current_dir = function(bufnr) end end ----Get the oil url for a given directory +---Get the canola url for a given directory ---@private ---@param dir nil|string When nil, use the cwd ----@param use_oil_parent nil|boolean If in an oil buffer, return the parent (default true) +---@param use_canola_parent nil|boolean If in an canola buffer, return the parent (default true) ---@return string The parent url ---@return nil|string The basename (if present) of the file/dir we were just in -M.get_url_for_path = function(dir, use_oil_parent) - if use_oil_parent == nil then - use_oil_parent = true +M.get_url_for_path = function(dir, use_canola_parent) + if use_canola_parent == nil then + use_canola_parent = true end - local config = require('oil.config') - local fs = require('oil.fs') - local util = require('oil.util') + local config = require('canola.config') + local fs = require('canola.fs') + local util = require('canola.util') if vim.bo.filetype == 'netrw' and not dir then dir = vim.b.netrw_curdir end @@ -180,20 +180,20 @@ M.get_url_for_path = function(dir, use_oil_parent) return config.adapter_to_scheme.files .. path else local bufname = vim.api.nvim_buf_get_name(0) - return M.get_buffer_parent_url(bufname, use_oil_parent) + return M.get_buffer_parent_url(bufname, use_canola_parent) end end ---@private ---@param bufname string ----@param use_oil_parent boolean If in an oil buffer, return the parent +---@param use_canola_parent boolean If in an canola buffer, return the parent ---@return string ---@return nil|string -M.get_buffer_parent_url = function(bufname, use_oil_parent) - local config = require('oil.config') - local fs = require('oil.fs') - local pathutil = require('oil.pathutil') - local util = require('oil.util') +M.get_buffer_parent_url = function(bufname, use_canola_parent) + local config = require('canola.config') + local fs = require('canola.fs') + local pathutil = require('canola.pathutil') + local util = require('canola.util') local scheme, path = util.parse_url(bufname) if not scheme then local parent, basename @@ -219,7 +219,7 @@ M.get_buffer_parent_url = function(bufname, use_oil_parent) return vim.fn.getcwd() end - if not use_oil_parent then + if not use_canola_parent then return bufname end local adapter = assert(config.get_adapter_by_scheme(scheme)) @@ -239,19 +239,19 @@ M.get_buffer_parent_url = function(bufname, use_oil_parent) end end ----@class (exact) oil.OpenOpts ----@field preview? oil.OpenPreviewOpts When present, open the preview window after opening oil +---@class (exact) canola.OpenOpts +---@field preview? canola.OpenPreviewOpts When present, open the preview window after opening canola ----Open oil browser in a floating window +---Open canola browser in a floating window ---@param dir? string When nil, open the parent of the current buffer, or the cwd if current buffer is not a file ----@param opts? oil.OpenOpts ----@param cb? fun() Called after the oil buffer is ready +---@param opts? canola.OpenOpts +---@param cb? fun() Called after the canola buffer is ready M.open_float = function(dir, opts, cb) opts = opts or {} - local config = require('oil.config') - local layout = require('oil.layout') - local util = require('oil.util') - local view = require('oil.view') + local config = require('canola.config') + local layout = require('canola.layout') + local util = require('canola.util') + local view = require('canola.view') local parent_url, basename = M.get_url_for_path(dir) if basename then @@ -264,8 +264,8 @@ M.open_float = function(dir, opts, cb) local original_winid = vim.api.nvim_get_current_win() local winid = vim.api.nvim_open_win(bufnr, true, win_opts) - vim.w[winid].is_oil_win = true - vim.w[winid].oil_original_win = original_winid + vim.w[winid].is_canola_win = true + vim.w[winid].canola_original_win = original_winid for k, v in pairs(config.float.win_options) do vim.api.nvim_set_option_value(k, v, { scope = 'local', win = winid }) end @@ -273,8 +273,8 @@ M.open_float = function(dir, opts, cb) table.insert( autocmds, vim.api.nvim_create_autocmd('WinLeave', { - desc = 'Close floating oil window', - group = 'Oil', + desc = 'Close floating canola window', + group = 'Canola', callback = vim.schedule_wrap(function() if util.is_floating_win() or vim.fn.win_gettype() == 'command' then return @@ -294,7 +294,7 @@ M.open_float = function(dir, opts, cb) table.insert( autocmds, vim.api.nvim_create_autocmd('BufWinEnter', { - desc = 'Reset local oil window options when buffer changes', + desc = 'Reset local canola window options when buffer changes', pattern = '*', callback = function(params) local winbuf = params.buf @@ -340,12 +340,12 @@ M.open_float = function(dir, opts, cb) end end ----Open oil browser in a floating window, or close it if open +---Open canola browser in a floating window, or close it if open ---@param dir nil|string When nil, open the parent of the current buffer, or the cwd if current buffer is not a file ----@param opts? oil.OpenOpts ----@param cb? fun() Called after the oil buffer is ready +---@param opts? canola.OpenOpts +---@param cb? fun() Called after the canola buffer is ready M.toggle_float = function(dir, opts, cb) - if vim.w.is_oil_win then + if vim.w.is_canola_win then M.close() if cb then cb() @@ -355,32 +355,32 @@ M.toggle_float = function(dir, opts, cb) end end ----@param oil_bufnr? integer -local function update_preview_window(oil_bufnr) - oil_bufnr = oil_bufnr or 0 - local util = require('oil.util') - util.run_after_load(oil_bufnr, function() +---@param canola_bufnr? integer +local function update_preview_window(canola_bufnr) + canola_bufnr = canola_bufnr or 0 + local util = require('canola.util') + util.run_after_load(canola_bufnr, function() local cursor_entry = M.get_cursor_entry() local preview_win_id = util.get_preview_win() if cursor_entry and preview_win_id - and cursor_entry.id ~= vim.w[preview_win_id].oil_entry_id + and cursor_entry.id ~= vim.w[preview_win_id].canola_entry_id then M.open_preview() end end) end ----Open oil browser for a directory +---Open canola browser for a directory ---@param dir? string When nil, open the parent of the current buffer, or the cwd if current buffer is not a file ----@param opts? oil.OpenOpts ----@param cb? fun() Called after the oil buffer is ready +---@param opts? canola.OpenOpts +---@param cb? fun() Called after the canola buffer is ready M.open = function(dir, opts, cb) opts = opts or {} - local config = require('oil.config') - local util = require('oil.util') - local view = require('oil.view') + local config = require('canola.config') + local util = require('canola.util') + local view = require('canola.view') local parent_url, basename = M.get_url_for_path(dir) if basename then view.set_last_cursor(parent_url, basename) @@ -403,11 +403,11 @@ M.open = function(dir, opts, cb) update_preview_window() end ----@class oil.CloseOpts ----@field exit_if_last_buf? boolean Exit vim if this oil buffer is the last open buffer +---@class canola.CloseOpts +---@field exit_if_last_buf? boolean Exit vim if this canola buffer is the last open buffer ----Restore the buffer that was present when oil was opened ----@param opts? oil.CloseOpts +---Restore the buffer that was present when canola was opened +---@param opts? canola.CloseOpts M.close = function(opts) opts = opts or {} local mode = vim.api.nvim_get_mode().mode @@ -415,27 +415,27 @@ M.close = function(opts) vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, true, true), 'n', false) return end - -- If we're in a floating oil window, close it and try to restore focus to the original window - if vim.w.is_oil_win then - local original_winid = vim.w.oil_original_win + -- If we're in a floating canola window, close it and try to restore focus to the original window + if vim.w.is_canola_win then + local original_winid = vim.w.canola_original_win vim.api.nvim_win_close(0, true) if original_winid and vim.api.nvim_win_is_valid(original_winid) then vim.api.nvim_set_current_win(original_winid) end return end - local ok, bufnr = pcall(vim.api.nvim_win_get_var, 0, 'oil_original_buffer') + local ok, bufnr = pcall(vim.api.nvim_win_get_var, 0, 'canola_original_buffer') if ok and vim.api.nvim_buf_is_valid(bufnr) then vim.api.nvim_win_set_buf(0, bufnr) - if vim.w.oil_original_view then - vim.fn.winrestview(vim.w.oil_original_view) + if vim.w.canola_original_view then + vim.fn.winrestview(vim.w.canola_original_view) end return end -- Deleting the buffer closes all windows with that buffer open, so navigate to a different -- buffer first - local oilbuf = vim.api.nvim_get_current_buf() + local canolabuf = vim.api.nvim_get_current_buf() ok = pcall(vim.cmd.bprev) -- If `bprev` failed, there are no buffers open if not ok then @@ -446,22 +446,22 @@ M.close = function(opts) vim.cmd.enew() end end - vim.api.nvim_buf_delete(oilbuf, { force = true }) + vim.api.nvim_buf_delete(canolabuf, { force = true }) end ----@class oil.OpenPreviewOpts +---@class canola.OpenPreviewOpts ---@field vertical? boolean Open the buffer in a vertical split ---@field horizontal? boolean Open the buffer in a horizontal split ---@field split? "aboveleft"|"belowright"|"topleft"|"botright" Split modifier ---Preview the entry under the cursor in a split ----@param opts? oil.OpenPreviewOpts +---@param opts? canola.OpenPreviewOpts ---@param callback? fun(err: nil|string) Called once the preview window has been opened M.open_preview = function(opts, callback) opts = opts or {} - local config = require('oil.config') - local layout = require('oil.layout') - local util = require('oil.util') + local config = require('canola.config') + local layout = require('canola.layout') + local util = require('canola.util') local function finish(err) if err then @@ -501,7 +501,7 @@ M.open_preview = function(opts, callback) local root_win_opts, preview_win_opts = layout.split_window(0, config.float.preview_split, config.float.padding) - local win_opts_oil = { + local win_opts_canola = { relative = 'editor', width = root_win_opts.width, height = root_win_opts.height, @@ -510,7 +510,7 @@ M.open_preview = function(opts, callback) border = config.float.border, zindex = 45, } - vim.api.nvim_win_set_config(0, win_opts_oil) + vim.api.nvim_win_set_config(0, win_opts_canola) local win_opts = { relative = 'editor', width = preview_win_opts.width, @@ -530,7 +530,7 @@ M.open_preview = function(opts, callback) preview_win = vim.api.nvim_open_win(bufnr, true, win_opts) vim.api.nvim_set_option_value('previewwindow', true, { scope = 'local', win = preview_win }) - vim.api.nvim_win_set_var(preview_win, 'oil_preview', true) + vim.api.nvim_win_set_var(preview_win, 'canola_preview', true) vim.api.nvim_set_current_win(prev_win) elseif vim.fn.has('nvim-0.9') == 1 then vim.api.nvim_win_set_config(preview_win, { title = entry_title }) @@ -585,7 +585,7 @@ M.open_preview = function(opts, callback) filebufnr = vim.fn.bufadd(normalized_url) if entry_is_file and vim.fn.bufloaded(filebufnr) == 0 then vim.bo[filebufnr].bufhidden = 'wipe' - vim.b[filebufnr].oil_preview_buffer = true + vim.b[filebufnr].canola_preview_buffer = true end end @@ -602,17 +602,17 @@ M.open_preview = function(opts, callback) -- If we called open_preview during an autocmd, then the edit command may not trigger the -- BufReadCmd to load the buffer. So we need to do it manually. - if util.is_oil_bufnr(filebufnr) and not vim.b[filebufnr].oil_ready then - M.load_oil_buffer(filebufnr) + if util.is_canola_bufnr(filebufnr) and not vim.b[filebufnr].canola_ready then + M.load_canola_buffer(filebufnr) end vim.api.nvim_set_option_value('previewwindow', true, { scope = 'local', win = 0 }) - vim.api.nvim_win_set_var(0, 'oil_preview', true) + vim.api.nvim_win_set_var(0, 'canola_preview', true) for k, v in pairs(config.preview_win.win_options) do vim.api.nvim_set_option_value(k, v, { scope = 'local', win = preview_win }) end - vim.w.oil_entry_id = entry.id - vim.w.oil_source_win = prev_win + vim.w.canola_entry_id = entry.id + vim.w.canola_source_win = prev_win if has_multicursors then hack_set_win(prev_win) mc.restoreCursors() @@ -627,22 +627,22 @@ M.open_preview = function(opts, callback) end) end ----@class (exact) oil.SelectOpts +---@class (exact) canola.SelectOpts ---@field vertical? boolean Open the buffer in a vertical split ---@field horizontal? boolean Open the buffer in a horizontal split ---@field split? "aboveleft"|"belowright"|"topleft"|"botright" Split modifier ---@field tab? boolean Open the buffer in a new tab ----@field close? boolean Close the original oil buffer once selection is made +---@field close? boolean Close the original canola buffer once selection is made ---@field handle_buffer_callback? fun(buf_id: integer) If defined, all other buffer related options here would be ignored. This callback allows you to take over the process of opening the buffer yourself. ---Select the entry under the cursor ----@param opts nil|oil.SelectOpts +---@param opts nil|canola.SelectOpts ---@param callback nil|fun(err: nil|string) Called once all entries have been opened M.select = function(opts, callback) - local cache = require('oil.cache') - local config = require('oil.config') - local constants = require('oil.constants') - local util = require('oil.util') + local cache = require('canola.cache') + local config = require('canola.config') + local constants = require('canola.constants') + local util = require('canola.util') local FIELD_META = constants.FIELD_META opts = vim.tbl_extend('keep', opts or {}, {}) @@ -666,12 +666,12 @@ M.select = function(opts, callback) end local adapter = util.get_adapter(0) if not adapter then - return finish('Not an oil buffer') + return finish('Not an canola buffer') end local visual_range = util.get_visual_range() - ---@type oil.Entry[] + ---@type canola.Entry[] local entries = {} if visual_range then for i = visual_range.start_lnum, visual_range.end_lnum do @@ -723,7 +723,7 @@ M.select = function(opts, callback) end local prev_win = vim.api.nvim_get_current_win() - local oil_bufnr = vim.api.nvim_get_current_buf() + local canola_bufnr = vim.api.nvim_get_current_buf() -- Async iter over entries so we can normalize the url before opening local i = 1 @@ -742,14 +742,14 @@ M.select = function(opts, callback) end else -- Close floating window before opening a file - if vim.w.is_oil_win then + if vim.w.is_canola_win then M.close() end end -- Normalize the url before opening to prevent needing to rename them inside the BufReadCmd -- Renaming buffers during opening can lead to missed autocmds - util.get_edit_path(oil_bufnr, entry, function(normalized_url) + util.get_edit_path(canola_bufnr, entry, function(normalized_url) local mods = { vertical = opts.vertical, horizontal = opts.horizontal, @@ -760,7 +760,7 @@ M.select = function(opts, callback) local entry_is_file = not vim.endswith(normalized_url, '/') -- The :buffer command doesn't set buflisted=true - -- So do that for normal files or for oil dirs if config set buflisted=true + -- So do that for normal files or for canola dirs if config set buflisted=true if entry_is_file or config.buf_options.buflisted then vim.bo[filebufnr].buflisted = true end @@ -815,9 +815,9 @@ end ---@param bufnr integer ---@return boolean local function maybe_hijack_directory_buffer(bufnr) - local config = require('oil.config') - local fs = require('oil.fs') - local util = require('oil.util') + local config = require('canola.config') + local fs = require('canola.fs') + local util = require('canola.util') if not config.default_file_explorer then return false end @@ -839,147 +839,147 @@ end M._get_highlights = function() return { { - name = 'OilEmpty', + name = 'CanolaEmpty', link = 'Comment', desc = 'Empty column values', }, { - name = 'OilHidden', + name = 'CanolaHidden', link = 'Comment', - desc = 'Hidden entry in an oil buffer', + desc = 'Hidden entry in an canola buffer', }, { - name = 'OilDir', + name = 'CanolaDir', link = 'Directory', - desc = 'Directory names in an oil buffer', + desc = 'Directory names in an canola buffer', }, { - name = 'OilDirHidden', - link = 'OilHidden', - desc = 'Hidden directory names in an oil buffer', + name = 'CanolaDirHidden', + link = 'CanolaHidden', + desc = 'Hidden directory names in an canola buffer', }, { - name = 'OilDirIcon', - link = 'OilDir', + name = 'CanolaDirIcon', + link = 'CanolaDir', desc = 'Icon for directories', }, { - name = 'OilFileIcon', + name = 'CanolaFileIcon', link = nil, desc = 'Icon for files', }, { - name = 'OilSocket', + name = 'CanolaSocket', link = 'Keyword', - desc = 'Socket files in an oil buffer', + desc = 'Socket files in an canola buffer', }, { - name = 'OilSocketHidden', - link = 'OilHidden', - desc = 'Hidden socket files in an oil buffer', + name = 'CanolaSocketHidden', + link = 'CanolaHidden', + desc = 'Hidden socket files in an canola buffer', }, { - name = 'OilLink', + name = 'CanolaLink', link = nil, - desc = 'Soft links in an oil buffer', + desc = 'Soft links in an canola buffer', }, { - name = 'OilOrphanLink', + name = 'CanolaOrphanLink', link = nil, - desc = 'Orphaned soft links in an oil buffer', + desc = 'Orphaned soft links in an canola buffer', }, { - name = 'OilLinkHidden', - link = 'OilHidden', - desc = 'Hidden soft links in an oil buffer', + name = 'CanolaLinkHidden', + link = 'CanolaHidden', + desc = 'Hidden soft links in an canola buffer', }, { - name = 'OilOrphanLinkHidden', - link = 'OilLinkHidden', - desc = 'Hidden orphaned soft links in an oil buffer', + name = 'CanolaOrphanLinkHidden', + link = 'CanolaLinkHidden', + desc = 'Hidden orphaned soft links in an canola buffer', }, { - name = 'OilLinkTarget', + name = 'CanolaLinkTarget', link = 'Comment', desc = 'The target of a soft link', }, { - name = 'OilOrphanLinkTarget', + name = 'CanolaOrphanLinkTarget', link = 'DiagnosticError', desc = 'The target of an orphaned soft link', }, { - name = 'OilLinkTargetHidden', - link = 'OilHidden', + name = 'CanolaLinkTargetHidden', + link = 'CanolaHidden', desc = 'The target of a hidden soft link', }, { - name = 'OilOrphanLinkTargetHidden', - link = 'OilOrphanLinkTarget', + name = 'CanolaOrphanLinkTargetHidden', + link = 'CanolaOrphanLinkTarget', desc = 'The target of an hidden orphaned soft link', }, { - name = 'OilFile', + name = 'CanolaFile', link = nil, - desc = 'Normal files in an oil buffer', + desc = 'Normal files in an canola buffer', }, { - name = 'OilFileHidden', - link = 'OilHidden', - desc = 'Hidden normal files in an oil buffer', + name = 'CanolaFileHidden', + link = 'CanolaHidden', + desc = 'Hidden normal files in an canola buffer', }, { - name = 'OilExecutable', + name = 'CanolaExecutable', link = 'DiagnosticOk', - desc = 'Executable files in an oil buffer', + desc = 'Executable files in an canola buffer', }, { - name = 'OilExecutableHidden', - link = 'OilHidden', - desc = 'Hidden executable files in an oil buffer', + name = 'CanolaExecutableHidden', + link = 'CanolaHidden', + desc = 'Hidden executable files in an canola buffer', }, { - name = 'OilCreate', + name = 'CanolaCreate', link = 'DiagnosticInfo', - desc = 'Create action in the oil preview window', + desc = 'Create action in the canola preview window', }, { - name = 'OilDelete', + name = 'CanolaDelete', link = 'DiagnosticError', - desc = 'Delete action in the oil preview window', + desc = 'Delete action in the canola preview window', }, { - name = 'OilMove', + name = 'CanolaMove', link = 'DiagnosticWarn', - desc = 'Move action in the oil preview window', + desc = 'Move action in the canola preview window', }, { - name = 'OilCopy', + name = 'CanolaCopy', link = 'DiagnosticHint', - desc = 'Copy action in the oil preview window', + desc = 'Copy action in the canola preview window', }, { - name = 'OilChange', + name = 'CanolaChange', link = 'Special', - desc = 'Change action in the oil preview window', + desc = 'Change action in the canola preview window', }, { - name = 'OilRestore', - link = 'OilCreate', - desc = 'Restore (from the trash) action in the oil preview window', + name = 'CanolaRestore', + link = 'CanolaCreate', + desc = 'Restore (from the trash) action in the canola preview window', }, { - name = 'OilPurge', - link = 'OilDelete', - desc = 'Purge (Permanently delete a file from trash) action in the oil preview window', + name = 'CanolaPurge', + link = 'CanolaDelete', + desc = 'Purge (Permanently delete a file from trash) action in the canola preview window', }, { - name = 'OilTrash', - link = 'OilDelete', - desc = 'Trash (delete a file to trash) action in the oil preview window', + name = 'CanolaTrash', + link = 'CanolaDelete', + desc = 'Trash (delete a file to trash) action in the canola preview window', }, { - name = 'OilTrashSourcePath', + name = 'CanolaTrashSourcePath', link = 'Comment', desc = 'Virtual text that shows the original path of file in the trash', }, @@ -1023,28 +1023,28 @@ M.save = function(opts, cb) end end end - local mutator = require('oil.mutator') + local mutator = require('canola.mutator') mutator.try_write_changes(opts.confirm, cb) end local function restore_alt_buf() - if vim.bo.filetype == 'oil' then - require('oil.view').set_win_options() - vim.api.nvim_win_set_var(0, 'oil_did_enter', true) - elseif vim.w.oil_did_enter then - vim.api.nvim_win_del_var(0, 'oil_did_enter') - -- We are entering a non-oil buffer *after* having been in an oil buffer - local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, 'oil_original_buffer') + if vim.bo.filetype == 'canola' then + require('canola.view').set_win_options() + vim.api.nvim_win_set_var(0, 'canola_did_enter', true) + elseif vim.w.canola_did_enter then + vim.api.nvim_win_del_var(0, 'canola_did_enter') + -- We are entering a non-canola buffer *after* having been in an canola buffer + local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, 'canola_original_buffer') if has_orig and vim.api.nvim_buf_is_valid(orig_buffer) then if vim.api.nvim_get_current_buf() ~= orig_buffer then - -- If we are editing a new file after navigating around oil, set the alternate buffer - -- to be the last buffer we were in before opening oil + -- If we are editing a new file after navigating around canola, set the alternate buffer + -- to be the last buffer we were in before opening canola vim.fn.setreg('#', orig_buffer) else - -- If we are editing the same buffer that we started oil from, set the alternate to be - -- what it was before we opened oil + -- If we are editing the same buffer that we started canola from, set the alternate to be + -- what it was before we opened canola local has_orig_alt, alt_buffer = - pcall(vim.api.nvim_win_get_var, 0, 'oil_original_alternate') + pcall(vim.api.nvim_win_get_var, 0, 'canola_original_alternate') if has_orig_alt and vim.api.nvim_buf_is_valid(alt_buffer) then vim.fn.setreg('#', alt_buffer) end @@ -1055,12 +1055,12 @@ end ---@private ---@param bufnr integer -M.load_oil_buffer = function(bufnr) - local config = require('oil.config') - local keymap_util = require('oil.keymap_util') - local loading = require('oil.loading') - local util = require('oil.util') - local view = require('oil.view') +M.load_canola_buffer = function(bufnr) + local config = require('canola.config') + local keymap_util = require('canola.keymap_util') + local loading = require('canola.loading') + local util = require('canola.util') + local view = require('canola.view') local bufname = vim.api.nvim_buf_get_name(bufnr) local scheme, path = util.parse_url(bufname) if config.adapter_aliases[scheme] then @@ -1081,7 +1081,7 @@ M.load_oil_buffer = function(bufnr) -- directory, and can set the filetype early. This is helpful for adapters with a lot of latency -- (e.g. ssh) because it will set up the filetype keybinds at the *beginning* of the loading -- process. - vim.bo[bufnr].filetype = 'oil' + vim.bo[bufnr].filetype = 'canola' vim.bo[bufnr].buftype = 'acwrite' keymap_util.set_keymaps(config.keymaps, bufnr) end @@ -1131,17 +1131,17 @@ M.load_oil_buffer = function(bufnr) adapter.normalize_url(bufname, finish) end -local function close_preview_window_if_not_in_oil() - local util = require('oil.util') +local function close_preview_window_if_not_in_canola() + local util = require('canola.util') local preview_win_id = util.get_preview_win() - if not preview_win_id or not vim.w[preview_win_id].oil_entry_id then + if not preview_win_id or not vim.w[preview_win_id].canola_entry_id then return end - local oil_source_win = vim.w[preview_win_id].oil_source_win - if oil_source_win and vim.api.nvim_win_is_valid(oil_source_win) then - local src_buf = vim.api.nvim_win_get_buf(oil_source_win) - if util.is_oil_bufnr(src_buf) then + local canola_source_win = vim.w[preview_win_id].canola_source_win + if canola_source_win and vim.api.nvim_win_is_valid(canola_source_win) then + local src_buf = vim.api.nvim_win_get_buf(canola_source_win) + if util.is_canola_bufnr(src_buf) then return end end @@ -1151,16 +1151,16 @@ local function close_preview_window_if_not_in_oil() end local _on_key_ns = 0 ----Initialize oil ----@param opts oil.setupOpts|nil +---Initialize canola +---@param opts canola.setupOpts|nil M.setup = function(opts) - local Ringbuf = require('oil.ringbuf') - local config = require('oil.config') + local Ringbuf = require('canola.ringbuf') + local config = require('canola.config') config.setup(opts) set_colors() local callback = function(args) - local util = require('oil.util') + local util = require('canola.util') if args.smods.tab > 0 then vim.cmd.tabnew() end @@ -1182,7 +1182,7 @@ M.setup = function(opts) preview = true table.remove(args.fargs, i) elseif v == '--progress' then - local mutator = require('oil.mutator') + local mutator = require('canola.mutator') if mutator.is_mutating() then mutator.show_progress() else @@ -1210,7 +1210,7 @@ M.setup = function(opts) if trash then local url = M.get_url_for_path(path, false) local _, new_path = util.parse_url(url) - path = 'oil-trash://' .. new_path + path = 'canola-trash://' .. new_path end if preview then open_opts.preview = {} @@ -1218,11 +1218,16 @@ M.setup = function(opts) M[method](path, open_opts) end vim.api.nvim_create_user_command( - 'Oil', + 'Canola', callback, - { desc = 'Open oil file browser on a directory', nargs = '*', complete = 'dir', count = true } + { + desc = 'Open canola file browser on a directory', + nargs = '*', + complete = 'dir', + count = true, + } ) - local aug = vim.api.nvim_create_augroup('Oil', {}) + local aug = vim.api.nvim_create_augroup('Canola', {}) if config.default_file_explorer then vim.g.loaded_netrw = 1 @@ -1237,15 +1242,15 @@ M.setup = function(opts) local filetype_patterns = {} for scheme in pairs(config.adapters) do table.insert(patterns, scheme .. '*') - filetype_patterns[scheme .. '.*'] = { 'oil', { priority = 10 } } + filetype_patterns[scheme .. '.*'] = { 'canola', { priority = 10 } } end for scheme in pairs(config.adapter_aliases) do table.insert(patterns, scheme .. '*') - filetype_patterns[scheme .. '.*'] = { 'oil', { priority = 10 } } + filetype_patterns[scheme .. '.*'] = { 'canola', { priority = 10 } } end local scheme_pattern = table.concat(patterns, ',') -- We need to add these patterns to the filetype matcher so the filetype doesn't get overridden - -- by other patterns. See https://github.com/stevearc/oil.nvim/issues/47 + -- by other patterns. See https://github.com/stevearc/canola.nvim/issues/47 vim.filetype.add({ pattern = filetype_patterns, }) @@ -1257,7 +1262,7 @@ M.setup = function(opts) end, _on_key_ns) end vim.api.nvim_create_autocmd('ColorScheme', { - desc = 'Set default oil highlights', + desc = 'Set default canola highlights', group = aug, pattern = '*', callback = set_colors, @@ -1267,7 +1272,7 @@ M.setup = function(opts) pattern = scheme_pattern, nested = true, callback = function(params) - M.load_oil_buffer(params.buf) + M.load_canola_buffer(params.buf) end, }) vim.api.nvim_create_autocmd('BufWriteCmd', { @@ -1312,45 +1317,45 @@ M.setup = function(opts) group = aug, pattern = '*', callback = function() - local util = require('oil.util') - if not util.is_oil_bufnr(0) then - vim.w.oil_original_buffer = vim.api.nvim_get_current_buf() - vim.w.oil_original_view = vim.fn.winsaveview() + local util = require('canola.util') + if not util.is_canola_bufnr(0) then + vim.w.canola_original_buffer = vim.api.nvim_get_current_buf() + vim.w.canola_original_view = vim.fn.winsaveview() ---@diagnostic disable-next-line: param-type-mismatch - vim.w.oil_original_alternate = vim.fn.bufnr('#') + vim.w.canola_original_alternate = vim.fn.bufnr('#') end end, }) vim.api.nvim_create_autocmd('BufEnter', { - desc = 'Set/unset oil window options and restore alternate buffer', + desc = 'Set/unset canola window options and restore alternate buffer', group = aug, pattern = '*', callback = function() - local util = require('oil.util') + local util = require('canola.util') local bufname = vim.api.nvim_buf_get_name(0) local scheme = util.parse_url(bufname) - local is_oil_buf = scheme and config.adapters[scheme] - -- We want to filter out oil buffers that are not directories (i.e. ssh files) - local is_oil_dir_or_unknown = (vim.bo.filetype == 'oil' or vim.bo.filetype == '') - if is_oil_buf and is_oil_dir_or_unknown then - local view = require('oil.view') + local is_canola_buf = scheme and config.adapters[scheme] + -- We want to filter out canola buffers that are not directories (i.e. ssh files) + local is_canola_dir_or_unknown = (vim.bo.filetype == 'canola' or vim.bo.filetype == '') + if is_canola_buf and is_canola_dir_or_unknown then + local view = require('canola.view') view.maybe_set_cursor() - -- While we are in an oil buffer, set the alternate file to the buffer we were in prior to - -- opening oil - local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, 'oil_original_buffer') + -- While we are in an canola buffer, set the alternate file to the buffer we were in prior to + -- opening canola + local has_orig, orig_buffer = pcall(vim.api.nvim_win_get_var, 0, 'canola_original_buffer') if has_orig and vim.api.nvim_buf_is_valid(orig_buffer) then vim.fn.setreg('#', orig_buffer) end view.set_win_options() - vim.w.oil_did_enter = true + vim.w.canola_did_enter = true elseif vim.fn.isdirectory(bufname) == 0 then - -- Only run this logic if we are *not* in an oil buffer (and it's not a directory, which - -- will be replaced by an oil:// url) - -- Oil buffers have to run it in BufReadCmd after confirming they are a directory or a file + -- Only run this logic if we are *not* in an canola buffer (and it's not a directory, which + -- will be replaced by a canola:// url) + -- Canola buffers have to run it in BufReadCmd after confirming they are a directory or a file restore_alt_buf() end - close_preview_window_if_not_in_oil() + close_preview_window_if_not_in_canola() end, }) @@ -1360,9 +1365,9 @@ M.setup = function(opts) pattern = '*', callback = function() -- If we have entered a "preview" buffer in a non-preview window, reset bufhidden - if vim.b.oil_preview_buffer and not vim.wo.previewwindow then + if vim.b.canola_preview_buffer and not vim.wo.previewwindow then vim.bo.bufhidden = vim.api.nvim_get_option_value('bufhidden', { scope = 'global' }) - vim.b.oil_preview_buffer = nil + vim.b.canola_preview_buffer = nil end end, }) @@ -1374,30 +1379,30 @@ M.setup = function(opts) once = true, callback = function() vim.notify( - 'If you are trying to browse using Oil, use oil-ssh:// instead of scp://\nSet `silence_scp_warning = true` in oil.setup() to disable this message.\nSee https://github.com/stevearc/oil.nvim/issues/27 for more information.', + 'If you are trying to browse using Canola, use canola-ssh:// instead of scp://\nSet `silence_scp_warning = true` in canola.setup() to disable this message.\nSee https://github.com/stevearc/canola.nvim/issues/27 for more information.', vim.log.levels.WARN ) end, }) end vim.api.nvim_create_autocmd('WinNew', { - desc = 'Restore window options when splitting an oil window', + desc = 'Restore window options when splitting an canola window', group = aug, pattern = '*', nested = true, callback = function(params) - local util = require('oil.util') - if not util.is_oil_bufnr(params.buf) or vim.w.oil_did_enter then + local util = require('canola.util') + if not util.is_canola_bufnr(params.buf) or vim.w.canola_did_enter then return end - -- This new window is a split off of an oil window. We need to transfer the window + -- This new window is a split off of an canola window. We need to transfer the window -- variables. First, locate the parent window local parent_win -- First search windows in this tab, then search all windows local winids = vim.list_extend(vim.api.nvim_tabpage_list_wins(0), vim.api.nvim_list_wins()) for _, winid in ipairs(winids) do if vim.api.nvim_win_is_valid(winid) then - if vim.w[winid].oil_did_enter then + if vim.w[winid].canola_did_enter then parent_win = winid break end @@ -1405,40 +1410,40 @@ M.setup = function(opts) end if not parent_win then vim.notify( - 'Oil split could not find parent window. Please try to replicate whatever you just did and report a bug on github', + 'Canola split could not find parent window. Please try to replicate whatever you just did and report a bug on github', vim.log.levels.WARN ) return end -- Then transfer over the relevant window vars - vim.w.oil_did_enter = true - vim.w.oil_original_buffer = vim.w[parent_win].oil_original_buffer - vim.w.oil_original_view = vim.w[parent_win].oil_original_view - vim.w.oil_original_alternate = vim.w[parent_win].oil_original_alternate + vim.w.canola_did_enter = true + vim.w.canola_original_buffer = vim.w[parent_win].canola_original_buffer + vim.w.canola_original_view = vim.w[parent_win].canola_original_view + vim.w.canola_original_alternate = vim.w[parent_win].canola_original_alternate end, }) - -- mksession doesn't save oil buffers in a useful way. We have to manually load them after a - -- session finishes loading. See https://github.com/stevearc/oil.nvim/issues/29 + -- mksession doesn't save canola buffers in a useful way. We have to manually load them after a + -- session finishes loading. See https://github.com/stevearc/canola.nvim/issues/29 vim.api.nvim_create_autocmd('SessionLoadPost', { - desc = 'Load oil buffers after a session is loaded', + desc = 'Load canola buffers after a session is loaded', group = aug, pattern = '*', callback = function(params) if vim.g.SessionLoad ~= 1 then return end - local util = require('oil.util') + local util = require('canola.util') local scheme = util.parse_url(params.file) if config.adapters[scheme] and vim.api.nvim_buf_line_count(params.buf) == 1 then - M.load_oil_buffer(params.buf) + M.load_canola_buffer(params.buf) end end, }) if config.default_file_explorer then vim.api.nvim_create_autocmd('BufAdd', { - desc = 'Detect directory buffer and open oil file browser', + desc = 'Detect directory buffer and open canola file browser', group = aug, pattern = '*', nested = true, @@ -1449,7 +1454,7 @@ M.setup = function(opts) for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do if maybe_hijack_directory_buffer(bufnr) and vim.v.vim_did_enter == 1 then - M.load_oil_buffer(bufnr) + M.load_canola_buffer(bufnr) end end end diff --git a/lua/oil/keymap_util.lua b/lua/canola/keymap_util.lua similarity index 94% rename from lua/oil/keymap_util.lua rename to lua/canola/keymap_util.lua index 8d62c93..8c398c3 100644 --- a/lua/oil/keymap_util.lua +++ b/lua/canola/keymap_util.lua @@ -1,7 +1,7 @@ -local actions = require('oil.actions') -local config = require('oil.config') -local layout = require('oil.layout') -local util = require('oil.util') +local actions = require('canola.actions') +local config = require('canola.config') +local layout = require('canola.layout') +local util = require('canola.util') local M = {} ---@param rhs string|table|fun() @@ -13,7 +13,7 @@ local function resolve(rhs) local action_name = vim.split(rhs, '.', { plain = true })[2] local action = actions[action_name] if not action then - vim.notify('[oil.nvim] Unknown action name: ' .. action_name, vim.log.levels.ERROR) + vim.notify('[canola.nvim] Unknown action name: ' .. action_name, vim.log.levels.ERROR) end return resolve(action) elseif type(rhs) == 'table' then @@ -121,7 +121,7 @@ M.show_help = function(keymaps) local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, lines) - local ns = vim.api.nvim_create_namespace('Oil') + local ns = vim.api.nvim_create_namespace('Canola') for _, hl in ipairs(highlights) do local hl_group, lnum, start_col, end_col = unpack(hl) vim.api.nvim_buf_set_extmark(bufnr, ns, lnum - 1, start_col, { diff --git a/lua/oil/layout.lua b/lua/canola/layout.lua similarity index 95% rename from lua/oil/layout.lua rename to lua/canola/layout.lua index 0f32fcd..b8d3167 100644 --- a/lua/oil/layout.lua +++ b/lua/canola/layout.lua @@ -98,7 +98,7 @@ M.calculate_height = function(desired_height, opts) ) end ----@class (exact) oil.WinLayout +---@class (exact) canola.WinLayout ---@field width integer ---@field height integer ---@field row integer @@ -106,7 +106,7 @@ end ---@return vim.api.keyset.win_config M.get_fullscreen_win_opts = function() - local config = require('oil.config') + local config = require('canola.config') local total_width = M.get_editor_width() local total_height = M.get_editor_height() @@ -141,15 +141,15 @@ end ---@param winid integer ---@param direction "above"|"below"|"left"|"right"|"auto" ---@param gap integer ----@return oil.WinLayout root_dim New dimensions of the original window ----@return oil.WinLayout new_dim New dimensions of the new window +---@return canola.WinLayout root_dim New dimensions of the original window +---@return canola.WinLayout new_dim New dimensions of the new window M.split_window = function(winid, direction, gap) if direction == 'auto' then direction = vim.o.splitright and 'right' or 'left' end local float_config = vim.api.nvim_win_get_config(winid) - ---@type oil.WinLayout + ---@type canola.WinLayout local dim_root = { width = float_config.width, height = float_config.height, diff --git a/lua/oil/loading.lua b/lua/canola/loading.lua similarity index 98% rename from lua/oil/loading.lua rename to lua/canola/loading.lua index 633af6e..17b2119 100644 --- a/lua/oil/loading.lua +++ b/lua/canola/loading.lua @@ -1,4 +1,4 @@ -local util = require('oil.util') +local util = require('canola.util') local M = {} local timers = {} diff --git a/lua/oil/log.lua b/lua/canola/log.lua similarity index 92% rename from lua/oil/log.lua rename to lua/canola/log.lua index a16394b..c49b346 100644 --- a/lua/oil/log.lua +++ b/lua/canola/log.lua @@ -11,14 +11,14 @@ Log.level = vim.log.levels.WARN ---@return string Log.get_logfile = function() - local fs = require('oil.fs') + local fs = require('canola.fs') local ok, stdpath = pcall(vim.fn.stdpath, 'log') if not ok then stdpath = vim.fn.stdpath('cache') end assert(type(stdpath) == 'string') - return fs.join(stdpath, 'oil.log') + return fs.join(stdpath, 'canola.log') end ---@param level integer @@ -73,11 +73,11 @@ local function initialize() end local parent = vim.fs.dirname(filepath) - require('oil.fs').mkdirp(parent) + require('canola.fs').mkdirp(parent) local logfile, openerr = io.open(filepath, 'a+') if not logfile then - local err_msg = string.format('Failed to open oil.nvim log file: %s', openerr) + local err_msg = string.format('Failed to open canola.nvim log file: %s', openerr) vim.notify(err_msg, vim.log.levels.ERROR) else write = function(line) diff --git a/lua/oil/lsp/helpers.lua b/lua/canola/lsp/helpers.lua similarity index 95% rename from lua/oil/lsp/helpers.lua rename to lua/canola/lsp/helpers.lua index cadeca1..ad6442d 100644 --- a/lua/oil/lsp/helpers.lua +++ b/lua/canola/lsp/helpers.lua @@ -1,11 +1,11 @@ -local config = require('oil.config') -local fs = require('oil.fs') -local util = require('oil.util') -local workspace = require('oil.lsp.workspace') +local config = require('canola.config') +local fs = require('canola.fs') +local util = require('canola.util') +local workspace = require('canola.lsp.workspace') local M = {} ----@param actions oil.Action[] +---@param actions canola.Action[] ---@return fun() did_perform Call this function when the file operations have been completed M.will_perform_file_operations = function(actions) local moves = {} diff --git a/lua/oil/lsp/workspace.lua b/lua/canola/lsp/workspace.lua similarity index 99% rename from lua/oil/lsp/workspace.lua rename to lua/canola/lsp/workspace.lua index a0e26bb..5c5b4ec 100644 --- a/lua/oil/lsp/workspace.lua +++ b/lua/canola/lsp/workspace.lua @@ -1,4 +1,4 @@ -local fs = require('oil.fs') +local fs = require('canola.fs') local ms = require('vim.lsp.protocol').Methods if vim.fn.has('nvim-0.10') == 0 then ms = { diff --git a/lua/oil/mutator/confirmation.lua b/lua/canola/mutator/confirmation.lua similarity index 91% rename from lua/oil/mutator/confirmation.lua rename to lua/canola/mutator/confirmation.lua index 0aff7a7..9ed6525 100644 --- a/lua/oil/mutator/confirmation.lua +++ b/lua/canola/mutator/confirmation.lua @@ -1,10 +1,10 @@ -local columns = require('oil.columns') -local config = require('oil.config') -local layout = require('oil.layout') -local util = require('oil.util') +local columns = require('canola.columns') +local config = require('canola.config') +local layout = require('canola.layout') +local util = require('canola.util') local M = {} ----@param actions oil.Action[] +---@param actions canola.Action[] ---@return boolean local function is_simple_edit(actions) local num_create = 0 @@ -53,7 +53,7 @@ local function render_lines(winid, bufnr, lines) }) end ----@param actions oil.Action[] +---@param actions canola.Action[] ---@param should_confirm nil|boolean ---@param cb fun(proceed: boolean) M.show = vim.schedule_wrap(function(actions, should_confirm, cb) @@ -77,7 +77,7 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb) local adapter = util.get_adapter_for_action(action) local line if action.type == 'change' then - ---@cast action oil.ChangeAction + ---@cast action canola.ChangeAction line = columns.render_change_action(adapter, action) else line = adapter.render_action(action) @@ -105,11 +105,14 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb) border = config.confirmation.border, }) if not ok then - vim.notify(string.format('Error showing oil preview window: %s', winid), vim.log.levels.ERROR) + vim.notify( + string.format('Error showing canola preview window: %s', winid), + vim.log.levels.ERROR + ) cb(false) end - vim.bo[bufnr].filetype = 'oil_preview' - vim.bo[bufnr].syntax = 'oil_preview' + vim.bo[bufnr].filetype = 'canola_preview' + vim.bo[bufnr].syntax = 'canola_preview' for k, v in pairs(config.confirmation.win_options) do vim.api.nvim_set_option_value(k, v, { scope = 'local', win = winid }) end diff --git a/lua/oil/mutator/init.lua b/lua/canola/mutator/init.lua similarity index 88% rename from lua/oil/mutator/init.lua rename to lua/canola/mutator/init.lua index 8e03340..34cf2b1 100644 --- a/lua/oil/mutator/init.lua +++ b/lua/canola/mutator/init.lua @@ -1,60 +1,60 @@ -local Progress = require('oil.mutator.progress') -local Trie = require('oil.mutator.trie') -local cache = require('oil.cache') -local columns = require('oil.columns') -local config = require('oil.config') -local confirmation = require('oil.mutator.confirmation') -local constants = require('oil.constants') -local fs = require('oil.fs') -local lsp_helpers = require('oil.lsp.helpers') -local oil = require('oil') -local parser = require('oil.mutator.parser') -local util = require('oil.util') -local view = require('oil.view') +local Progress = require('canola.mutator.progress') +local Trie = require('canola.mutator.trie') +local cache = require('canola.cache') +local canola = require('canola') +local columns = require('canola.columns') +local config = require('canola.config') +local confirmation = require('canola.mutator.confirmation') +local constants = require('canola.constants') +local fs = require('canola.fs') +local lsp_helpers = require('canola.lsp.helpers') +local parser = require('canola.mutator.parser') +local util = require('canola.util') +local view = require('canola.view') local M = {} local FIELD_NAME = constants.FIELD_NAME local FIELD_TYPE = constants.FIELD_TYPE ----@alias oil.Action oil.CreateAction|oil.DeleteAction|oil.MoveAction|oil.CopyAction|oil.ChangeAction +---@alias canola.Action canola.CreateAction|canola.DeleteAction|canola.MoveAction|canola.CopyAction|canola.ChangeAction ----@class (exact) oil.CreateAction +---@class (exact) canola.CreateAction ---@field type "create" ---@field url string ----@field entry_type oil.EntryType +---@field entry_type canola.EntryType ---@field link nil|string ----@class (exact) oil.DeleteAction +---@class (exact) canola.DeleteAction ---@field type "delete" ---@field url string ----@field entry_type oil.EntryType +---@field entry_type canola.EntryType ----@class (exact) oil.MoveAction +---@class (exact) canola.MoveAction ---@field type "move" ----@field entry_type oil.EntryType +---@field entry_type canola.EntryType ---@field src_url string ---@field dest_url string ----@class (exact) oil.CopyAction +---@class (exact) canola.CopyAction ---@field type "copy" ----@field entry_type oil.EntryType +---@field entry_type canola.EntryType ---@field src_url string ---@field dest_url string ----@class (exact) oil.ChangeAction +---@class (exact) canola.ChangeAction ---@field type "change" ----@field entry_type oil.EntryType +---@field entry_type canola.EntryType ---@field url string ---@field column string ---@field value any ----@param all_diffs table ----@return oil.Action[] +---@param all_diffs table +---@return canola.Action[] M.create_actions_from_diffs = function(all_diffs) - ---@type oil.Action[] + ---@type canola.Action[] local actions = {} - ---@type table + ---@type table local diff_by_id = setmetatable({}, { __index = function(t, key) local list = {} @@ -69,7 +69,7 @@ M.create_actions_from_diffs = function(all_diffs) -- > foo/bar/b.txt local seen_creates = {} - ---@param action oil.Action + ---@param action canola.Action local function add_action(action) local adapter = assert(config.get_adapter_by_scheme(action.dest_url or action.url)) if not adapter.filter_action or adapter.filter_action(action) then @@ -195,8 +195,8 @@ M.create_actions_from_diffs = function(all_diffs) return M.enforce_action_order(actions) end ----@param actions oil.Action[] ----@return oil.Action[] +---@param actions canola.Action[] +---@return canola.Action[] M.enforce_action_order = function(actions) local src_trie = Trie.new() local dest_trie = Trie.new() @@ -220,7 +220,7 @@ M.enforce_action_order = function(actions) ---Gets the dependencies of a particular action. Effectively dynamically calculates the dependency ---"edges" of the graph. - ---@param action oil.Action + ---@param action canola.Action local function get_deps(action) local ret = {} if action.type == 'delete' then @@ -278,8 +278,8 @@ M.enforce_action_order = function(actions) return ret end - ---@return nil|oil.Action The leaf action - ---@return nil|oil.Action When no leaves found, this is the last action in the loop + ---@return nil|canola.Action The leaf action + ---@return nil|canola.Action When no leaves found, this is the last action in the loop local function find_leaf(action, seen) if not seen then seen = {} @@ -321,7 +321,7 @@ M.enforce_action_order = function(actions) -- We've detected a move cycle (e.g. MOVE /a -> /b + MOVE /b -> /a) -- Split one of the moves and retry local intermediate_url = - string.format('%s__oil_tmp_%05d', loop_action.src_url, math.random(999999)) + string.format('%s__canola_tmp_%05d', loop_action.src_url, math.random(999999)) local move_1 = { type = 'move', entry_type = loop_action.entry_type, @@ -383,12 +383,12 @@ end local progress ----@param actions oil.Action[] +---@param actions canola.Action[] ---@param cb fun(err: nil|string) M.process_actions = function(actions, cb) vim.api.nvim_exec_autocmds( 'User', - { pattern = 'OilActionsPre', modeline = false, data = { actions = actions } } + { pattern = 'CanolaActionsPre', modeline = false, data = { actions = actions } } ) local did_complete = nil @@ -422,7 +422,7 @@ M.process_actions = function(actions, cb) progress = nil vim.api.nvim_exec_autocmds( 'User', - { pattern = 'OilActionsPost', modeline = false, data = { err = err, actions = actions } } + { pattern = 'CanolaActionsPost', modeline = false, data = { err = err, actions = actions } } ) cb(err) end @@ -473,7 +473,7 @@ M.process_actions = function(actions, cb) end end) if action.type == 'change' then - ---@cast action oil.ChangeAction + ---@cast action canola.ChangeAction columns.perform_change_action(adapter, action, callback) else adapter.perform_action(action, callback) @@ -509,7 +509,7 @@ M.try_write_changes = function(confirm, cb) local was_modified = vim.bo.modified local buffers = view.get_all_buffers() local all_diffs = {} - ---@type table + ---@type table local all_errors = {} mutation_in_progress = true @@ -537,7 +537,7 @@ M.try_write_changes = function(confirm, cb) mutation_in_progress = false end - local ns = vim.api.nvim_create_namespace('Oil') + local ns = vim.api.nvim_create_namespace('Canola') vim.diagnostic.reset(ns) if not vim.tbl_isempty(all_errors) then for bufnr, errors in pairs(all_errors) do @@ -564,7 +564,7 @@ M.try_write_changes = function(confirm, cb) end) end unlock() - cb('Error parsing oil buffers') + cb('Error parsing canola buffers') return end @@ -581,12 +581,12 @@ M.try_write_changes = function(confirm, cb) vim.schedule_wrap(function(err) view.unlock_buffers() if err then - err = string.format('[oil] Error applying actions: %s', err) - view.rerender_all_oil_buffers(nil, function() + err = string.format('[canola] Error applying actions: %s', err) + view.rerender_all_canola_buffers(nil, function() cb(err) end) else - local current_entry = oil.get_cursor_entry() + local current_entry = canola.get_cursor_entry() if current_entry then -- get the entry under the cursor and make sure the cursor stays on it view.set_last_cursor( @@ -594,10 +594,10 @@ M.try_write_changes = function(confirm, cb) vim.split(current_entry.parsed_name or current_entry.name, '/')[1] ) end - view.rerender_all_oil_buffers(nil, function(render_err) + view.rerender_all_canola_buffers(nil, function(render_err) vim.api.nvim_exec_autocmds( 'User', - { pattern = 'OilMutationComplete', modeline = false } + { pattern = 'CanolaMutationComplete', modeline = false } ) cb(render_err) end) diff --git a/lua/oil/mutator/parser.lua b/lua/canola/mutator/parser.lua similarity index 90% rename from lua/oil/mutator/parser.lua rename to lua/canola/mutator/parser.lua index 45f7239..8a9e278 100644 --- a/lua/oil/mutator/parser.lua +++ b/lua/canola/mutator/parser.lua @@ -1,10 +1,10 @@ -local cache = require('oil.cache') -local columns = require('oil.columns') -local config = require('oil.config') -local constants = require('oil.constants') -local fs = require('oil.fs') -local util = require('oil.util') -local view = require('oil.view') +local cache = require('canola.cache') +local columns = require('canola.columns') +local config = require('canola.config') +local constants = require('canola.constants') +local fs = require('canola.fs') +local util = require('canola.util') +local view = require('canola.view') local M = {} local FIELD_ID = constants.FIELD_ID @@ -12,23 +12,23 @@ local FIELD_NAME = constants.FIELD_NAME local FIELD_TYPE = constants.FIELD_TYPE local FIELD_META = constants.FIELD_META ----@alias oil.Diff oil.DiffNew|oil.DiffDelete|oil.DiffChange +---@alias canola.Diff canola.DiffNew|canola.DiffDelete|canola.DiffChange ----@class (exact) oil.DiffNew +---@class (exact) canola.DiffNew ---@field type "new" ---@field name string ----@field entry_type oil.EntryType +---@field entry_type canola.EntryType ---@field id nil|integer ---@field link nil|string ----@class (exact) oil.DiffDelete +---@class (exact) canola.DiffDelete ---@field type "delete" ---@field name string ---@field id integer ----@class (exact) oil.DiffChange +---@class (exact) canola.DiffChange ---@field type "change" ----@field entry_type oil.EntryType +---@field entry_type canola.EntryType ---@field name string ---@field column string ---@field value any @@ -57,16 +57,16 @@ local function compare_link_target(meta, parsed_entry) return meta_name == parsed_name end ----@class (exact) oil.ParseResult +---@class (exact) canola.ParseResult ---@field data table Parsed entry data ---@field ranges table Locations of the various columns ----@field entry nil|oil.InternalEntry If the entry already exists +---@field entry nil|canola.InternalEntry If the entry already exists ---Parse a single line in a buffer ----@param adapter oil.Adapter +---@param adapter canola.Adapter ---@param line string ----@param column_defs oil.ColumnSpec[] ----@return nil|oil.ParseResult +---@param column_defs canola.ColumnSpec[] +---@return nil|canola.ParseResult ---@return nil|string Error M.parse_line = function(adapter, line, column_defs) local ret = {} @@ -142,18 +142,18 @@ M.parse_line = function(adapter, line, column_defs) return { data = ret, entry = entry, ranges = ranges } end ----@class (exact) oil.ParseError +---@class (exact) canola.ParseError ---@field lnum integer ---@field col integer ---@field message string ---@param bufnr integer ----@return oil.Diff[] diffs ----@return oil.ParseError[] errors Parsing errors +---@return canola.Diff[] diffs +---@return canola.ParseError[] errors Parsing errors M.parse = function(bufnr) - ---@type oil.Diff[] + ---@type canola.Diff[] local diffs = {} - ---@type oil.ParseError[] + ---@type canola.ParseError[] local errors = {} local bufname = vim.api.nvim_buf_get_name(bufnr) local adapter = util.get_adapter(bufnr, true) diff --git a/lua/oil/mutator/progress.lua b/lua/canola/mutator/progress.lua similarity index 92% rename from lua/oil/mutator/progress.lua rename to lua/canola/mutator/progress.lua index 81b6b5c..4a74dbc 100644 --- a/lua/oil/mutator/progress.lua +++ b/lua/canola/mutator/progress.lua @@ -1,8 +1,8 @@ -local columns = require('oil.columns') -local config = require('oil.config') -local layout = require('oil.layout') -local loading = require('oil.loading') -local util = require('oil.util') +local columns = require('canola.columns') +local config = require('canola.config') +local layout = require('canola.layout') +local loading = require('canola.loading') +local util = require('canola.util') local Progress = {} local FPS = 20 @@ -68,7 +68,7 @@ function Progress:show(opts) style = 'minimal', border = config.progress.border, }) - vim.bo[self.bufnr].filetype = 'oil_progress' + vim.bo[self.bufnr].filetype = 'canola_progress' for k, v in pairs(config.progress.win_options) do vim.api.nvim_set_option_value(k, v, { scope = 'local', win = self.winid }) end @@ -121,7 +121,7 @@ function Progress:_render() if self.min_bufnr and vim.api.nvim_buf_is_valid(self.min_bufnr) then util.render_text( self.min_bufnr, - { string.format('%sOil: %s', self.spinner, self.count) }, + { string.format('%sCanola: %s', self.spinner, self.count) }, { winid = self.min_winid, h_align = 'left' } ) end @@ -189,17 +189,17 @@ function Progress:minimize() self.min_bufnr = bufnr self.min_winid = winid self:_render() - vim.notify_once('Restore progress window with :Oil --progress') + vim.notify_once('Restore progress window with :Canola --progress') end ----@param action oil.Action +---@param action canola.Action ---@param idx integer ---@param total integer function Progress:set_action(action, idx, total) local adapter = util.get_adapter_for_action(action) local change_line if action.type == 'change' then - ---@cast action oil.ChangeAction + ---@cast action canola.ChangeAction change_line = columns.render_change_action(adapter, action) else change_line = adapter.render_action(action) diff --git a/lua/oil/mutator/trie.lua b/lua/canola/mutator/trie.lua similarity index 91% rename from lua/oil/mutator/trie.lua rename to lua/canola/mutator/trie.lua index 95ab979..9dbf6d1 100644 --- a/lua/oil/mutator/trie.lua +++ b/lua/canola/mutator/trie.lua @@ -1,13 +1,13 @@ -local util = require('oil.util') +local util = require('canola.util') ----@class (exact) oil.Trie ----@field new fun(): oil.Trie +---@class (exact) canola.Trie +---@field new fun(): canola.Trie ---@field private root table local Trie = {} ----@return oil.Trie +---@return canola.Trie Trie.new = function() - ---@type oil.Trie + ---@type canola.Trie return setmetatable({ root = { values = {}, children = {} }, }, { @@ -80,7 +80,7 @@ end ---Add the first action that affects a parent path of the url ---@param url string ----@param ret oil.InternalEntry[] +---@param ret canola.InternalEntry[] function Trie:accum_first_parents_of(url, ret) local pieces = self:_url_to_path_pieces(url) local containers = { self.root } @@ -117,8 +117,8 @@ end ---Add all actions affecting children of the url ---@param url string ----@param ret oil.InternalEntry[] ----@param filter nil|fun(entry: oil.Action): boolean +---@param ret canola.InternalEntry[] +---@param filter nil|fun(entry: canola.Action): boolean function Trie:accum_children_of(url, ret, filter) local pieces = self:_url_to_path_pieces(url) local current = self.root @@ -137,8 +137,8 @@ end ---Add all actions at a specific path ---@param url string ----@param ret oil.InternalEntry[] ----@param filter? fun(entry: oil.Action): boolean +---@param ret canola.InternalEntry[] +---@param filter? fun(entry: canola.Action): boolean function Trie:accum_actions_at(url, ret, filter) local pieces = self:_url_to_path_pieces(url) local current = self.root diff --git a/lua/oil/pathutil.lua b/lua/canola/pathutil.lua similarity index 100% rename from lua/oil/pathutil.lua rename to lua/canola/pathutil.lua diff --git a/lua/oil/ringbuf.lua b/lua/canola/ringbuf.lua similarity index 96% rename from lua/oil/ringbuf.lua rename to lua/canola/ringbuf.lua index 66cd912..ced0907 100644 --- a/lua/oil/ringbuf.lua +++ b/lua/canola/ringbuf.lua @@ -1,4 +1,4 @@ ----@class oil.Ringbuf +---@class canola.Ringbuf ---@field private size integer ---@field private tail integer ---@field private buf string[] diff --git a/lua/oil/shell.lua b/lua/canola/shell.lua similarity index 100% rename from lua/oil/shell.lua rename to lua/canola/shell.lua diff --git a/lua/oil/util.lua b/lua/canola/util.lua similarity index 91% rename from lua/oil/util.lua rename to lua/canola/util.lua index 3703d1a..2231470 100644 --- a/lua/oil/util.lua +++ b/lua/canola/util.lua @@ -1,5 +1,5 @@ -local config = require('oil.config') -local constants = require('oil.constants') +local config = require('canola.config') +local constants = require('canola.constants') local M = {} @@ -8,7 +8,7 @@ local FIELD_NAME = constants.FIELD_NAME local FIELD_TYPE = constants.FIELD_TYPE local FIELD_META = constants.FIELD_META ----@alias oil.IconProvider fun(type: string, name: string, conf: table?, ft: string?): (icon: string, hl: string) +---@alias canola.IconProvider fun(type: string, name: string, conf: table?, ft: string?): (icon: string, hl: string) ---@param url string ---@return nil|string @@ -77,13 +77,13 @@ end ---@param bufnr integer ---@param silent? boolean ----@return nil|oil.Adapter +---@return nil|canola.Adapter M.get_adapter = function(bufnr, silent) local bufname = vim.api.nvim_buf_get_name(bufnr) local adapter = config.get_adapter_by_scheme(bufname) if not adapter and not silent then vim.notify_once( - string.format("[oil] could not find adapter for buffer '%s://'", bufname), + string.format("[canola] could not find adapter for buffer '%s://'", bufname), vim.log.levels.ERROR ) end @@ -92,7 +92,7 @@ end ---@param text string ---@param width integer|nil ----@param align oil.ColumnAlign +---@param align canola.ColumnAlign ---@return string padded_text ---@return integer left_padding M.pad_align = function(text, width, align) @@ -135,8 +135,8 @@ M.tbl_slice = function(tbl, start_idx, end_idx) return ret end ----@param entry oil.InternalEntry ----@return oil.Entry +---@param entry canola.InternalEntry +---@return canola.Entry M.export_entry = function(entry) return { name = entry[FIELD_NAME], @@ -244,7 +244,7 @@ end ---@param url string ---@return string[] local function get_possible_buffer_names_from_url(url) - local fs = require('oil.fs') + local fs = require('canola.fs') local scheme, path = M.parse_url(url) if config.adapters[scheme] == 'files' then assert(path) @@ -253,7 +253,7 @@ local function get_possible_buffer_names_from_url(url) return { url } end ----@param entry_type oil.EntryType +---@param entry_type canola.EntryType ---@param src_url string ---@param dest_url string M.update_moved_buffers = function(entry_type, src_url, dest_url) @@ -271,7 +271,7 @@ M.update_moved_buffers = function(entry_type, src_url, dest_url) for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do local bufname = vim.api.nvim_buf_get_name(bufnr) if vim.startswith(bufname, src_url) then - -- Handle oil directory buffers + -- Handle canola directory buffers vim.api.nvim_buf_set_name(bufnr, dest_url .. bufname:sub(src_url:len() + 1)) elseif bufname ~= '' and vim.bo[bufnr].buftype == '' then -- Handle regular buffers @@ -309,11 +309,11 @@ M.split_config = function(name_or_config) end end ----@alias oil.ColumnAlign "left"|"center"|"right" +---@alias canola.ColumnAlign "left"|"center"|"right" ----@param lines oil.TextChunk[][] +---@param lines canola.TextChunk[][] ---@param col_width integer[] ----@param col_align? oil.ColumnAlign[] +---@param col_align? canola.ColumnAlign[] ---@return string[] ---@return any[][] List of highlights {group, lnum, col_start, col_end} M.render_table = function(lines, col_width, col_align) @@ -364,7 +364,7 @@ end ---@param bufnr integer ---@param highlights any[][] List of highlights {group, lnum, col_start, col_end} M.set_highlights = function(bufnr, highlights) - local ns = vim.api.nvim_create_namespace('Oil') + local ns = vim.api.nvim_create_namespace('Canola') vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) for _, hl in ipairs(highlights) do local group, line, col_start, col_end = unpack(hl) @@ -381,7 +381,7 @@ end ---@return string M.addslash = function(path, os_slash) local slash = '/' - if os_slash and require('oil.fs').is_windows then + if os_slash and require('canola.fs').is_windows then slash = '\\' end @@ -413,7 +413,7 @@ M.get_title = function(winid) if config.adapters[scheme] == 'files' then assert(path) - local fs = require('oil.fs') + local fs = require('canola.fs') title = vim.fn.fnamemodify(fs.posix_to_os_path(path), ':~') end return title @@ -445,7 +445,7 @@ M.add_title_to_win = function(winid, opts) col = vim.api.nvim_win_get_width(winid) - 1 - width elseif opts.align ~= 'left' then vim.notify( - string.format("Unknown oil window title alignment: '%s'", opts.align), + string.format("Unknown canola window title alignment: '%s'", opts.align), vim.log.levels.ERROR ) end @@ -470,7 +470,7 @@ M.add_title_to_win = function(winid, opts) vim.bo[bufnr].bufhidden = 'wipe' local update_autocmd = vim.api.nvim_create_autocmd('BufWinEnter', { - desc = 'Update oil floating window title when buffer changes', + desc = 'Update canola floating window title when buffer changes', pattern = '*', callback = function(params) local winbuf = params.buf @@ -500,7 +500,7 @@ M.add_title_to_win = function(winid, opts) end, }) vim.api.nvim_create_autocmd('WinClosed', { - desc = 'Close oil floating window title when floating window closes', + desc = 'Close canola floating window title when floating window closes', pattern = tostring(winid), callback = function() if title_winid and vim.api.nvim_win_is_valid(title_winid) then @@ -522,9 +522,9 @@ M.add_title_to_win = function(winid, opts) ) end ----@param action oil.Action ----@return oil.Adapter ----@return nil|oil.CrossAdapterAction +---@param action canola.Action +---@return canola.Adapter +---@return nil|canola.CrossAdapterAction M.get_adapter_for_action = function(action) local adapter = assert(config.get_adapter_by_scheme(action.url or action.src_url)) if action.dest_url then @@ -675,12 +675,12 @@ end ---@param bufnr integer ---@return boolean -M.is_oil_bufnr = function(bufnr) +M.is_canola_bufnr = function(bufnr) local filetype = vim.bo[bufnr].filetype - if filetype == 'oil' then + if filetype == 'canola' then return true elseif filetype ~= '' then - -- If the filetype is set and is NOT "oil", then it's not an oil buffer + -- If the filetype is set and is NOT "canola", then it's not an canola buffer return false end local scheme = M.parse_url(vim.api.nvim_buf_get_name(bufnr)) @@ -713,7 +713,7 @@ M.get_preview_win = function(opts) if vim.api.nvim_win_is_valid(winid) and vim.wo[winid].previewwindow - and (opts.include_not_owned or vim.w[winid]['oil_preview']) + and (opts.include_not_owned or vim.w[winid]['canola_preview']) then return winid end @@ -722,9 +722,9 @@ end ---@return fun() restore Function that restores the cursor M.hide_cursor = function() - vim.api.nvim_set_hl(0, 'OilPreviewCursor', { nocombine = true, blend = 100 }) + vim.api.nvim_set_hl(0, 'CanolaPreviewCursor', { nocombine = true, blend = 100 }) local original_guicursor = vim.go.guicursor - vim.go.guicursor = 'a:OilPreviewCursor/OilPreviewCursor' + vim.go.guicursor = 'a:CanolaPreviewCursor/CanolaPreviewCursor' return function() -- HACK: see https://github.com/neovim/neovim/issues/21018 @@ -758,12 +758,12 @@ M.buf_get_win = function(bufnr, preferred_win) return nil end ----@param adapter oil.Adapter +---@param adapter canola.Adapter ---@param url string ---@param opts {columns?: string[], no_cache?: boolean} ----@param callback fun(err: nil|string, entries: nil|oil.InternalEntry[]) +---@param callback fun(err: nil|string, entries: nil|canola.InternalEntry[]) M.adapter_list_all = function(adapter, url, opts, callback) - local cache = require('oil.cache') + local cache = require('canola.cache') if not opts.no_cache then local entries = cache.list_url(url) if not vim.tbl_isempty(entries) then @@ -787,15 +787,15 @@ M.adapter_list_all = function(adapter, url, opts, callback) end) end ----Send files from the current oil directory to quickfix +---Send files from the current canola directory to quickfix ---based on the provided options. ---@param opts {target?: "qflist"|"loclist", action?: "r"|"a", only_matching_search?: boolean} M.send_to_quickfix = function(opts) if type(opts) ~= 'table' then opts = {} end - local oil = require('oil') - local dir = oil.get_current_dir() + local canola = require('canola') + local dir = canola.get_current_dir() if type(dir) ~= 'string' then return end @@ -806,7 +806,7 @@ M.send_to_quickfix = function(opts) local match_all = not opts.only_matching_search local qf_entries = {} for i = range.start_lnum, range.end_lnum do - local entry = oil.get_entry_on_line(0, i) + local entry = canola.get_entry_on_line(0, i) if entry and entry.type == 'file' and (match_all or M.is_matching(entry)) then local qf_entry = { filename = dir .. entry.name, @@ -818,11 +818,11 @@ M.send_to_quickfix = function(opts) end end if #qf_entries == 0 then - vim.notify('[oil] No entries found to send to quickfix', vim.log.levels.WARN) + vim.notify('[canola] No entries found to send to quickfix', vim.log.levels.WARN) return end vim.api.nvim_exec_autocmds('QuickFixCmdPre', {}) - local qf_title = 'oil files' + local qf_title = 'canola files' local action = opts.action == 'a' and 'a' or 'r' if opts.target == 'loclist' then vim.fn.setloclist(0, {}, action, { title = qf_title, items = qf_entries }) @@ -856,7 +856,7 @@ M.get_visual_range = function() return { start_lnum = start_lnum, end_lnum = end_lnum } end ----@param entry oil.Entry +---@param entry canola.Entry ---@return boolean M.is_matching = function(entry) -- if search highlightig is not enabled, all files are considered to match @@ -875,11 +875,11 @@ M.run_after_load = function(bufnr, callback) if bufnr == 0 then bufnr = vim.api.nvim_get_current_buf() end - if vim.b[bufnr].oil_ready then + if vim.b[bufnr].canola_ready then callback() else vim.api.nvim_create_autocmd('User', { - pattern = 'OilEnter', + pattern = 'CanolaEnter', callback = function(args) if args.data.buf == bufnr then vim.api.nvim_buf_call(bufnr, callback) @@ -890,7 +890,7 @@ M.run_after_load = function(bufnr, callback) end end ----@param entry oil.Entry +---@param entry canola.Entry ---@return boolean M.is_directory = function(entry) local is_directory = entry.type == 'directory' @@ -904,11 +904,11 @@ M.is_directory = function(entry) end ---Get the :edit path for an entry ----@param bufnr integer The oil buffer that contains the entry ----@param entry oil.Entry +---@param bufnr integer The canola buffer that contains the entry +---@param entry canola.Entry ---@param callback fun(normalized_url: string) M.get_edit_path = function(bufnr, entry, callback) - local pathutil = require('oil.pathutil') + local pathutil = require('canola.pathutil') local bufname = vim.api.nvim_buf_get_name(bufnr) local scheme, dir = M.parse_url(bufname) @@ -930,7 +930,7 @@ M.get_edit_path = function(bufnr, entry, callback) end --- Check for an icon provider and return a common icon provider API ----@return (oil.IconProvider)? +---@return (canola.IconProvider)? M.get_icon_provider = function() -- prefer mini.icons local _, mini_icons = pcall(require, 'mini.icons') @@ -954,20 +954,20 @@ M.get_icon_provider = function() return function(type, name, conf, ft) if type == 'directory' then local icon, hl = nonicons.get('file-directory-fill') - return icon or (conf and conf.directory or ''), hl or 'OilDirIcon' + return icon or (conf and conf.directory or ''), hl or 'CanolaDirIcon' end if ft then local ft_icon, ft_hl = nonicons.get_icon_by_filetype(ft) if ft_icon then - return ft_icon, ft_hl or 'OilFileIcon' + return ft_icon, ft_hl or 'CanolaFileIcon' end end local icon, hl = nonicons.get_icon(name) if icon then - return icon, hl or 'OilFileIcon' + return icon, hl or 'CanolaFileIcon' end local fallback, fallback_hl = nonicons.get('file') - return fallback or (conf and conf.default_file or ''), fallback_hl or 'OilFileIcon' + return fallback or (conf and conf.default_file or ''), fallback_hl or 'CanolaFileIcon' end end @@ -979,7 +979,7 @@ M.get_icon_provider = function() return function(type, name, conf, ft) if type == 'directory' then - return conf and conf.directory or '', 'OilDirIcon' + return conf and conf.directory or '', 'CanolaDirIcon' else if ft then local ft_icon, ft_hl = devicons.get_icon_by_filetype(ft) @@ -988,7 +988,7 @@ M.get_icon_provider = function() end end local icon, hl = devicons.get_icon(name) - hl = hl or 'OilFileIcon' + hl = hl or 'CanolaFileIcon' icon = icon or (conf and conf.default_file or '') return icon, hl end @@ -997,7 +997,7 @@ end ---Read a buffer into a scratch buffer and apply syntactic highlighting when possible ---@param path string The path to the file to read ----@param preview_method oil.PreviewMethod +---@param preview_method canola.PreviewMethod ---@return nil|integer M.read_file_to_scratch_buffer = function(path, preview_method) local bufnr = vim.api.nvim_create_buf(false, true) @@ -1032,7 +1032,7 @@ M.read_file_to_scratch_buffer = function(path, preview_method) -- Replace the scratch buffer with a real buffer if we enter it vim.api.nvim_create_autocmd('BufEnter', { - desc = 'oil.nvim replace scratch buffer with real buffer', + desc = 'canola.nvim replace scratch buffer with real buffer', buffer = bufnr, callback = function() local winid = vim.api.nvim_get_current_win() @@ -1045,7 +1045,7 @@ M.read_file_to_scratch_buffer = function(path, preview_method) -- preview if vim.wo.previewwindow then vim.bo.bufhidden = 'wipe' - vim.b.oil_preview_buffer = true + vim.b.canola_preview_buffer = true end end end) diff --git a/lua/oil/view.lua b/lua/canola/view.lua similarity index 88% rename from lua/oil/view.lua rename to lua/canola/view.lua index e477009..faad884 100644 --- a/lua/oil/view.lua +++ b/lua/canola/view.lua @@ -1,12 +1,12 @@ local uv = vim.uv or vim.loop -local cache = require('oil.cache') -local columns = require('oil.columns') -local config = require('oil.config') -local constants = require('oil.constants') -local fs = require('oil.fs') -local keymap_util = require('oil.keymap_util') -local loading = require('oil.loading') -local util = require('oil.util') +local cache = require('canola.cache') +local columns = require('canola.columns') +local config = require('canola.config') +local constants = require('canola.constants') +local fs = require('canola.fs') +local keymap_util = require('canola.keymap_util') +local loading = require('canola.loading') +local util = require('canola.util') local M = {} local FIELD_ID = constants.FIELD_ID @@ -18,7 +18,7 @@ local FIELD_META = constants.FIELD_META local last_cursor_entry = {} ---@param bufnr integer ----@param entry oil.InternalEntry +---@param entry canola.InternalEntry ---@return boolean display ---@return boolean is_hidden Whether the file is classified as a hidden file M.should_display = function(bufnr, entry) @@ -41,7 +41,7 @@ end ---Set the cursor to the last_cursor_entry if one exists M.maybe_set_cursor = function() - local oil = require('oil') + local canola = require('canola') local bufname = vim.api.nvim_buf_get_name(0) local entry_name = last_cursor_entry[bufname] if not entry_name then @@ -49,7 +49,7 @@ M.maybe_set_cursor = function() end local line_count = vim.api.nvim_buf_line_count(0) for lnum = 1, line_count do - local entry = oil.get_entry_on_line(0, lnum) + local entry = canola.get_entry_on_line(0, lnum) if entry and entry.name == entry_name then local line = vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, true)[1] local id_str = line:match('^/(%d+)') @@ -101,18 +101,18 @@ M.toggle_hidden = function() vim.notify('Cannot toggle hidden files when you have unsaved changes', vim.log.levels.WARN) else config.view_options.show_hidden = not config.view_options.show_hidden - M.rerender_all_oil_buffers({ refetch = false }) + M.rerender_all_canola_buffers({ refetch = false }) end end ----@param is_hidden_file fun(filename: string, bufnr: integer, entry: oil.Entry): boolean +---@param is_hidden_file fun(filename: string, bufnr: integer, entry: canola.Entry): boolean M.set_is_hidden_file = function(is_hidden_file) local any_modified = are_any_modified() if any_modified then vim.notify('Cannot change is_hidden_file when you have unsaved changes', vim.log.levels.WARN) else config.view_options.is_hidden_file = is_hidden_file - M.rerender_all_oil_buffers({ refetch = false }) + M.rerender_all_canola_buffers({ refetch = false }) end end @@ -123,7 +123,7 @@ M.set_columns = function(cols) else config.columns = cols -- TODO only refetch if we don't have all the necessary data for the columns - M.rerender_all_oil_buffers({ refetch = true }) + M.rerender_all_canola_buffers({ refetch = true }) end end @@ -134,15 +134,15 @@ M.set_sort = function(new_sort) else config.view_options.sort = new_sort -- TODO only refetch if we don't have all the necessary data for the columns - M.rerender_all_oil_buffers({ refetch = true }) + M.rerender_all_canola_buffers({ refetch = true }) end end ----@class oil.ViewData +---@class canola.ViewData ---@field fs_event? any uv_fs_event_t -- List of bufnrs ----@type table +---@type table local session = {} ---@return integer[] @@ -151,7 +151,7 @@ M.get_all_buffers = function() end local buffers_locked = false ----Make all oil buffers nomodifiable +---Make all canola buffers nomodifiable M.lock_buffers = function() buffers_locked = true for bufnr in pairs(session) do @@ -161,7 +161,7 @@ M.lock_buffers = function() end end ----Restore normal modifiable settings for oil buffers +---Restore normal modifiable settings for canola buffers M.unlock_buffers = function() buffers_locked = false for bufnr in pairs(session) do @@ -177,8 +177,8 @@ end ---@param opts? table ---@param callback? fun(err: nil|string) ---@note ---- This DISCARDS ALL MODIFICATIONS a user has made to oil buffers -M.rerender_all_oil_buffers = function(opts, callback) +--- This DISCARDS ALL MODIFICATIONS a user has made to canola buffers +M.rerender_all_canola_buffers = function(opts, callback) opts = opts or {} local buffers = M.get_all_buffers() local hidden_buffers = {} @@ -193,7 +193,7 @@ M.rerender_all_oil_buffers = function(opts, callback) local cb = util.cb_collect(#buffers, callback or function() end) for _, bufnr in ipairs(buffers) do if hidden_buffers[bufnr] then - vim.b[bufnr].oil_dirty = opts + vim.b[bufnr].canola_dirty = opts -- We also need to mark this as nomodified so it doesn't interfere with quitting vim vim.bo[bufnr].modified = false vim.schedule(cb) @@ -219,7 +219,7 @@ M.set_win_options = function() end end ----Get a list of visible oil buffers and a list of hidden oil buffers +---Get a list of visible canola buffers and a list of hidden canola buffers ---@note --- If any buffers are modified, return values are nil ---@return nil|integer[] visible @@ -244,7 +244,7 @@ local function get_visible_hidden_buffers() return visible_buffers, vim.tbl_keys(hidden_buffers) end ----Delete unmodified, hidden oil buffers and if none remain, clear the cache +---Delete unmodified, hidden canola buffers and if none remain, clear the cache M.delete_hidden_buffers = function() local visible_buffers, hidden_buffers = get_visible_hidden_buffers() if @@ -261,7 +261,7 @@ M.delete_hidden_buffers = function() cache.clear_everything() end ----@param adapter oil.Adapter +---@param adapter canola.Adapter ---@param ranges table ---@return integer local function get_first_mutable_column_col(adapter, ranges) @@ -278,12 +278,12 @@ local function get_first_mutable_column_col(adapter, ranges) end --- @param bufnr integer ---- @param adapter oil.Adapter +--- @param adapter canola.Adapter --- @param mode false|"name"|"editable" --- @param cur integer[] --- @return integer[] | nil local function calc_constrained_cursor_pos(bufnr, adapter, mode, cur) - local parser = require('oil.mutator.parser') + local parser = require('canola.mutator.parser') local line = vim.api.nvim_buf_get_lines(bufnr, cur[1] - 1, cur[1], true)[1] local column_defs = columns.get_supported_columns(adapter) local result = parser.parse_line(adapter, line, column_defs) @@ -346,14 +346,14 @@ local function redraw_trash_virtual_text(bufnr) if not vim.api.nvim_buf_is_valid(bufnr) or not vim.api.nvim_buf_is_loaded(bufnr) then return end - local parser = require('oil.mutator.parser') + local parser = require('canola.mutator.parser') local adapter = util.get_adapter(bufnr, true) if not adapter or adapter.name ~= 'trash' then return end local _, buf_path = util.parse_url(vim.api.nvim_buf_get_name(bufnr)) local os_path = fs.posix_to_os_path(assert(buf_path)) - local ns = vim.api.nvim_create_namespace('OilVtext') + local ns = vim.api.nvim_create_namespace('CanolaVtext') vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) local column_defs = columns.get_supported_columns(adapter) for lnum, line in ipairs(vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)) do @@ -361,14 +361,14 @@ local function redraw_trash_virtual_text(bufnr) local entry = result and result.entry if entry then local meta = entry[FIELD_META] - ---@type nil|oil.TrashInfo + ---@type nil|canola.TrashInfo local trash_info = meta and meta.trash_info if trash_info then vim.api.nvim_buf_set_extmark(bufnr, ns, lnum - 1, 0, { virt_text = { { '➜ ' .. fs.shorten_path(trash_info.original_path, os_path), - 'OilTrashSourcePath', + 'CanolaTrashSourcePath', }, }, }) @@ -387,13 +387,13 @@ M.initialize = function(bufnr) end vim.api.nvim_clear_autocmds({ buffer = bufnr, - group = 'Oil', + group = 'Canola', }) vim.bo[bufnr].buftype = 'acwrite' vim.bo[bufnr].readonly = false vim.bo[bufnr].swapfile = false - vim.bo[bufnr].syntax = 'oil' - vim.bo[bufnr].filetype = 'oil' + vim.bo[bufnr].syntax = 'canola' + vim.bo[bufnr].filetype = 'canola' vim.b[bufnr].EditorConfig_disable = 1 session[bufnr] = session[bufnr] or {} for k, v in pairs(config.buf_options) do @@ -402,15 +402,15 @@ M.initialize = function(bufnr) vim.api.nvim_buf_call(bufnr, M.set_win_options) vim.api.nvim_create_autocmd('BufHidden', { - desc = 'Delete oil buffers when no longer in use', - group = 'Oil', + desc = 'Delete canola buffers when no longer in use', + group = 'Canola', nested = true, buffer = bufnr, callback = function() -- First wait a short time (100ms) for the buffer change to settle vim.defer_fn(function() local visible_buffers = get_visible_hidden_buffers() - -- Only delete oil buffers if none of them are visible + -- Only delete canola buffers if none of them are visible if visible_buffers and vim.tbl_isempty(visible_buffers) then -- Check if cleanup is enabled if type(config.cleanup_delay_ms) == 'number' then @@ -427,7 +427,7 @@ M.initialize = function(bufnr) end, }) vim.api.nvim_create_autocmd('BufUnload', { - group = 'Oil', + group = 'Canola', nested = true, once = true, buffer = bufnr, @@ -440,20 +440,20 @@ M.initialize = function(bufnr) end, }) vim.api.nvim_create_autocmd('BufEnter', { - group = 'Oil', + group = 'Canola', buffer = bufnr, callback = function(args) - local opts = vim.b[args.buf].oil_dirty + local opts = vim.b[args.buf].canola_dirty if opts then - vim.b[args.buf].oil_dirty = nil + vim.b[args.buf].canola_dirty = nil M.render_buffer_async(args.buf, opts) end end, }) local timer vim.api.nvim_create_autocmd('InsertEnter', { - desc = 'Constrain oil cursor position', - group = 'Oil', + desc = 'Constrain canola cursor position', + group = 'Canola', buffer = bufnr, callback = function() -- For some reason the cursor bounces back to its original position, @@ -462,11 +462,11 @@ M.initialize = function(bufnr) end, }) vim.api.nvim_create_autocmd({ 'CursorMoved', 'ModeChanged' }, { - desc = 'Update oil preview window', - group = 'Oil', + desc = 'Update canola preview window', + group = 'Canola', buffer = bufnr, callback = function() - local oil = require('oil') + local canola = require('canola') if vim.wo.previewwindow then return end @@ -491,14 +491,14 @@ M.initialize = function(bufnr) if vim.api.nvim_get_current_buf() ~= bufnr then return end - local entry = oil.get_cursor_entry() + local entry = canola.get_cursor_entry() -- Don't update in visual mode. Visual mode implies editing not browsing, -- and updating the preview can cause flicker and stutter. if entry and not util.is_visual_mode() then local winid = util.get_preview_win() if winid then - if entry.id ~= vim.w[winid].oil_entry_id then - oil.open_preview() + if entry.id ~= vim.w[winid].canola_entry_id then + canola.open_preview() end end end @@ -532,8 +532,8 @@ M.initialize = function(bufnr) fs_event:stop() return end - local mutator = require('oil.mutator') - if err or vim.bo[bufnr].modified or vim.b[bufnr].oil_dirty or mutator.is_mutating() then + local mutator = require('canola.mutator') + if err or vim.bo[bufnr].modified or vim.b[bufnr].canola_dirty or mutator.is_mutating() then return end @@ -546,7 +546,7 @@ M.initialize = function(bufnr) end -- If it is not currently visible, mark it as dirty - vim.b[bufnr].oil_dirty = {} + vim.b[bufnr].canola_dirty = {} end) ) session[bufnr].fs_event = fs_event @@ -557,7 +557,7 @@ M.initialize = function(bufnr) local debounce_timer = assert(uv.new_timer()) local pending = false vim.api.nvim_create_autocmd('TextChanged', { - desc = 'Update oil virtual text of original path', + desc = 'Update canola virtual text of original path', buffer = bufnr, callback = function() -- Respond immediately to prevent flickering, the set the timer for a "cooldown period" @@ -583,23 +583,23 @@ M.initialize = function(bufnr) M.render_buffer_async(bufnr, {}, function(err) if err then vim.notify( - string.format('Error rendering oil buffer %s: %s', vim.api.nvim_buf_get_name(bufnr), err), + string.format('Error rendering canola buffer %s: %s', vim.api.nvim_buf_get_name(bufnr), err), vim.log.levels.ERROR ) else - vim.b[bufnr].oil_ready = true + vim.b[bufnr].canola_ready = true vim.api.nvim_exec_autocmds( 'User', - { pattern = 'OilEnter', modeline = false, data = { buf = bufnr } } + { pattern = 'CanolaEnter', modeline = false, data = { buf = bufnr } } ) end end) keymap_util.set_keymaps(config.keymaps, bufnr) end ----@param adapter oil.Adapter +---@param adapter canola.Adapter ---@param num_entries integer ----@return fun(a: oil.InternalEntry, b: oil.InternalEntry): boolean +---@return fun(a: canola.InternalEntry, b: canola.InternalEntry): boolean local function get_sort_function(adapter, num_entries) local idx_funs = {} local sort_config = config.view_options.sort @@ -676,7 +676,7 @@ local function render_buffer(bufnr, opts) local entry_list = vim.tbl_values(entries) -- Only sort the entries once we have them all - if not vim.b[bufnr].oil_rendering then + if not vim.b[bufnr].canola_rendering then table.sort(entry_list, get_sort_function(adapter, #entry_list)) end @@ -776,13 +776,13 @@ local function get_link_text(name, meta) end ---@private ----@param entry oil.InternalEntry +---@param entry canola.InternalEntry ---@param column_defs table[] ---@param col_width integer[] ----@param adapter oil.Adapter +---@param adapter canola.Adapter ---@param is_hidden boolean ---@param bufnr integer ----@return oil.TextChunk[] +---@return canola.TextChunk[] M.format_entry_cols = function(entry, column_defs, col_width, adapter, is_hidden, bufnr) local name = entry[FIELD_NAME] local meta = entry[FIELD_META] @@ -857,9 +857,9 @@ M.format_entry_cols = function(entry, column_defs, col_width, adapter, is_hidden end if entry_type == 'directory' then - table.insert(cols, { name .. '/', 'OilDir' .. hl_suffix }) + table.insert(cols, { name .. '/', 'CanolaDir' .. hl_suffix }) elseif entry_type == 'socket' then - table.insert(cols, { name, 'OilSocket' .. hl_suffix }) + table.insert(cols, { name, 'CanolaSocket' .. hl_suffix }) elseif entry_type == 'link' then if not link_name then link_name, link_target = get_link_text(name, meta) @@ -867,23 +867,23 @@ M.format_entry_cols = function(entry, column_defs, col_width, adapter, is_hidden local is_orphan = not (meta and meta.link_stat) if not link_name_hl then if highlight_as_executable then - link_name_hl = 'OilExecutable' .. hl_suffix + link_name_hl = 'CanolaExecutable' .. hl_suffix else - link_name_hl = (is_orphan and 'OilOrphanLink' or 'OilLink') .. hl_suffix + link_name_hl = (is_orphan and 'CanolaOrphanLink' or 'CanolaLink') .. hl_suffix end end table.insert(cols, { link_name, link_name_hl }) if link_target then if not link_target_hl then - link_target_hl = (is_orphan and 'OilOrphanLinkTarget' or 'OilLinkTarget') .. hl_suffix + link_target_hl = (is_orphan and 'CanolaOrphanLinkTarget' or 'CanolaLinkTarget') .. hl_suffix end table.insert(cols, { link_target, link_target_hl }) end elseif highlight_as_executable then - table.insert(cols, { name, 'OilExecutable' .. hl_suffix }) + table.insert(cols, { name, 'CanolaExecutable' .. hl_suffix }) else - table.insert(cols, { name, 'OilFile' .. hl_suffix }) + table.insert(cols, { name, 'CanolaFile' .. hl_suffix }) end return cols @@ -916,7 +916,7 @@ M.render_buffer_async = function(bufnr, opts, caller_callback) if not err then vim.api.nvim_exec_autocmds( 'User', - { pattern = 'OilReadPost', modeline = false, data = { buf = bufnr } } + { pattern = 'CanolaReadPost', modeline = false, data = { buf = bufnr } } ) end if caller_callback then @@ -933,7 +933,7 @@ M.render_buffer_async = function(bufnr, opts, caller_callback) end -- If we're already rendering, queue up another rerender after it's complete - if vim.b[bufnr].oil_rendering then + if vim.b[bufnr].canola_rendering then if not pending_renders[bufnr] then pending_renders[bufnr] = { callback } elseif callback then @@ -943,13 +943,13 @@ M.render_buffer_async = function(bufnr, opts, caller_callback) end local bufname = vim.api.nvim_buf_get_name(bufnr) - vim.b[bufnr].oil_rendering = true + vim.b[bufnr].canola_rendering = true local _, dir = util.parse_url(bufname) -- Undo should not return to a blank buffer -- Method taken from :h clear-undo vim.bo[bufnr].undolevels = -1 local handle_error = vim.schedule_wrap(function(message) - vim.b[bufnr].oil_rendering = false + vim.b[bufnr].canola_rendering = false vim.bo[bufnr].undolevels = vim.api.nvim_get_option_value('undolevels', { scope = 'global' }) util.render_text(bufnr, { 'Error: ' .. message }) if pending_renders[bufnr] then @@ -965,12 +965,12 @@ M.render_buffer_async = function(bufnr, opts, caller_callback) end end) if not dir then - handle_error(string.format("Could not parse oil url '%s'", bufname)) + handle_error(string.format("Could not parse canola url '%s'", bufname)) return end local adapter = util.get_adapter(bufnr, true) if not adapter then - handle_error(string.format("[oil] no adapter for buffer '%s'", bufname)) + handle_error(string.format("[canola] no adapter for buffer '%s'", bufname)) return end local start_ms = uv.hrtime() / 1e6 @@ -984,7 +984,7 @@ M.render_buffer_async = function(bufnr, opts, caller_callback) if not vim.api.nvim_buf_is_valid(bufnr) then return end - vim.b[bufnr].oil_rendering = false + vim.b[bufnr].canola_rendering = false loading.set_loading(bufnr, false) render_buffer(bufnr, { jump = true }) M.set_last_cursor(bufname, nil) diff --git a/lua/oil/adapters/trash.lua b/lua/oil/adapters/trash.lua deleted file mode 100644 index 9ec3e52..0000000 --- a/lua/oil/adapters/trash.lua +++ /dev/null @@ -1,9 +0,0 @@ -local fs = require('oil.fs') - -if fs.is_mac then - return require('oil.adapters.trash.mac') -elseif fs.is_windows then - return require('oil.adapters.trash.windows') -else - return require('oil.adapters.trash.freedesktop') -end diff --git a/lua/resession/extensions/oil.lua b/lua/resession/extensions/canola.lua similarity index 76% rename from lua/resession/extensions/oil.lua rename to lua/resession/extensions/canola.lua index b3ba754..8bbfe86 100644 --- a/lua/resession/extensions/oil.lua +++ b/lua/resession/extensions/canola.lua @@ -1,7 +1,7 @@ local M = {} M.is_win_supported = function(winid, bufnr) - return vim.bo[bufnr].filetype == 'oil' + return vim.bo[bufnr].filetype == 'canola' end M.save_win = function(winid) @@ -11,7 +11,7 @@ M.save_win = function(winid) end M.load_win = function(winid, config) - require('oil').open(config.bufname) + require('canola').open(config.bufname) end return M diff --git a/perf/bootstrap.lua b/perf/bootstrap.lua index 19e17e8..86c170e 100644 --- a/perf/bootstrap.lua +++ b/perf/bootstrap.lua @@ -4,8 +4,8 @@ vim.opt.runtimepath:prepend('.') local bm = require('benchmark') bm.sandbox() ----@module 'oil' ----@type oil.SetupOpts +---@module 'canola' +---@type canola.SetupOpts local setup_opts = { -- columns = { "icon", "permissions", "size", "mtime" }, } @@ -21,36 +21,36 @@ require('benchmark.files').create_files(TEST_DIR, 'file %d.txt', DIR_SIZE) -- selene: allow(global_usage) function _G.jit_profile() - require('oil').setup(setup_opts) + require('canola').setup(setup_opts) local finish = bm.jit_profile({ filename = TEST_DIR .. '/profile.txt' }) - bm.wait_for_user_event('OilEnter', function() + bm.wait_for_user_event('CanolaEnter', function() finish() end) - require('oil').open(TEST_DIR) + require('canola').open(TEST_DIR) end -- selene: allow(global_usage) function _G.flame_profile() local start, stop = bm.flame_profile({ - pattern = 'oil*', + pattern = 'canola*', filename = 'profile.json', }) - require('oil').setup(setup_opts) + require('canola').setup(setup_opts) start() - bm.wait_for_user_event('OilEnter', function() + bm.wait_for_user_event('CanolaEnter', function() stop(function() vim.cmd.qall({ mods = { silent = true } }) end) end) - require('oil').open(TEST_DIR) + require('canola').open(TEST_DIR) end -- selene: allow(global_usage) function _G.benchmark() - require('oil').setup(setup_opts) - bm.run({ title = 'oil.nvim', iterations = ITERATIONS, warm_up = WARM_UP }, function(callback) - bm.wait_for_user_event('OilEnter', callback) - require('oil').open(TEST_DIR) + require('canola').setup(setup_opts) + bm.run({ title = 'canola.nvim', iterations = ITERATIONS, warm_up = WARM_UP }, function(callback) + bm.wait_for_user_event('CanolaEnter', callback) + require('canola').open(TEST_DIR) end, function(times) local avg = bm.avg(times, { trim_outliers = OUTLIERS }) local std_dev = bm.std_dev(times, { trim_outliers = OUTLIERS }) diff --git a/plugin/canola.lua b/plugin/canola.lua new file mode 100644 index 0000000..ee1c0b7 --- /dev/null +++ b/plugin/canola.lua @@ -0,0 +1,3 @@ +if vim.g.canola ~= nil then + require('canola').setup() +end diff --git a/plugin/oil.lua b/plugin/oil.lua deleted file mode 100644 index bcb530d..0000000 --- a/plugin/oil.lua +++ /dev/null @@ -1,3 +0,0 @@ -if vim.g.oil ~= nil then - require('oil').setup() -end diff --git a/spec/altbuf_spec.lua b/spec/altbuf_spec.lua index cd2cf4b..b74a5e2 100644 --- a/spec/altbuf_spec.lua +++ b/spec/altbuf_spec.lua @@ -1,5 +1,5 @@ -local fs = require('oil.fs') -local oil = require('oil') +local canola = require('canola') +local fs = require('canola.fs') local test_util = require('spec.test_util') describe('Alternate buffer', function() @@ -9,27 +9,27 @@ describe('Alternate buffer', function() it('sets previous buffer as alternate', function() vim.cmd.edit({ args = { 'foo' } }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) vim.cmd.edit({ args = { 'bar' } }) assert.equals('foo', vim.fn.expand('#')) end) it('sets previous buffer as alternate when editing url file', function() vim.cmd.edit({ args = { 'foo' } }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) local readme = fs.join(vim.fn.getcwd(), 'README.md') - vim.cmd.edit({ args = { 'oil://' .. fs.os_to_posix_path(readme) } }) + vim.cmd.edit({ args = { 'canola://' .. fs.os_to_posix_path(readme) } }) test_util.wait_for_autocmd('BufEnter') assert.equals(readme, vim.api.nvim_buf_get_name(0)) assert.equals('foo', vim.fn.expand('#')) end) - it('sets previous buffer as alternate when editing oil://', function() + it('sets previous buffer as alternate when editing canola://', function() vim.cmd.edit({ args = { 'foo' } }) - vim.cmd.edit({ args = { 'oil://' .. fs.os_to_posix_path(vim.fn.getcwd()) } }) - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + vim.cmd.edit({ args = { 'canola://' .. fs.os_to_posix_path(vim.fn.getcwd()) } }) + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) vim.cmd.edit({ args = { 'bar' } }) assert.equals('foo', vim.fn.expand('#')) end) @@ -37,8 +37,8 @@ describe('Alternate buffer', function() it('preserves alternate buffer if editing the same file', function() vim.cmd.edit({ args = { 'foo' } }) vim.cmd.edit({ args = { 'bar' } }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) vim.cmd.edit({ args = { 'bar' } }) assert.equals('foo', vim.fn.expand('#')) end) @@ -46,71 +46,71 @@ describe('Alternate buffer', function() it('preserves alternate buffer if discarding changes', function() vim.cmd.edit({ args = { 'foo' } }) vim.cmd.edit({ args = { 'bar' } }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - oil.close() + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + canola.close() assert.equals('bar', vim.fn.expand('%')) assert.equals('foo', vim.fn.expand('#')) end) it('sets previous buffer as alternate after multi-dir hops', function() vim.cmd.edit({ args = { 'foo' } }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) vim.cmd.edit({ args = { 'bar' } }) assert.equals('foo', vim.fn.expand('#')) end) - it('sets previous buffer as alternate when inside oil buffer', function() + it('sets previous buffer as alternate when inside canola buffer', function() vim.cmd.edit({ args = { 'foo' } }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) assert.equals('foo', vim.fn.expand('#')) vim.cmd.edit({ args = { 'bar' } }) assert.equals('foo', vim.fn.expand('#')) - oil.open() + canola.open() assert.equals('bar', vim.fn.expand('#')) end) - it('preserves alternate when traversing oil dirs', function() + it('preserves alternate when traversing canola dirs', function() vim.cmd.edit({ args = { 'foo' } }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) assert.equals('foo', vim.fn.expand('#')) vim.wait(1000, function() - return oil.get_cursor_entry() + return canola.get_cursor_entry() end, 10) vim.api.nvim_win_set_cursor(0, { 1, 1 }) - oil.select() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.select() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) assert.equals('foo', vim.fn.expand('#')) end) it('preserves alternate when opening preview', function() vim.cmd.edit({ args = { 'foo' } }) - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) assert.equals('foo', vim.fn.expand('#')) vim.wait(1000, function() - return oil.get_cursor_entry() + return canola.get_cursor_entry() end, 10) vim.api.nvim_win_set_cursor(0, { 1, 1 }) - oil.open_preview() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open_preview() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) assert.equals('foo', vim.fn.expand('#')) end) describe('floating window', function() it('sets previous buffer as alternate', function() vim.cmd.edit({ args = { 'foo' } }) - oil.open_float() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open_float() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) vim.api.nvim_win_close(0, true) vim.cmd.edit({ args = { 'bar' } }) assert.equals('foo', vim.fn.expand('#')) @@ -119,8 +119,8 @@ describe('Alternate buffer', function() it('preserves alternate buffer if editing the same file', function() vim.cmd.edit({ args = { 'foo' } }) vim.cmd.edit({ args = { 'bar' } }) - oil.open_float() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open_float() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) vim.api.nvim_win_close(0, true) vim.cmd.edit({ args = { 'bar' } }) assert.equals('foo', vim.fn.expand('#')) @@ -129,19 +129,19 @@ describe('Alternate buffer', function() it('preserves alternate buffer if discarding changes', function() vim.cmd.edit({ args = { 'foo' } }) vim.cmd.edit({ args = { 'bar' } }) - oil.open_float() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - oil.close() + canola.open_float() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + canola.close() assert.equals('foo', vim.fn.expand('#')) end) it('preserves alternate when traversing to a new file', function() vim.cmd.edit({ args = { 'foo' } }) - oil.open_float() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open_float() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) assert.equals('foo', vim.fn.expand('#')) test_util.feedkeys({ '/LICENSE' }, 10) - oil.select() + canola.select() test_util.wait_for_autocmd('BufEnter') assert.equals('LICENSE', vim.fn.expand('%:.')) assert.equals('foo', vim.fn.expand('#')) diff --git a/spec/close_spec.lua b/spec/close_spec.lua index 0e15ab7..dc4138e 100644 --- a/spec/close_spec.lua +++ b/spec/close_spec.lua @@ -1,4 +1,4 @@ -local oil = require('oil') +local canola = require('canola') local test_util = require('spec.test_util') describe('close', function() @@ -10,35 +10,35 @@ describe('close', function() end) it('does not close buffer from visual mode', function() - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - assert.equals('oil', vim.bo.filetype) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + assert.equals('canola', vim.bo.filetype) test_util.feedkeys({ 'V' }, 10) - oil.close() - assert.equals('oil', vim.bo.filetype) + canola.close() + assert.equals('canola', vim.bo.filetype) test_util.feedkeys({ '' }, 10) end) it('does not close buffer from operator-pending mode', function() - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - assert.equals('oil', vim.bo.filetype) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + assert.equals('canola', vim.bo.filetype) vim.api.nvim_feedkeys('d', 'n', false) vim.wait(20) local mode = vim.api.nvim_get_mode().mode if mode:match('^no') then - oil.close() - assert.equals('oil', vim.bo.filetype) + canola.close() + assert.equals('canola', vim.bo.filetype) end vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, true, true), 'n', false) vim.wait(20) end) it('closes buffer from normal mode', function() - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - assert.equals('oil', vim.bo.filetype) - oil.close() - assert.not_equals('oil', vim.bo.filetype) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + assert.equals('canola', vim.bo.filetype) + canola.close() + assert.not_equals('canola', vim.bo.filetype) end) end) diff --git a/spec/config_spec.lua b/spec/config_spec.lua index c565c72..bb37e41 100644 --- a/spec/config_spec.lua +++ b/spec/config_spec.lua @@ -1,26 +1,26 @@ -local config = require('oil.config') +local config = require('canola.config') describe('config', function() after_each(function() - vim.g.oil = nil + vim.g.canola = nil end) - it('falls back to vim.g.oil when setup() is called with no args', function() - vim.g.oil = { delete_to_trash = true, cleanup_delay_ms = 5000 } + it('falls back to vim.g.canola when setup() is called with no args', function() + vim.g.canola = { delete_to_trash = true, cleanup_delay_ms = 5000 } config.setup() assert.is_true(config.delete_to_trash) assert.equals(5000, config.cleanup_delay_ms) end) - it('uses defaults when neither opts nor vim.g.oil is set', function() - vim.g.oil = nil + it('uses defaults when neither opts nor vim.g.canola is set', function() + vim.g.canola = nil config.setup() assert.is_false(config.delete_to_trash) assert.equals(2000, config.cleanup_delay_ms) end) - it('prefers explicit opts over vim.g.oil', function() - vim.g.oil = { delete_to_trash = true } + it('prefers explicit opts over vim.g.canola', function() + vim.g.canola = { delete_to_trash = true } config.setup({ delete_to_trash = false }) assert.is_false(config.delete_to_trash) end) diff --git a/spec/files_spec.lua b/spec/files_spec.lua index 299b434..7c430f3 100644 --- a/spec/files_spec.lua +++ b/spec/files_spec.lua @@ -1,5 +1,5 @@ local TmpDir = require('spec.tmpdir') -local files = require('oil.adapters.files') +local files = require('canola.adapters.files') local test_util = require('spec.test_util') describe('files adapter', function() @@ -26,7 +26,7 @@ describe('files adapter', function() it('Creates files', function() local err = test_util.await(files.perform_action, 2, { - url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt', + url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt', entry_type = 'file', type = 'create', }) @@ -38,7 +38,7 @@ describe('files adapter', function() it('Creates directories', function() local err = test_util.await(files.perform_action, 2, { - url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a', + url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a', entry_type = 'directory', type = 'create', }) @@ -50,7 +50,7 @@ describe('files adapter', function() it('Deletes files', function() tmpdir:create({ 'a.txt' }) - local url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' + local url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' local err = test_util.await(files.perform_action, 2, { url = url, entry_type = 'file', @@ -62,7 +62,7 @@ describe('files adapter', function() it('Deletes directories', function() tmpdir:create({ 'a/' }) - local url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' + local url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' local err = test_util.await(files.perform_action, 2, { url = url, entry_type = 'directory', @@ -74,8 +74,8 @@ describe('files adapter', function() it('Moves files', function() tmpdir:create({ 'a.txt' }) - local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' - local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b.txt' + local src_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' + local dest_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b.txt' local err = test_util.await(files.perform_action, 2, { src_url = src_url, dest_url = dest_url, @@ -90,8 +90,8 @@ describe('files adapter', function() it('Moves directories', function() tmpdir:create({ 'a/a.txt' }) - local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' - local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b' + local src_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' + local dest_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b' local err = test_util.await(files.perform_action, 2, { src_url = src_url, dest_url = dest_url, @@ -107,8 +107,8 @@ describe('files adapter', function() it('Copies files', function() tmpdir:create({ 'a.txt' }) - local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' - local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b.txt' + local src_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' + local dest_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b.txt' local err = test_util.await(files.perform_action, 2, { src_url = src_url, dest_url = dest_url, @@ -124,8 +124,8 @@ describe('files adapter', function() it('Recursively copies directories', function() tmpdir:create({ 'a/a.txt' }) - local src_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' - local dest_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b' + local src_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a' + local dest_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b' local err = test_util.await(files.perform_action, 2, { src_url = src_url, dest_url = dest_url, @@ -141,22 +141,22 @@ describe('files adapter', function() }) end) - it('Editing a new oil://path/ creates an oil buffer', function() - local tmpdir_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. '/' + it('Editing a new canola://path/ creates an canola buffer', function() + local tmpdir_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. '/' vim.cmd.edit({ args = { tmpdir_url } }) - test_util.wait_oil_ready() - local new_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'newdir' + test_util.wait_canola_ready() + local new_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'newdir' vim.cmd.edit({ args = { new_url } }) - test_util.wait_oil_ready() - assert.equals('oil', vim.bo.filetype) + test_util.wait_canola_ready() + assert.equals('canola', vim.bo.filetype) assert.equals(new_url .. '/', vim.api.nvim_buf_get_name(0)) end) - it('Editing a new oil://file.rb creates a normal buffer', function() - local tmpdir_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. '/' + it('Editing a new canola://file.rb creates a normal buffer', function() + local tmpdir_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. '/' vim.cmd.edit({ args = { tmpdir_url } }) test_util.wait_for_autocmd('BufReadPost') - local new_url = 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'file.rb' + local new_url = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') .. 'file.rb' vim.cmd.edit({ args = { new_url } }) test_util.wait_for_autocmd('BufReadPost') assert.equals('ruby', vim.bo.filetype) diff --git a/spec/manual_progress.lua b/spec/manual_progress.lua index 593a748..3842674 100644 --- a/spec/manual_progress.lua +++ b/spec/manual_progress.lua @@ -1,5 +1,5 @@ -- Manual test for minimizing/restoring progress window -local Progress = require('oil.mutator.progress') +local Progress = require('canola.mutator.progress') local progress = Progress.new() @@ -13,7 +13,7 @@ for i = 1, 10, 1 do vim.defer_fn(function() progress:set_action({ type = 'create', - url = string.format('oil:///tmp/test_%d.txt', i), + url = string.format('canola:///tmp/test_%d.txt', i), entry_type = 'file', }, i, 10) end, (i - 1) * 1000) diff --git a/spec/move_rename_spec.lua b/spec/move_rename_spec.lua index 5b7348b..7b2d5a5 100644 --- a/spec/move_rename_spec.lua +++ b/spec/move_rename_spec.lua @@ -1,6 +1,6 @@ -local fs = require('oil.fs') +local fs = require('canola.fs') local test_util = require('spec.test_util') -local util = require('oil.util') +local util = require('canola.util') describe('update_moved_buffers', function() after_each(function() @@ -8,51 +8,51 @@ describe('update_moved_buffers', function() end) it('Renames moved buffers', function() - vim.cmd.edit({ args = { 'oil-test:///foo/bar.txt' } }) - util.update_moved_buffers('file', 'oil-test:///foo/bar.txt', 'oil-test:///foo/baz.txt') - assert.equals('oil-test:///foo/baz.txt', vim.api.nvim_buf_get_name(0)) + vim.cmd.edit({ args = { 'canola-test:///foo/bar.txt' } }) + util.update_moved_buffers('file', 'canola-test:///foo/bar.txt', 'canola-test:///foo/baz.txt') + assert.equals('canola-test:///foo/baz.txt', vim.api.nvim_buf_get_name(0)) end) it('Renames moved buffers when they are normal files', function() - local tmpdir = fs.join(vim.loop.fs_realpath(vim.fn.stdpath('cache')), 'oil', 'test') + local tmpdir = fs.join(vim.loop.fs_realpath(vim.fn.stdpath('cache')), 'canola', 'test') local testfile = fs.join(tmpdir, 'foo.txt') vim.cmd.edit({ args = { testfile } }) util.update_moved_buffers( 'file', - 'oil://' .. fs.os_to_posix_path(testfile), - 'oil://' .. fs.os_to_posix_path(fs.join(tmpdir, 'bar.txt')) + 'canola://' .. fs.os_to_posix_path(testfile), + 'canola://' .. fs.os_to_posix_path(fs.join(tmpdir, 'bar.txt')) ) assert.equals(fs.join(tmpdir, 'bar.txt'), vim.api.nvim_buf_get_name(0)) end) it('Renames directories', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) - util.update_moved_buffers('directory', 'oil-test:///foo/', 'oil-test:///bar/') - assert.equals('oil-test:///bar/', vim.api.nvim_buf_get_name(0)) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) + util.update_moved_buffers('directory', 'canola-test:///foo/', 'canola-test:///bar/') + assert.equals('canola-test:///bar/', vim.api.nvim_buf_get_name(0)) end) it('Renames subdirectories', function() - vim.cmd.edit({ args = { 'oil-test:///foo/bar/' } }) - util.update_moved_buffers('directory', 'oil-test:///foo/', 'oil-test:///baz/') - assert.equals('oil-test:///baz/bar/', vim.api.nvim_buf_get_name(0)) + vim.cmd.edit({ args = { 'canola-test:///foo/bar/' } }) + util.update_moved_buffers('directory', 'canola-test:///foo/', 'canola-test:///baz/') + assert.equals('canola-test:///baz/bar/', vim.api.nvim_buf_get_name(0)) end) it('Renames subfiles', function() - vim.cmd.edit({ args = { 'oil-test:///foo/bar.txt' } }) - util.update_moved_buffers('directory', 'oil-test:///foo/', 'oil-test:///baz/') - assert.equals('oil-test:///baz/bar.txt', vim.api.nvim_buf_get_name(0)) + vim.cmd.edit({ args = { 'canola-test:///foo/bar.txt' } }) + util.update_moved_buffers('directory', 'canola-test:///foo/', 'canola-test:///baz/') + assert.equals('canola-test:///baz/bar.txt', vim.api.nvim_buf_get_name(0)) end) it('Renames subfiles when they are normal files', function() - local tmpdir = fs.join(vim.loop.fs_realpath(vim.fn.stdpath('cache')), 'oil', 'test') + local tmpdir = fs.join(vim.loop.fs_realpath(vim.fn.stdpath('cache')), 'canola', 'test') local foo = fs.join(tmpdir, 'foo') local bar = fs.join(tmpdir, 'bar') local testfile = fs.join(foo, 'foo.txt') vim.cmd.edit({ args = { testfile } }) util.update_moved_buffers( 'directory', - 'oil://' .. fs.os_to_posix_path(foo), - 'oil://' .. fs.os_to_posix_path(bar) + 'canola://' .. fs.os_to_posix_path(foo), + 'canola://' .. fs.os_to_posix_path(bar) ) assert.equals(fs.join(bar, 'foo.txt'), vim.api.nvim_buf_get_name(0)) end) diff --git a/spec/mutator_spec.lua b/spec/mutator_spec.lua index 74ce935..2060b6d 100644 --- a/spec/mutator_spec.lua +++ b/spec/mutator_spec.lua @@ -1,7 +1,7 @@ -local cache = require('oil.cache') -local constants = require('oil.constants') -local mutator = require('oil.mutator') -local test_adapter = require('oil.adapters.test') +local cache = require('canola.cache') +local constants = require('canola.constants') +local mutator = require('canola.mutator') +local test_adapter = require('canola.adapters.test') local test_util = require('spec.test_util') local FIELD_ID = constants.FIELD_ID @@ -15,7 +15,7 @@ describe('mutator', function() describe('build actions', function() it('empty diffs produce no actions', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local actions = mutator.create_actions_from_diffs({ [bufnr] = {}, @@ -24,7 +24,7 @@ describe('mutator', function() end) it('constructs CREATE actions', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { { type = 'new', name = 'a.txt', entry_type = 'file' }, @@ -36,14 +36,14 @@ describe('mutator', function() { type = 'create', entry_type = 'file', - url = 'oil-test:///foo/a.txt', + url = 'canola-test:///foo/a.txt', }, }, actions) end) it('constructs DELETE actions', function() local file = test_adapter.test_set('/foo/a.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { { type = 'delete', name = 'a.txt', id = file[FIELD_ID] }, @@ -55,14 +55,14 @@ describe('mutator', function() { type = 'delete', entry_type = 'file', - url = 'oil-test:///foo/a.txt', + url = 'canola-test:///foo/a.txt', }, }, actions) end) it('constructs COPY actions', function() local file = test_adapter.test_set('/foo/a.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { { type = 'new', name = 'b.txt', entry_type = 'file', id = file[FIELD_ID] }, @@ -74,15 +74,15 @@ describe('mutator', function() { type = 'copy', entry_type = 'file', - src_url = 'oil-test:///foo/a.txt', - dest_url = 'oil-test:///foo/b.txt', + src_url = 'canola-test:///foo/a.txt', + dest_url = 'canola-test:///foo/b.txt', }, }, actions) end) it('constructs MOVE actions', function() local file = test_adapter.test_set('/foo/a.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { { type = 'delete', name = 'a.txt', id = file[FIELD_ID] }, @@ -95,15 +95,15 @@ describe('mutator', function() { type = 'move', entry_type = 'file', - src_url = 'oil-test:///foo/a.txt', - dest_url = 'oil-test:///foo/b.txt', + src_url = 'canola-test:///foo/a.txt', + dest_url = 'canola-test:///foo/b.txt', }, }, actions) end) it('correctly orders MOVE + CREATE', function() local file = test_adapter.test_set('/a.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///' } }) + vim.cmd.edit({ args = { 'canola-test:///' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { { type = 'delete', name = 'a.txt', id = file[FIELD_ID] }, @@ -117,13 +117,13 @@ describe('mutator', function() { type = 'move', entry_type = 'file', - src_url = 'oil-test:///a.txt', - dest_url = 'oil-test:///b.txt', + src_url = 'canola-test:///a.txt', + dest_url = 'canola-test:///b.txt', }, { type = 'create', entry_type = 'file', - url = 'oil-test:///a.txt', + url = 'canola-test:///a.txt', }, }, actions) end) @@ -131,7 +131,7 @@ describe('mutator', function() it('resolves MOVE loops', function() local afile = test_adapter.test_set('/a.txt', 'file') local bfile = test_adapter.test_set('/b.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///' } }) + vim.cmd.edit({ args = { 'canola-test:///' } }) local bufnr = vim.api.nvim_get_current_buf() local diffs = { { type = 'delete', name = 'a.txt', id = afile[FIELD_ID] }, @@ -143,25 +143,25 @@ describe('mutator', function() local actions = mutator.create_actions_from_diffs({ [bufnr] = diffs, }) - local tmp_url = 'oil-test:///a.txt__oil_tmp_510852' + local tmp_url = 'canola-test:///a.txt__canola_tmp_510852' assert.are.same({ { type = 'move', entry_type = 'file', - src_url = 'oil-test:///a.txt', + src_url = 'canola-test:///a.txt', dest_url = tmp_url, }, { type = 'move', entry_type = 'file', - src_url = 'oil-test:///b.txt', - dest_url = 'oil-test:///a.txt', + src_url = 'canola-test:///b.txt', + dest_url = 'canola-test:///a.txt', }, { type = 'move', entry_type = 'file', src_url = tmp_url, - dest_url = 'oil-test:///b.txt', + dest_url = 'canola-test:///b.txt', }, }, actions) end) @@ -171,11 +171,11 @@ describe('mutator', function() it('Creates files inside dir before move', function() local move = { type = 'move', - src_url = 'oil-test:///a', - dest_url = 'oil-test:///b', + src_url = 'canola-test:///a', + dest_url = 'canola-test:///b', entry_type = 'directory', } - local create = { type = 'create', url = 'oil-test:///a/hi.txt', entry_type = 'file' } + local create = { type = 'create', url = 'canola-test:///a/hi.txt', entry_type = 'file' } local actions = { move, create } local ordered_actions = mutator.enforce_action_order(actions) assert.are.same({ create, move }, ordered_actions) @@ -184,11 +184,11 @@ describe('mutator', function() it('Moves file out of parent before deleting parent', function() local move = { type = 'move', - src_url = 'oil-test:///a/b.txt', - dest_url = 'oil-test:///b.txt', + src_url = 'canola-test:///a/b.txt', + dest_url = 'canola-test:///b.txt', entry_type = 'file', } - local delete = { type = 'delete', url = 'oil-test:///a', entry_type = 'directory' } + local delete = { type = 'delete', url = 'canola-test:///a', entry_type = 'directory' } local actions = { delete, move } local ordered_actions = mutator.enforce_action_order(actions) assert.are.same({ move, delete }, ordered_actions) @@ -197,14 +197,14 @@ describe('mutator', function() it('Handles parent child move ordering', function() local move1 = { type = 'move', - src_url = 'oil-test:///a/b', - dest_url = 'oil-test:///b', + src_url = 'canola-test:///a/b', + dest_url = 'canola-test:///b', entry_type = 'directory', } local move2 = { type = 'move', - src_url = 'oil-test:///a', - dest_url = 'oil-test:///b/a', + src_url = 'canola-test:///a', + dest_url = 'canola-test:///b/a', entry_type = 'directory', } local actions = { move2, move1 } @@ -215,13 +215,13 @@ describe('mutator', function() it('Handles a delete inside a moved folder', function() local del = { type = 'delete', - url = 'oil-test:///a/b.txt', + url = 'canola-test:///a/b.txt', entry_type = 'file', } local move = { type = 'move', - src_url = 'oil-test:///a', - dest_url = 'oil-test:///b', + src_url = 'canola-test:///a', + dest_url = 'canola-test:///b', entry_type = 'directory', } local actions = { move, del } @@ -232,8 +232,8 @@ describe('mutator', function() it('Detects move directory loops', function() local move = { type = 'move', - src_url = 'oil-test:///a', - dest_url = 'oil-test:///a/b', + src_url = 'canola-test:///a', + dest_url = 'canola-test:///a/b', entry_type = 'directory', } assert.has_error(function() @@ -244,8 +244,8 @@ describe('mutator', function() it('Detects copy directory loops', function() local move = { type = 'copy', - src_url = 'oil-test:///a', - dest_url = 'oil-test:///a/b', + src_url = 'canola-test:///a', + dest_url = 'canola-test:///a/b', entry_type = 'directory', } assert.has_error(function() @@ -256,8 +256,8 @@ describe('mutator', function() it('Detects nested copy directory loops', function() local move = { type = 'copy', - src_url = 'oil-test:///a', - dest_url = 'oil-test:///a/b/a', + src_url = 'canola-test:///a', + dest_url = 'canola-test:///a/b/a', entry_type = 'directory', } assert.has_error(function() @@ -267,10 +267,10 @@ describe('mutator', function() describe('change', function() it('applies CHANGE after CREATE', function() - local create = { type = 'create', url = 'oil-test:///a/hi.txt', entry_type = 'file' } + local create = { type = 'create', url = 'canola-test:///a/hi.txt', entry_type = 'file' } local change = { type = 'change', - url = 'oil-test:///a/hi.txt', + url = 'canola-test:///a/hi.txt', entry_type = 'file', column = 'TEST', value = 'TEST', @@ -283,13 +283,13 @@ describe('mutator', function() it('applies CHANGE after COPY src', function() local copy = { type = 'copy', - src_url = 'oil-test:///a/hi.txt', - dest_url = 'oil-test:///b.txt', + src_url = 'canola-test:///a/hi.txt', + dest_url = 'canola-test:///b.txt', entry_type = 'file', } local change = { type = 'change', - url = 'oil-test:///a/hi.txt', + url = 'canola-test:///a/hi.txt', entry_type = 'file', column = 'TEST', value = 'TEST', @@ -302,13 +302,13 @@ describe('mutator', function() it('applies CHANGE after COPY dest', function() local copy = { type = 'copy', - src_url = 'oil-test:///b.txt', - dest_url = 'oil-test:///a/hi.txt', + src_url = 'canola-test:///b.txt', + dest_url = 'canola-test:///a/hi.txt', entry_type = 'file', } local change = { type = 'change', - url = 'oil-test:///a/hi.txt', + url = 'canola-test:///a/hi.txt', entry_type = 'file', column = 'TEST', value = 'TEST', @@ -321,13 +321,13 @@ describe('mutator', function() it('applies CHANGE after MOVE dest', function() local move = { type = 'move', - src_url = 'oil-test:///b.txt', - dest_url = 'oil-test:///a/hi.txt', + src_url = 'canola-test:///b.txt', + dest_url = 'canola-test:///a/hi.txt', entry_type = 'file', } local change = { type = 'change', - url = 'oil-test:///a/hi.txt', + url = 'canola-test:///a/hi.txt', entry_type = 'file', column = 'TEST', value = 'TEST', @@ -342,10 +342,10 @@ describe('mutator', function() describe('perform actions', function() it('creates new entries', function() local actions = { - { type = 'create', url = 'oil-test:///a.txt', entry_type = 'file' }, + { type = 'create', url = 'canola-test:///a.txt', entry_type = 'file' }, } test_util.await(mutator.process_actions, 2, actions) - local files = cache.list_url('oil-test:///') + local files = cache.list_url('canola-test:///') assert.are.same({ ['a.txt'] = { [FIELD_ID] = 1, @@ -358,10 +358,10 @@ describe('mutator', function() it('deletes entries', function() local file = test_adapter.test_set('/a.txt', 'file') local actions = { - { type = 'delete', url = 'oil-test:///a.txt', entry_type = 'file' }, + { type = 'delete', url = 'canola-test:///a.txt', entry_type = 'file' }, } test_util.await(mutator.process_actions, 2, actions) - local files = cache.list_url('oil-test:///') + local files = cache.list_url('canola-test:///') assert.are.same({}, files) assert.is_nil(cache.get_entry_by_id(file[FIELD_ID])) assert.has_error(function() @@ -374,13 +374,13 @@ describe('mutator', function() local actions = { { type = 'move', - src_url = 'oil-test:///a.txt', - dest_url = 'oil-test:///b.txt', + src_url = 'canola-test:///a.txt', + dest_url = 'canola-test:///b.txt', entry_type = 'file', }, } test_util.await(mutator.process_actions, 2, actions) - local files = cache.list_url('oil-test:///') + local files = cache.list_url('canola-test:///') local new_entry = { [FIELD_ID] = file[FIELD_ID], [FIELD_TYPE] = 'file', @@ -390,7 +390,7 @@ describe('mutator', function() ['b.txt'] = new_entry, }, files) assert.are.same(new_entry, cache.get_entry_by_id(file[FIELD_ID])) - assert.equals('oil-test:///', cache.get_parent_url(file[FIELD_ID])) + assert.equals('canola-test:///', cache.get_parent_url(file[FIELD_ID])) end) it('copies entries', function() @@ -398,13 +398,13 @@ describe('mutator', function() local actions = { { type = 'copy', - src_url = 'oil-test:///a.txt', - dest_url = 'oil-test:///b.txt', + src_url = 'canola-test:///a.txt', + dest_url = 'canola-test:///b.txt', entry_type = 'file', }, } test_util.await(mutator.process_actions, 2, actions) - local files = cache.list_url('oil-test:///') + local files = cache.list_url('canola-test:///') local new_entry = { [FIELD_ID] = file[FIELD_ID] + 1, [FIELD_TYPE] = 'file', diff --git a/spec/parser_spec.lua b/spec/parser_spec.lua index 563c001..ffc638b 100644 --- a/spec/parser_spec.lua +++ b/spec/parser_spec.lua @@ -1,9 +1,9 @@ -local constants = require('oil.constants') -local parser = require('oil.mutator.parser') -local test_adapter = require('oil.adapters.test') +local constants = require('canola.constants') +local parser = require('canola.mutator.parser') +local test_adapter = require('canola.adapters.test') local test_util = require('spec.test_util') -local util = require('oil.util') -local view = require('oil.view') +local util = require('canola.util') +local view = require('canola.view') local FIELD_ID = constants.FIELD_ID local FIELD_META = constants.FIELD_META @@ -19,7 +19,7 @@ describe('parser', function() end) it('detects new files', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { 'a.txt', @@ -29,7 +29,7 @@ describe('parser', function() end) it('detects new directories', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { 'foo/', @@ -39,7 +39,7 @@ describe('parser', function() end) it('detects new links', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { 'a.txt -> b.txt', @@ -53,7 +53,7 @@ describe('parser', function() it('detects deleted files', function() local file = test_adapter.test_set('/foo/a.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, {}) local diffs = parser.parse(bufnr) @@ -64,7 +64,7 @@ describe('parser', function() it('detects deleted directories', function() local dir = test_adapter.test_set('/foo/bar', 'directory') - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, {}) local diffs = parser.parse(bufnr) @@ -76,7 +76,7 @@ describe('parser', function() it('detects deleted links', function() local file = test_adapter.test_set('/foo/a.txt', 'link') file[FIELD_META] = { link = 'b.txt' } - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, {}) local diffs = parser.parse(bufnr) @@ -87,7 +87,7 @@ describe('parser', function() it('ignores empty lines', function() local file = test_adapter.test_set('/foo/a.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() local cols = view.format_entry_cols(file, {}, {}, test_adapter, false) local lines = util.render_table({ cols }, {}) @@ -99,7 +99,7 @@ describe('parser', function() end) it('errors on missing filename', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { '/008', @@ -116,7 +116,7 @@ describe('parser', function() end) it('errors on empty dirname', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { '/008 /', @@ -133,7 +133,7 @@ describe('parser', function() end) it('errors on duplicate names', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { 'foo', @@ -152,7 +152,7 @@ describe('parser', function() it('errors on duplicate names for existing files', function() local file = test_adapter.test_set('/foo/a.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { 'a.txt', @@ -170,7 +170,7 @@ describe('parser', function() end) it('ignores new dirs with empty name', function() - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { '/', @@ -181,7 +181,7 @@ describe('parser', function() it('parses a rename as a delete + new', function() local file = test_adapter.test_set('/foo/a.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { string.format('/%d b.txt', file[FIELD_ID]), @@ -195,7 +195,7 @@ describe('parser', function() it('detects a new trailing slash as a delete + create', function() local file = test_adapter.test_set('/foo', 'file') - vim.cmd.edit({ args = { 'oil-test:///' } }) + vim.cmd.edit({ args = { 'canola-test:///' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { string.format('/%d foo/', file[FIELD_ID]), @@ -210,7 +210,7 @@ describe('parser', function() it('detects renamed files that conflict', function() local afile = test_adapter.test_set('/foo/a.txt', 'file') local bfile = test_adapter.test_set('/foo/b.txt', 'file') - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { string.format('/%d a.txt', bfile[FIELD_ID]), @@ -238,7 +238,7 @@ describe('parser', function() it('views link targets with trailing slashes as the same', function() local file = test_adapter.test_set('/foo/mydir', 'link') file[FIELD_META] = { link = 'dir/' } - vim.cmd.edit({ args = { 'oil-test:///foo/' } }) + vim.cmd.edit({ args = { 'canola-test:///foo/' } }) local bufnr = vim.api.nvim_get_current_buf() set_lines(bufnr, { string.format('/%d mydir/ -> dir/', file[FIELD_ID]), diff --git a/spec/path_spec.lua b/spec/path_spec.lua index ab83fe4..f066d1c 100644 --- a/spec/path_spec.lua +++ b/spec/path_spec.lua @@ -1,4 +1,4 @@ -local pathutil = require('oil.pathutil') +local pathutil = require('canola.pathutil') describe('pathutil', function() it('calculates parent path', function() local cases = { diff --git a/spec/preview_spec.lua b/spec/preview_spec.lua index 030332d..137c9f9 100644 --- a/spec/preview_spec.lua +++ b/spec/preview_spec.lua @@ -1,9 +1,9 @@ local TmpDir = require('spec.tmpdir') -local oil = require('oil') +local canola = require('canola') local test_util = require('spec.test_util') -local util = require('oil.util') +local util = require('canola.util') -describe('oil preview', function() +describe('canola preview', function() local tmpdir before_each(function() tmpdir = TmpDir.new() @@ -17,8 +17,8 @@ describe('oil preview', function() it('opens preview window', function() tmpdir:create({ 'a.txt' }) - test_util.oil_open(tmpdir.path) - test_util.await(oil.open_preview, 2) + test_util.canola_open(tmpdir.path) + test_util.await(canola.open_preview, 2) local preview_win = util.get_preview_win() assert.not_nil(preview_win) assert(preview_win) @@ -29,7 +29,7 @@ describe('oil preview', function() it('opens preview window when open(preview={})', function() tmpdir:create({ 'a.txt' }) - test_util.oil_open(tmpdir.path, { preview = {} }) + test_util.canola_open(tmpdir.path, { preview = {} }) local preview_win = util.get_preview_win() assert.not_nil(preview_win) assert(preview_win) diff --git a/spec/regression_spec.lua b/spec/regression_spec.lua index bfa5e53..fddb1f8 100644 --- a/spec/regression_spec.lua +++ b/spec/regression_spec.lua @@ -1,8 +1,8 @@ local TmpDir = require('spec.tmpdir') -local actions = require('oil.actions') -local oil = require('oil') +local actions = require('canola.actions') +local canola = require('canola') local test_util = require('spec.test_util') -local view = require('oil.view') +local view = require('canola.view') describe('regression tests', function() local tmpdir @@ -21,29 +21,29 @@ describe('regression tests', function() vim.cmd.edit({ args = { 'README.md' } }) vim.cmd.vsplit() vim.cmd.edit({ args = { '%:p:h' } }) - assert.equals('oil', vim.bo.filetype) + assert.equals('canola', vim.bo.filetype) vim.cmd.wincmd({ args = { 'p' } }) assert.equals('markdown', vim.bo.filetype) vim.cmd.edit({ args = { '%:p:h' } }) - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - assert.equals('oil', vim.bo.filetype) + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + assert.equals('canola', vim.bo.filetype) end) it('places the cursor on correct entry when opening on file', function() vim.cmd.edit({ args = { '.' } }) - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - local entry = oil.get_cursor_entry() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + local entry = canola.get_cursor_entry() assert.not_nil(entry) assert.not_equals('README.md', entry and entry.name) vim.cmd.edit({ args = { 'README.md' } }) view.delete_hidden_buffers() - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - entry = oil.get_cursor_entry() + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + entry = canola.get_cursor_entry() assert.equals('README.md', entry and entry.name) end) - it("doesn't close floating windows oil didn't open itself", function() + it("doesn't close floating windows canola didn't open itself", function() local winid = vim.api.nvim_open_win(vim.fn.bufadd('README.md'), true, { relative = 'editor', row = 1, @@ -51,21 +51,21 @@ describe('regression tests', function() width = 100, height = 100, }) - oil.open() + canola.open() vim.wait(10) - oil.close() + canola.close() vim.wait(10) assert.equals(winid, vim.api.nvim_get_current_win()) end) - it("doesn't close splits on oil.close", function() + it("doesn't close splits on canola.close", function() vim.cmd.edit({ args = { 'README.md' } }) vim.cmd.vsplit() local winid = vim.api.nvim_get_current_win() local bufnr = vim.api.nvim_get_current_buf() - oil.open() + canola.open() vim.wait(10) - oil.close() + canola.close() vim.wait(10) assert.equals(2, #vim.api.nvim_tabpage_list_wins(0)) assert.equals(winid, vim.api.nvim_get_current_win()) @@ -73,24 +73,24 @@ describe('regression tests', function() end) it('Returns to empty buffer on close', function() - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - oil.close() - assert.not_equals('oil', vim.bo.filetype) + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + canola.close() + assert.not_equals('canola', vim.bo.filetype) assert.equals('', vim.api.nvim_buf_get_name(0)) end) it('All buffers set nomodified after save', function() tmpdir:create({ 'a.txt' }) - vim.cmd.edit({ args = { 'oil://' .. vim.fn.fnamemodify(tmpdir.path, ':p') } }) + vim.cmd.edit({ args = { 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') } }) local first_dir = vim.api.nvim_get_current_buf() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) test_util.feedkeys({ 'dd', 'itest/', '' }, 10) vim.wait(1000, function() return vim.bo.modifiable end, 10) test_util.feedkeys({ 'p' }, 10) - oil.save({ confirm = false }) + canola.save({ confirm = false }) vim.wait(1000, function() return vim.bo.modifiable end, 10) @@ -102,11 +102,11 @@ describe('regression tests', function() it("refreshing buffer doesn't lose track of it", function() vim.cmd.edit({ args = { '.' } }) - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) local bufnr = vim.api.nvim_get_current_buf() vim.cmd.edit({ bang = true }) - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - assert.are.same({ bufnr }, require('oil.view').get_all_buffers()) + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + assert.are.same({ bufnr }, require('canola.view').get_all_buffers()) end) it('can copy a file multiple times', function() @@ -126,8 +126,8 @@ describe('regression tests', function() it('can open files from floating window', function() tmpdir:create({ 'a.txt' }) - oil.open_float(tmpdir.path) - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + canola.open_float(tmpdir.path) + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) actions.select.callback() vim.wait(1000, function() return vim.fn.expand('%:t') == 'a.txt' diff --git a/spec/select_spec.lua b/spec/select_spec.lua index 47c95ac..6708618 100644 --- a/spec/select_spec.lua +++ b/spec/select_spec.lua @@ -1,52 +1,52 @@ -local oil = require('oil') +local canola = require('canola') local test_util = require('spec.test_util') -describe('oil select', function() +describe('canola select', function() after_each(function() test_util.reset_editor() end) it('opens file under cursor', function() - test_util.oil_open() + test_util.canola_open() vim.cmd.normal({ args = { 'G' } }) - test_util.await(oil.select, 2) + test_util.await(canola.select, 2) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) - assert.not_equals('oil', vim.bo.filetype) + assert.not_equals('canola', vim.bo.filetype) end) it('opens file in new tab', function() - test_util.oil_open() + test_util.canola_open() local tabpage = vim.api.nvim_get_current_tabpage() - test_util.await(oil.select, 2, { tab = true }) + test_util.await(canola.select, 2, { tab = true }) assert.equals(2, #vim.api.nvim_list_tabpages()) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals(tabpage, vim.api.nvim_get_current_tabpage()) end) it('opens file in new split', function() - test_util.oil_open() + test_util.canola_open() local winid = vim.api.nvim_get_current_win() - test_util.await(oil.select, 2, { vertical = true }) + test_util.await(canola.select, 2, { vertical = true }) assert.equals(1, #vim.api.nvim_list_tabpages()) assert.equals(2, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals(winid, vim.api.nvim_get_current_win()) end) it('opens multiple files in new tabs', function() - test_util.oil_open() + test_util.canola_open() vim.api.nvim_feedkeys('Vj', 'x', true) local tabpage = vim.api.nvim_get_current_tabpage() - test_util.await(oil.select, 2, { tab = true }) + test_util.await(canola.select, 2, { tab = true }) assert.equals(3, #vim.api.nvim_list_tabpages()) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals(tabpage, vim.api.nvim_get_current_tabpage()) end) it('opens multiple files in new splits', function() - test_util.oil_open() + test_util.canola_open() vim.api.nvim_feedkeys('Vj', 'x', true) local winid = vim.api.nvim_get_current_win() - test_util.await(oil.select, 2, { vertical = true }) + test_util.await(canola.select, 2, { vertical = true }) assert.equals(1, #vim.api.nvim_list_tabpages()) assert.equals(3, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals(winid, vim.api.nvim_get_current_win()) @@ -56,20 +56,20 @@ describe('oil select', function() it('same window', function() vim.cmd.edit({ args = { 'foo' } }) local bufnr = vim.api.nvim_get_current_buf() - test_util.oil_open() + test_util.canola_open() vim.cmd.normal({ args = { 'G' } }) - test_util.await(oil.select, 2, { close = true }) + test_util.await(canola.select, 2, { close = true }) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) assert.not_equals(bufnr, vim.api.nvim_get_current_buf()) - assert.not_equals('oil', vim.bo.filetype) + assert.not_equals('canola', vim.bo.filetype) end) it('split', function() vim.cmd.edit({ args = { 'foo' } }) local bufnr = vim.api.nvim_get_current_buf() local winid = vim.api.nvim_get_current_win() - test_util.oil_open() - test_util.await(oil.select, 2, { vertical = true, close = true }) + test_util.canola_open() + test_util.await(canola.select, 2, { vertical = true, close = true }) assert.equals(2, #vim.api.nvim_tabpage_list_wins(0)) assert.equals(bufnr, vim.api.nvim_win_get_buf(winid)) end) @@ -78,8 +78,8 @@ describe('oil select', function() vim.cmd.edit({ args = { 'foo' } }) local bufnr = vim.api.nvim_get_current_buf() local tabpage = vim.api.nvim_get_current_tabpage() - test_util.oil_open() - test_util.await(oil.select, 2, { tab = true, close = true }) + test_util.canola_open() + test_util.await(canola.select, 2, { tab = true, close = true }) assert.equals(1, #vim.api.nvim_tabpage_list_wins(0)) assert.equals(2, #vim.api.nvim_list_tabpages()) vim.api.nvim_set_current_tabpage(tabpage) diff --git a/spec/test_util.lua b/spec/test_util.lua index 57f81b1..3afdf75 100644 --- a/spec/test_util.lua +++ b/spec/test_util.lua @@ -1,13 +1,13 @@ -local cache = require('oil.cache') -local test_adapter = require('oil.adapters.test') -local util = require('oil.util') +local cache = require('canola.cache') +local test_adapter = require('canola.adapters.test') +local util = require('canola.util') local M = {} M.reset_editor = function() - require('oil').setup({ + require('canola').setup({ columms = {}, adapters = { - ['oil-test://'] = 'test', + ['canola-test://'] = 'test', }, prompt_save_on_select_new_entry = false, }) @@ -53,8 +53,8 @@ M.await_throwiferr = function(fn, nargs, ...) return throwiferr(M.await(fn, nargs, ...)) end -M.oil_open = function(...) - M.await(require('oil').open, 3, ...) +M.canola_open = function(...) + M.await(require('canola').open, 3, ...) end M.wait_for_autocmd = function(autocmd) @@ -81,7 +81,7 @@ M.wait_for_autocmd = function(autocmd) end end -M.wait_oil_ready = function() +M.wait_canola_ready = function() local ready = false util.run_after_load( 0, @@ -93,7 +93,7 @@ M.wait_oil_ready = function() return ready end, 10) if not ready then - error('wait_oil_ready timed out') + error('wait_canola_ready timed out') end end @@ -113,34 +113,34 @@ M.feedkeys = function(actions, timestep) end M.actions = { - ---Open oil and wait for it to finish rendering + ---Open canola and wait for it to finish rendering ---@param args string[] open = function(args) vim.schedule(function() - vim.cmd.Oil({ args = args }) - if vim.b.oil_ready then + vim.cmd.Canola({ args = args }) + if vim.b.canola_ready then vim.api.nvim_exec_autocmds('User', { - pattern = 'OilEnter', + pattern = 'CanolaEnter', modeline = false, data = { buf = vim.api.nvim_get_current_buf() }, }) end end) - M.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) + M.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) end, ---Save all changes and wait for operation to complete save = function() - vim.schedule_wrap(require('oil').save)({ confirm = false }) - M.wait_for_autocmd({ 'User', pattern = 'OilMutationComplete' }) + vim.schedule_wrap(require('canola').save)({ confirm = false }) + M.wait_for_autocmd({ 'User', pattern = 'CanolaMutationComplete' }) end, ---@param bufnr? integer reload = function(bufnr) - M.await(require('oil.view').render_buffer_async, 3, bufnr or 0) + M.await(require('canola.view').render_buffer_async, 3, bufnr or 0) end, - ---Move cursor to a file or directory in an oil buffer + ---Move cursor to a file or directory in an canola buffer ---@param filename string focus = function(filename) local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true) @@ -155,13 +155,13 @@ M.actions = { end, } ----Get the raw list of filenames from an unmodified oil buffer +---Get the raw list of filenames from an unmodified canola buffer ---@param bufnr? integer ---@return string[] M.parse_entries = function(bufnr) bufnr = bufnr or 0 if vim.bo[bufnr].modified then - error("parse_entries doesn't work on a modified oil buffer") + error("parse_entries doesn't work on a modified canola buffer") end local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) return vim.tbl_map(function(line) diff --git a/spec/tmpdir.lua b/spec/tmpdir.lua index 00a04fd..42dd44e 100644 --- a/spec/tmpdir.lua +++ b/spec/tmpdir.lua @@ -1,4 +1,4 @@ -local fs = require('oil.fs') +local fs = require('canola.fs') local test_util = require('spec.test_util') ---@param path string @@ -25,7 +25,7 @@ end local TmpDir = {} TmpDir.new = function() - local path, err = vim.loop.fs_mkdtemp('oil_test_XXXXXXXXX') + local path, err = vim.loop.fs_mkdtemp('canola_test_XXXXXXXXX') if not path then error(err) end diff --git a/spec/trash_spec.lua b/spec/trash_spec.lua index b34b40b..f3db67f 100644 --- a/spec/trash_spec.lua +++ b/spec/trash_spec.lua @@ -6,10 +6,10 @@ describe('freedesktop', function() local tmphome local home = vim.env.XDG_DATA_HOME before_each(function() - require('oil.config').delete_to_trash = true + require('canola.config').delete_to_trash = true tmpdir = TmpDir.new() tmphome = TmpDir.new() - package.loaded['oil.adapters.trash'] = require('oil.adapters.trash.freedesktop') + package.loaded['canola.adapters.trash'] = require('canola.adapters.trash.freedesktop') vim.env.XDG_DATA_HOME = tmphome.path end) after_each(function() @@ -21,7 +21,7 @@ describe('freedesktop', function() tmphome:dispose() end test_util.reset_editor() - package.loaded['oil.adapters.trash'] = nil + package.loaded['canola.adapters.trash'] = nil end) it('files can be moved to the trash', function() diff --git a/spec/url_spec.lua b/spec/url_spec.lua index 46b7af7..68dfc3f 100644 --- a/spec/url_spec.lua +++ b/spec/url_spec.lua @@ -1,19 +1,26 @@ -local oil = require('oil') -local util = require('oil.util') +local canola = require('canola') +local util = require('canola.util') describe('url', function() it('get_url_for_path', function() local cases = { - { '', 'oil://' .. util.addslash(vim.fn.getcwd()) }, - { 'term://~/oil.nvim//52953:/bin/sh', 'oil://' .. vim.loop.os_homedir() .. '/oil.nvim/' }, - { '/foo/bar.txt', 'oil:///foo/', 'bar.txt' }, - { 'oil:///foo/bar.txt', 'oil:///foo/', 'bar.txt' }, - { 'oil:///', 'oil:///' }, - { 'oil-ssh://user@hostname:8888//bar.txt', 'oil-ssh://user@hostname:8888//', 'bar.txt' }, - { 'oil-ssh://user@hostname:8888//', 'oil-ssh://user@hostname:8888//' }, + { '', 'canola://' .. util.addslash(vim.fn.getcwd()) }, + { + 'term://~/canola.nvim//52953:/bin/sh', + 'canola://' .. vim.loop.os_homedir() .. '/canola.nvim/', + }, + { '/foo/bar.txt', 'canola:///foo/', 'bar.txt' }, + { 'canola:///foo/bar.txt', 'canola:///foo/', 'bar.txt' }, + { 'canola:///', 'canola:///' }, + { + 'canola-ssh://user@hostname:8888//bar.txt', + 'canola-ssh://user@hostname:8888//', + 'bar.txt', + }, + { 'canola-ssh://user@hostname:8888//', 'canola-ssh://user@hostname:8888//' }, } for _, case in ipairs(cases) do local input, expected, expected_basename = unpack(case) - local output, basename = oil.get_buffer_parent_url(input, true) + local output, basename = canola.get_buffer_parent_url(input, true) assert.equals(expected, output, string.format('Parent url for path "%s" failed', input)) assert.equals( expected_basename, diff --git a/spec/util_spec.lua b/spec/util_spec.lua index 5796398..bb8fce9 100644 --- a/spec/util_spec.lua +++ b/spec/util_spec.lua @@ -1,4 +1,4 @@ -local util = require('oil.util') +local util = require('canola.util') describe('util', function() it('url_escape', function() local cases = { diff --git a/spec/win_options_spec.lua b/spec/win_options_spec.lua index f62aa83..54f94f2 100644 --- a/spec/win_options_spec.lua +++ b/spec/win_options_spec.lua @@ -1,4 +1,4 @@ -local oil = require('oil') +local canola = require('canola') local test_util = require('spec.test_util') describe('window options', function() @@ -8,28 +8,28 @@ describe('window options', function() it('Restores window options on close', function() vim.cmd.edit({ args = { 'README.md' } }) - test_util.oil_open() + test_util.canola_open() assert.equals('no', vim.o.signcolumn) - oil.close() + canola.close() assert.equals('auto', vim.o.signcolumn) end) it('Restores window options on edit', function() - test_util.oil_open() + test_util.canola_open() assert.equals('no', vim.o.signcolumn) vim.cmd.edit({ args = { 'README.md' } }) assert.equals('auto', vim.o.signcolumn) end) it('Restores window options on split ', function() - test_util.oil_open() + test_util.canola_open() assert.equals('no', vim.o.signcolumn) vim.cmd.split({ args = { 'README.md' } }) assert.equals('auto', vim.o.signcolumn) end) it('Restores window options on split', function() - test_util.oil_open() + test_util.canola_open() assert.equals('no', vim.o.signcolumn) vim.cmd.split() vim.cmd.edit({ args = { 'README.md' } }) @@ -37,29 +37,29 @@ describe('window options', function() end) it('Restores window options on tabnew ', function() - test_util.oil_open() + test_util.canola_open() assert.equals('no', vim.o.signcolumn) vim.cmd.tabnew({ args = { 'README.md' } }) assert.equals('auto', vim.o.signcolumn) end) it('Restores window options on tabnew', function() - test_util.oil_open() + test_util.canola_open() assert.equals('no', vim.o.signcolumn) vim.cmd.tabnew() vim.cmd.edit({ args = { 'README.md' } }) assert.equals('auto', vim.o.signcolumn) end) - it('Sets the window options when re-entering oil buffer', function() - oil.open() - test_util.wait_for_autocmd({ 'User', pattern = 'OilEnter' }) - assert.truthy(vim.w.oil_did_enter) + it('Sets the window options when re-entering canola buffer', function() + canola.open() + test_util.wait_for_autocmd({ 'User', pattern = 'CanolaEnter' }) + assert.truthy(vim.w.canola_did_enter) vim.cmd.edit({ args = { 'README.md' } }) - assert.falsy(vim.w.oil_did_enter) - oil.open() - assert.truthy(vim.w.oil_did_enter) + assert.falsy(vim.w.canola_did_enter) + canola.open() + assert.truthy(vim.w.canola_did_enter) vim.cmd.vsplit() - assert.truthy(vim.w.oil_did_enter) + assert.truthy(vim.w.canola_did_enter) end) end) diff --git a/syntax/canola.vim b/syntax/canola.vim new file mode 100644 index 0000000..330abc7 --- /dev/null +++ b/syntax/canola.vim @@ -0,0 +1,7 @@ +if exists("b:current_syntax") + finish +endif + +syn match canolaId /^\/\d* / conceal + +let b:current_syntax = "canola" diff --git a/syntax/canola_preview.vim b/syntax/canola_preview.vim new file mode 100644 index 0000000..2473f1e --- /dev/null +++ b/syntax/canola_preview.vim @@ -0,0 +1,15 @@ +if exists("b:current_syntax") + finish +endif + +syn match canolaCreate /^CREATE\( BUCKET\)\? / +syn match canolaMove /^ MOVE / +syn match canolaDelete /^DELETE\( BUCKET\)\? / +syn match canolaCopy /^ COPY / +syn match canolaChange /^CHANGE / +" Trash operations +syn match canolaRestore /^RESTORE / +syn match canolaPurge /^ PURGE / +syn match canolaTrash /^ TRASH / + +let b:current_syntax = "canola_preview" diff --git a/syntax/oil.vim b/syntax/oil.vim deleted file mode 100644 index 0f2a4a3..0000000 --- a/syntax/oil.vim +++ /dev/null @@ -1,7 +0,0 @@ -if exists("b:current_syntax") - finish -endif - -syn match oilId /^\/\d* / conceal - -let b:current_syntax = "oil" diff --git a/syntax/oil_preview.vim b/syntax/oil_preview.vim deleted file mode 100644 index 2f14df9..0000000 --- a/syntax/oil_preview.vim +++ /dev/null @@ -1,15 +0,0 @@ -if exists("b:current_syntax") - finish -endif - -syn match oilCreate /^CREATE\( BUCKET\)\? / -syn match oilMove /^ MOVE / -syn match oilDelete /^DELETE\( BUCKET\)\? / -syn match oilCopy /^ COPY / -syn match oilChange /^CHANGE / -" Trash operations -syn match oilRestore /^RESTORE / -syn match oilPurge /^ PURGE / -syn match oilTrash /^ TRASH / - -let b:current_syntax = "oil_preview" From c3de0004d18e4578997b7330f31e419f5a50a87e Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 5 Mar 2026 14:53:30 -0500 Subject: [PATCH 52/77] ci: format --- lua/canola/init.lua | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lua/canola/init.lua b/lua/canola/init.lua index 81837fa..5d6d06a 100644 --- a/lua/canola/init.lua +++ b/lua/canola/init.lua @@ -1217,16 +1217,12 @@ M.setup = function(opts) end M[method](path, open_opts) end - vim.api.nvim_create_user_command( - 'Canola', - callback, - { - desc = 'Open canola file browser on a directory', - nargs = '*', - complete = 'dir', - count = true, - } - ) + vim.api.nvim_create_user_command('Canola', callback, { + desc = 'Open canola file browser on a directory', + nargs = '*', + complete = 'dir', + count = true, + }) local aug = vim.api.nvim_create_augroup('Canola', {}) if config.default_file_explorer then From 41f375ee9e73e8ca77d857414dac669330aae336 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:55:37 -0500 Subject: [PATCH 53/77] fix: restore `buflisted` on jumplist buffer re-entry (#71) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: restore `buflisted` on jumplist buffer re-entry Problem: Neovim's jumplist machinery re-enters canola buffers via an internal `:edit`-equivalent path, which unconditionally sets `buflisted = true`. The existing workaround in `open()` and `open_float()` only covers canola-initiated navigation, leaving `` and `` unhandled. Solution: Apply the same `buf_options.buflisted` guard in the `BufEnter` autocmd, directly after `set_win_options()`. This fires on every buffer entry — including all jumplist paths — and mirrors the pattern already used at the two `:edit` callsites. * docs: mark upstream #302 as fixed in tracker --- doc/upstream.md | 3 ++- lua/canola/init.lua | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/upstream.md b/doc/upstream.md index f83b4a2..b85fa6e 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -28,6 +28,7 @@ Bugs fixed in this fork that remain open upstream. | Upstream issue | Description | PR | | ------------------------------------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | +| [#302](https://github.com/stevearc/oil.nvim/issues/302) | `buflisted=true` after jumplist nav | [#71](https://github.com/barrettruth/canola.nvim/pull/71) ([`a078bcf`](https://github.com/barrettruth/canola.nvim/commit/a078bcf)) | | [#632](https://github.com/stevearc/oil.nvim/issues/632) | Preview + move = copy | [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | | [#642](https://github.com/stevearc/oil.nvim/issues/642) | W10 warning under `nvim -R` | [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | | [#670](https://github.com/stevearc/oil.nvim/issues/670) | Multi-directory cmdline args ignored | [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | @@ -74,7 +75,7 @@ addressed, `open` = not yet triaged. | [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | | [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | | [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | -| [#302](https://github.com/stevearc/oil.nvim/issues/302) | open | C-o parent nav makes buffer buflisted (P0) | +| [#302](https://github.com/stevearc/oil.nvim/issues/302) | fixed | `buflisted=true` after jumplist nav — [#71](https://github.com/barrettruth/canola.nvim/pull/71) ([`a078bcf`](https://github.com/barrettruth/canola.nvim/commit/a078bcf)) | | [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | | [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | | [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | diff --git a/lua/canola/init.lua b/lua/canola/init.lua index 5d6d06a..a728bdb 100644 --- a/lua/canola/init.lua +++ b/lua/canola/init.lua @@ -1343,6 +1343,9 @@ M.setup = function(opts) vim.fn.setreg('#', orig_buffer) end view.set_win_options() + if config.buf_options.buflisted ~= nil then + vim.api.nvim_set_option_value('buflisted', config.buf_options.buflisted, { buf = 0 }) + end vim.w.canola_did_enter = true elseif vim.fn.isdirectory(bufname) == 0 then -- Only run this logic if we are *not* in an canola buffer (and it's not a directory, which From 69d85b8de1e178b6c903d9aefc3767f43ce2cb43 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 14:40:10 -0500 Subject: [PATCH 54/77] feat(view): position cursor at name column on new empty lines (#72) Problem: pressing `o`/`O` in a canola buffer placed the cursor at column 0, requiring manual navigation past concealed ID prefixes and column text (icons, permissions) to reach the name column. Solution: add `show_insert_guide()` which temporarily sets `virtualedit=all` on empty lines and positions the cursor at the name column. Computes the correct virtual column by measuring the visible column prefix width via `nvim_strwidth`, adjusting for `conceallevel` (0=full ID width, 1=replacement char, 2/3=hidden). Restores `virtualedit` on `TextChangedI` or `InsertLeave`. --- lua/canola/view.lua | 93 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/lua/canola/view.lua b/lua/canola/view.lua index faad884..0f75faf 100644 --- a/lua/canola/view.lua +++ b/lua/canola/view.lua @@ -340,6 +340,84 @@ local function constrain_cursor(bufnr, mode) end end +---@param bufnr integer +local function show_insert_guide(bufnr) + if not config.constrain_cursor then + return + end + if bufnr ~= vim.api.nvim_get_current_buf() then + return + end + local adapter = util.get_adapter(bufnr, true) + if not adapter then + return + end + + local cur = vim.api.nvim_win_get_cursor(0) + local current_line = vim.api.nvim_buf_get_lines(bufnr, cur[1] - 1, cur[1], true)[1] + if current_line ~= '' then + return + end + + local all_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) + local ref_line + if cur[1] > 1 and all_lines[cur[1] - 1] ~= '' then + ref_line = all_lines[cur[1] - 1] + elseif cur[1] < #all_lines and all_lines[cur[1] + 1] ~= '' then + ref_line = all_lines[cur[1] + 1] + else + for i, line in ipairs(all_lines) do + if line ~= '' and i ~= cur[1] then + ref_line = line + break + end + end + end + if not ref_line then + return + end + + local parser = require('canola.mutator.parser') + local column_defs = columns.get_supported_columns(adapter) + local result = parser.parse_line(adapter, ref_line, column_defs) + if not result or not result.ranges then + return + end + + local id_end = result.ranges.id[2] + 1 + local col_prefix = ref_line:sub(id_end + 1, result.ranges.name[1]) + local col_width = vim.api.nvim_strwidth(col_prefix) + local id_width + local cole = vim.wo.conceallevel + if cole >= 2 then + id_width = 0 + elseif cole == 1 then + id_width = 1 + else + id_width = vim.api.nvim_strwidth(ref_line:sub(1, id_end)) + end + local virtual_col = id_width + col_width + if virtual_col <= 0 then + return + end + + vim.w.canola_saved_ve = vim.wo.virtualedit + vim.wo.virtualedit = 'all' + vim.api.nvim_win_set_cursor(0, { cur[1], virtual_col }) + + vim.api.nvim_create_autocmd('TextChangedI', { + group = 'Canola', + buffer = bufnr, + once = true, + callback = function() + if vim.w.canola_saved_ve ~= nil then + vim.wo.virtualedit = vim.w.canola_saved_ve + vim.w.canola_saved_ve = nil + end + end, + }) +end + ---Redraw original path virtual text for trash buffer ---@param bufnr integer local function redraw_trash_virtual_text(bufnr) @@ -458,7 +536,20 @@ M.initialize = function(bufnr) callback = function() -- For some reason the cursor bounces back to its original position, -- so we have to defer the call - vim.schedule_wrap(constrain_cursor)(bufnr, config.constrain_cursor) + vim.schedule(function() + constrain_cursor(bufnr, config.constrain_cursor) + show_insert_guide(bufnr) + end) + end, + }) + vim.api.nvim_create_autocmd('InsertLeave', { + group = 'Canola', + buffer = bufnr, + callback = function() + if vim.w.canola_saved_ve ~= nil then + vim.wo.virtualedit = vim.w.canola_saved_ve + vim.w.canola_saved_ve = nil + end end, }) vim.api.nvim_create_autocmd({ 'CursorMoved', 'ModeChanged' }, { From 1ee6c6b259721bd047408be0105b11b3fba58d8c Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:19:32 -0500 Subject: [PATCH 55/77] feat: add `cleanup_buffers_on_delete` option (#73) Problem: When files are deleted via canola, any open Neovim buffers for those files remain alive, polluting the jumplist with stale entries. Solution: Add an opt-in `cleanup_buffers_on_delete` config option (default `false`). When enabled, `finish()` in `mutator/init.lua` iterates completed delete actions and wipes matching buffers via `nvim_buf_delete` before `CanolaActionsPost` fires. Only local filesystem deletes are handled (guarded by the `files` adapter check). --- doc/canola.txt | 6 + doc/upstream.md | 216 ++++++++++++++++++------------------ lua/canola/config.lua | 4 + lua/canola/mutator/init.lua | 15 +++ spec/files_spec.lua | 43 +++++++ 5 files changed, 176 insertions(+), 108 deletions(-) diff --git a/doc/canola.txt b/doc/canola.txt index 2553b66..641eee5 100644 --- a/doc/canola.txt +++ b/doc/canola.txt @@ -311,6 +311,12 @@ prompt_save_on_select_new_entry *canola.prompt_save_on_select_new_e When this option is `true`, Canola will prompt you to save before entering a file or directory that is pending within canola, but does not exist on disk. +cleanup_buffers_on_delete *canola.cleanup_buffers_on_delete* + type: `boolean` default: `false` + When `true`, canola will wipe any open buffer whose path matches a file that + was successfully deleted via canola. This prevents stale buffers from + appearing in the jumplist after a deletion. + -------------------------------------------------------------------------------- API *canola-api* diff --git a/doc/upstream.md b/doc/upstream.md index b85fa6e..48bf754 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -55,112 +55,112 @@ Bugs fixed in this fork that remain open upstream. cherry-picked PR, `not actionable` = can't/won't fix, `tracking` = known/not yet addressed, `open` = not yet triaged. -| Issue | Status | Notes | -| ------------------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | -| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | -| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | -| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | -| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | -| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | -| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | -| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | -| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | -| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | -| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | -| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | -| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | -| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | -| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | -| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | -| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | +| Issue | Status | Notes | +| ------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | +| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | +| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | +| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | +| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | +| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | +| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | +| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | +| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | +| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | +| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | +| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | +| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | +| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | +| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | +| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | +| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | | [#302](https://github.com/stevearc/oil.nvim/issues/302) | fixed | `buflisted=true` after jumplist nav — [#71](https://github.com/barrettruth/canola.nvim/pull/71) ([`a078bcf`](https://github.com/barrettruth/canola.nvim/commit/a078bcf)) | -| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | -| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | -| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | -| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | -| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | -| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | -| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | -| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | -| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | -| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | -| [#363](https://github.com/stevearc/oil.nvim/issues/363) | open | `prompt_save_on_select_new_entry` uses wrong prompt | -| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | -| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | -| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | -| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | -| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | -| [#392](https://github.com/stevearc/oil.nvim/issues/392) | open | Option to skip delete prompt | -| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | -| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | -| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | -| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | -| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | -| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | -| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | -| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | -| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | -| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | -| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | -| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | -| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | -| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | -| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | -| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | -| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | -| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | -| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | -| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | -| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | -| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | -| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | -| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | -| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | -| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/canola.nvim/commit/38db6cf) | -| [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | -| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | -| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | -| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | -| [#612](https://github.com/stevearc/oil.nvim/issues/612) | open | Delete buffers on file delete (P2) | -| [#615](https://github.com/stevearc/oil.nvim/issues/615) | open | Cursor at name column on o/O (P2) | -| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | -| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | -| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | -| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | -| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | -| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | -| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | -| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | -| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | -| [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | -| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/canola.nvim/commit/f6bcdda) | -| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | -| [#650](https://github.com/stevearc/oil.nvim/issues/650) | open | Emit LSP `workspace.fileOperations` events | -| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | -| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | -| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | -| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | -| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | -| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | -| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | -| [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | -| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | -| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | -| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#682](https://github.com/stevearc/oil.nvim/issues/682) | open | `get_current_dir()` nil in non-telescope context | -| [#683](https://github.com/stevearc/oil.nvim/issues/683) | open | Path not shown in floating mode | -| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | -| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | -| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/canola.nvim/commit/ce64ae1) | -| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | -| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | -| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | -| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | -| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | -| [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | -| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | feature request: make icons virtual text | +| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | +| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | +| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | +| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | +| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | +| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | +| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | +| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | +| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | +| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | +| [#363](https://github.com/stevearc/oil.nvim/issues/363) | open | `prompt_save_on_select_new_entry` uses wrong prompt | +| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | +| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | +| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | +| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | +| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | +| [#392](https://github.com/stevearc/oil.nvim/issues/392) | open | Option to skip delete prompt | +| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | +| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | +| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | +| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | +| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | +| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | +| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | +| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | +| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | +| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | +| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | +| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | +| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | +| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | +| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | +| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | +| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | +| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | +| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | +| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | +| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | +| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | +| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | +| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | +| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | +| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/canola.nvim/commit/38db6cf) | +| [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | +| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | +| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | +| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | +| [#612](https://github.com/stevearc/oil.nvim/issues/612) | fixed | Delete buffers on file delete — `cleanup_buffers_on_delete` option | +| [#615](https://github.com/stevearc/oil.nvim/issues/615) | open | Cursor at name column on o/O (P2) | +| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | +| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | +| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | +| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | +| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | +| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | +| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | +| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | +| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | +| [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | +| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/canola.nvim/commit/f6bcdda) | +| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | +| [#650](https://github.com/stevearc/oil.nvim/issues/650) | open | Emit LSP `workspace.fileOperations` events | +| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | +| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | +| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | +| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | +| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | +| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | +| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | +| [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | +| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | +| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | +| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#682](https://github.com/stevearc/oil.nvim/issues/682) | open | `get_current_dir()` nil in non-telescope context | +| [#683](https://github.com/stevearc/oil.nvim/issues/683) | open | Path not shown in floating mode | +| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | +| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | +| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/canola.nvim/commit/ce64ae1) | +| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | +| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | +| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | +| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | +| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | +| [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | +| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | feature request: make icons virtual text | diff --git a/lua/canola/config.lua b/lua/canola/config.lua index 607f4c0..3790661 100644 --- a/lua/canola/config.lua +++ b/lua/canola/config.lua @@ -28,6 +28,8 @@ local default_config = { }, -- Send deleted files to the trash instead of permanently deleting them (:help canola-trash) delete_to_trash = false, + -- Wipe open buffers for files deleted via canola (:help canola.cleanup_buffers_on_delete) + cleanup_buffers_on_delete = false, -- Skip the confirmation popup for simple operations (:help canola.skip_confirm_for_simple_edits) skip_confirm_for_simple_edits = false, -- Selecting a new/moved/renamed file or directory will prompt you to save changes first @@ -232,6 +234,7 @@ default_config.view_options.highlight_filename = nil ---@field buf_options table ---@field win_options table ---@field delete_to_trash boolean +---@field cleanup_buffers_on_delete boolean ---@field skip_confirm_for_simple_edits boolean ---@field prompt_save_on_select_new_entry boolean ---@field cleanup_delay_ms integer @@ -263,6 +266,7 @@ local M = {} ---@field buf_options? table Buffer-local options to use for canola buffers ---@field win_options? table Window-local options to use for canola buffers ---@field delete_to_trash? boolean Send deleted files to the trash instead of permanently deleting them (:help canola-trash). +---@field cleanup_buffers_on_delete? boolean Wipe open buffers for files deleted via canola (:help canola.cleanup_buffers_on_delete). ---@field skip_confirm_for_simple_edits? boolean Skip the confirmation popup for simple operations (:help canola.skip_confirm_for_simple_edits). ---@field prompt_save_on_select_new_entry? boolean Selecting a new/moved/renamed file or directory will prompt you to save changes first (:help prompt_save_on_select_new_entry). ---@field cleanup_delay_ms? integer Canola will automatically delete hidden buffers after this delay. You can set the delay to false to disable cleanup entirely. Note that the cleanup process only starts when none of the canola buffers are currently displayed. diff --git a/lua/canola/mutator/init.lua b/lua/canola/mutator/init.lua index 34cf2b1..626ec70 100644 --- a/lua/canola/mutator/init.lua +++ b/lua/canola/mutator/init.lua @@ -420,6 +420,21 @@ M.process_actions = function(actions, cb) finished = true progress:close() progress = nil + if config.cleanup_buffers_on_delete and not err then + for _, action in ipairs(actions) do + if action.type == 'delete' then + local scheme, path = util.parse_url(action.url) + if config.adapters[scheme] == 'files' then + assert(path) + local os_path = fs.posix_to_os_path(path) + local bufnr = vim.fn.bufnr(os_path) + if bufnr ~= -1 then + vim.api.nvim_buf_delete(bufnr, { force = true }) + end + end + end + end + end vim.api.nvim_exec_autocmds( 'User', { pattern = 'CanolaActionsPost', modeline = false, data = { err = err, actions = actions } } diff --git a/spec/files_spec.lua b/spec/files_spec.lua index 7c430f3..0282c0b 100644 --- a/spec/files_spec.lua +++ b/spec/files_spec.lua @@ -163,4 +163,47 @@ describe('files adapter', function() assert.equals(vim.fn.fnamemodify(tmpdir.path, ':p') .. 'file.rb', vim.api.nvim_buf_get_name(0)) assert.equals(tmpdir.path .. '/file.rb', vim.fn.bufname()) end) + + describe('cleanup_buffers_on_delete', function() + local cache = require('canola.cache') + local config = require('canola.config') + local mutator = require('canola.mutator') + + before_each(function() + config.cleanup_buffers_on_delete = true + end) + + after_each(function() + config.cleanup_buffers_on_delete = false + end) + + it('wipes the buffer for a deleted file', function() + tmpdir:create({ 'a.txt' }) + local dirurl = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') + local filepath = vim.fn.fnamemodify(tmpdir.path, ':p') .. 'a.txt' + cache.create_and_store_entry(dirurl, 'a.txt', 'file') + vim.cmd.edit({ args = { filepath } }) + local bufnr = vim.api.nvim_get_current_buf() + local url = 'canola://' .. filepath + test_util.await(mutator.process_actions, 2, { + { type = 'delete', url = url, entry_type = 'file' }, + }) + assert.is_false(vim.api.nvim_buf_is_valid(bufnr)) + end) + + it('does not wipe the buffer when disabled', function() + config.cleanup_buffers_on_delete = false + tmpdir:create({ 'b.txt' }) + local dirurl = 'canola://' .. vim.fn.fnamemodify(tmpdir.path, ':p') + local filepath = vim.fn.fnamemodify(tmpdir.path, ':p') .. 'b.txt' + cache.create_and_store_entry(dirurl, 'b.txt', 'file') + vim.cmd.edit({ args = { filepath } }) + local bufnr = vim.api.nvim_get_current_buf() + local url = 'canola://' .. filepath + test_util.await(mutator.process_actions, 2, { + { type = 'delete', url = url, entry_type = 'file' }, + }) + assert.is_true(vim.api.nvim_buf_is_valid(bufnr)) + end) + end) end) From c7a55fd7873555fd0996f161708003fe626a16b8 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:48:07 -0500 Subject: [PATCH 56/77] docs(upstream): triage PRs #721 and #735 (#74) * docs(upstream): triage PRs #721 and #735 * docs(upstream): fix #721 status to deferred * docs(upstream): remove status key legend * docs(upstream): s/addressing/fixing in #721 note --- doc/upstream.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index 48bf754..1ea0759 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -45,15 +45,12 @@ Bugs fixed in this fork that remain open upstream. | [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | | [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | | [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | -| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | open | +| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | deferred — fixing via autocmd event on file create | | [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | -| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with a selection. | open | +| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with selection | not actionable — hardcoded Linux-only program list, no config surface, author-acknowledged incomplete | ## Upstream issues -**Status key:** `fixed` = original fix in fork, `resolved` = addressed by -cherry-picked PR, `not actionable` = can't/won't fix, `tracking` = known/not yet -addressed, `open` = not yet triaged. | Issue | Status | Notes | | ------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | From a74747e1f53ae956e63e565b69ec13154a2064b9 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 15:54:01 -0500 Subject: [PATCH 57/77] feat: emit `CanolaFileCreated` autocmd on file creation (#75) * feat: emit \`CanolaFileCreated\` autocmd on file creation Problem: no way to hook into individual file creation to populate initial contents, without a plugin-specific config callback. Solution: fire \`User CanolaFileCreated\` with \`data.path\` after each successful \`fs.touch\` in the files adapter. Users listen with \`nvim_create_autocmd\` and write to the path however they like. * build: gitignore `doc/upstream.html` * docs(upstream): mark #721 fixed, triage #735 * docs(upstream): simplify #735 note --- .gitignore | 1 + doc/canola.txt | 16 ++++++++++++++++ doc/upstream.md | 23 +++++++++++------------ lua/canola/adapters/files.lua | 14 +++++++++++++- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 4a27603..43aea5a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ doc/tags +doc/upstream.html *.log .*cache* CLAUDE.md diff --git a/doc/canola.txt b/doc/canola.txt index 641eee5..14c6655 100644 --- a/doc/canola.txt +++ b/doc/canola.txt @@ -1135,6 +1135,22 @@ CanolaMutationComplete *CanolaMutationComp additional data fields. Use this event for post-mutation side effects such as refreshing external status indicators. +CanolaFileCreated *CanolaFileCreated* + Fired after a new file is successfully created on the local filesystem. + The `args.data.path` field contains the absolute path of the created file. + Use this event to populate initial file contents, run formatters, or + perform any other setup on newly created files. >lua + vim.api.nvim_create_autocmd("User", { + pattern = "CanolaFileCreated", + callback = function(args) + local path = args.data.path + if path:match("%.sh$") then + vim.fn.writefile({ "#!/usr/bin/env bash" }, path) + end + end, + }) +< + -------------------------------------------------------------------------------- TRASH *canola-trash* diff --git a/doc/upstream.md b/doc/upstream.md index 1ea0759..238396a 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -37,21 +37,20 @@ Bugs fixed in this fork that remain open upstream. ## Open upstream PRs -| PR | Description | Status | -| ----------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------ | -| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | -| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | -| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | -| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | -| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | -| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | -| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | deferred — fixing via autocmd event on file create | -| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | -| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with selection | not actionable — hardcoded Linux-only program list, no config surface, author-acknowledged incomplete | +| PR | Description | Status | +| ----------------------------------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | +| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | +| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | +| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | +| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | +| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | +| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | fixed — `CanolaFileCreated` autocmd — [#75](https://github.com/barrettruth/canola.nvim/pull/75) | +| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | +| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with a selection. | not actionable — wrong abstraction layer | ## Upstream issues - | Issue | Status | Notes | | ------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | diff --git a/lua/canola/adapters/files.lua b/lua/canola/adapters/files.lua index 3bb8a89..dff8e1a 100644 --- a/lua/canola/adapters/files.lua +++ b/lua/canola/adapters/files.lua @@ -600,7 +600,19 @@ M.perform_action = function(action, cb) ---@diagnostic disable-next-line: param-type-mismatch uv.fs_symlink(target, path, flags, cb) else - fs.touch(path, config.new_file_mode, cb) + fs.touch( + path, + config.new_file_mode, + vim.schedule_wrap(function(err) + if not err then + vim.api.nvim_exec_autocmds( + 'User', + { pattern = 'CanolaFileCreated', modeline = false, data = { path = path } } + ) + end + cb(err) + end) + ) end elseif action.type == 'delete' then local _, path = util.parse_url(action.url) From 7a4624606202d73b9cab31031e72552bdc074529 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:28:57 -0500 Subject: [PATCH 58/77] fix: escape on save prompt cancels select (#76) Problem: when `prompt_save_on_select_new_entry` is enabled and the user presses Escape on the "Save changes?" confirm dialog, `vim.fn.confirm` returns 0, but the select continued as if the user had chosen "No". Solution: add an explicit `choice == 0` branch that returns immediately, aborting the select without saving or opening any files. --- doc/upstream.md | 24 ++++++++++++------------ lua/canola/init.lua | 2 ++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index 238396a..459e043 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -37,17 +37,17 @@ Bugs fixed in this fork that remain open upstream. ## Open upstream PRs -| PR | Description | Status | -| ----------------------------------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------- | -| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | -| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | -| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | -| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | -| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | -| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | -| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | fixed — `CanolaFileCreated` autocmd — [#75](https://github.com/barrettruth/canola.nvim/pull/75) | -| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | -| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with a selection. | not actionable — wrong abstraction layer | +| PR | Description | Status | +| ----------------------------------------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------- | +| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | +| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | +| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | +| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | +| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | +| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | +| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | deferred — fixing via autocmd event on file create | +| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | +| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with selection | not actionable — hardcoded Linux-only program list, no config surface, author-acknowledged incomplete | ## Upstream issues @@ -82,7 +82,7 @@ Bugs fixed in this fork that remain open upstream. | [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | | [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | | [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | -| [#363](https://github.com/stevearc/oil.nvim/issues/363) | open | `prompt_save_on_select_new_entry` uses wrong prompt | +| [#363](https://github.com/stevearc/oil.nvim/issues/363) | fixed | `prompt_save_on_select_new_entry` uses wrong prompt — escape now cancels select | | [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | | [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | | [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | diff --git a/lua/canola/init.lua b/lua/canola/init.lua index a728bdb..aacebe2 100644 --- a/lua/canola/init.lua +++ b/lua/canola/init.lua @@ -716,6 +716,8 @@ M.select = function(opts, callback) local ok, choice = pcall(vim.fn.confirm, 'Save changes?', 'Yes\nNo', 1) if not ok then return finish() + elseif choice == 0 then + return elseif choice == 1 then M.save() return finish() From ba49f76e9167ac9b3a062b6a5f02b61d2bb3e0aa Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:29:12 -0500 Subject: [PATCH 59/77] feat: add `skip_confirm_for_delete` option (#77) feat: add \`skip_confirm_for_delete\` option Problem: there was no way to suppress the confirmation popup when the only pending operations are deletes. \`skip_confirm_for_simple_edits\` explicitly excludes deletes, so users who delete frequently had no opt-out. Solution: add \`skip_confirm_for_delete = false\` config option. When true, \`confirmation.show()\` skips the popup if every pending action is a delete. Based on: stevearc/oil.nvim#392 --- doc/canola.txt | 5 +++++ doc/upstream.md | 2 +- lua/canola/config.lua | 3 +++ lua/canola/mutator/confirmation.lua | 13 +++++++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/doc/canola.txt b/doc/canola.txt index 14c6655..28ecd11 100644 --- a/doc/canola.txt +++ b/doc/canola.txt @@ -292,6 +292,11 @@ skip_confirm_for_simple_edits *canola.skip_confirm_for_simple_e * contain at most one copy or move * contain at most five creates +skip_confirm_for_delete *canola.skip_confirm_for_delete* + type: `boolean` default: `false` + When this option is `true`, the confirmation popup will be skipped if all pending + actions are deletes. + prompt_save_on_select_new_entry *canola.prompt_save_on_select_new_entry* type: `boolean` default: `true` There are two cases where this option is relevant: diff --git a/doc/upstream.md b/doc/upstream.md index 459e043..bdfe20c 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -88,7 +88,7 @@ Bugs fixed in this fork that remain open upstream. | [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | | [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | | [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | -| [#392](https://github.com/stevearc/oil.nvim/issues/392) | open | Option to skip delete prompt | +| [#392](https://github.com/stevearc/oil.nvim/issues/392) | fixed | Option to skip delete prompt — fixed — `skip_confirm_for_delete` option | | [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | | [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | | [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | diff --git a/lua/canola/config.lua b/lua/canola/config.lua index 3790661..12d2751 100644 --- a/lua/canola/config.lua +++ b/lua/canola/config.lua @@ -32,6 +32,7 @@ local default_config = { cleanup_buffers_on_delete = false, -- Skip the confirmation popup for simple operations (:help canola.skip_confirm_for_simple_edits) skip_confirm_for_simple_edits = false, + skip_confirm_for_delete = false, -- Selecting a new/moved/renamed file or directory will prompt you to save changes first -- (:help prompt_save_on_select_new_entry) prompt_save_on_select_new_entry = true, @@ -236,6 +237,7 @@ default_config.view_options.highlight_filename = nil ---@field delete_to_trash boolean ---@field cleanup_buffers_on_delete boolean ---@field skip_confirm_for_simple_edits boolean +---@field skip_confirm_for_delete boolean ---@field prompt_save_on_select_new_entry boolean ---@field cleanup_delay_ms integer ---@field lsp_file_methods canola.LspFileMethods @@ -268,6 +270,7 @@ local M = {} ---@field delete_to_trash? boolean Send deleted files to the trash instead of permanently deleting them (:help canola-trash). ---@field cleanup_buffers_on_delete? boolean Wipe open buffers for files deleted via canola (:help canola.cleanup_buffers_on_delete). ---@field skip_confirm_for_simple_edits? boolean Skip the confirmation popup for simple operations (:help canola.skip_confirm_for_simple_edits). +---@field skip_confirm_for_delete? boolean Skip the confirmation popup when all pending actions are deletes (:help canola.skip_confirm_for_delete). ---@field prompt_save_on_select_new_entry? boolean Selecting a new/moved/renamed file or directory will prompt you to save changes first (:help prompt_save_on_select_new_entry). ---@field cleanup_delay_ms? integer Canola will automatically delete hidden buffers after this delay. You can set the delay to false to disable cleanup entirely. Note that the cleanup process only starts when none of the canola buffers are currently displayed. ---@field lsp_file_methods? canola.SetupLspFileMethods Configure LSP file operation integration. diff --git a/lua/canola/mutator/confirmation.lua b/lua/canola/mutator/confirmation.lua index 9ed6525..b4448ee 100644 --- a/lua/canola/mutator/confirmation.lua +++ b/lua/canola/mutator/confirmation.lua @@ -67,6 +67,19 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb) cb(true) return end + if should_confirm == nil and config.skip_confirm_for_delete then + local all_deletes = true + for _, action in ipairs(actions) do + if action.type ~= 'delete' then + all_deletes = false + break + end + end + if all_deletes then + cb(true) + return + end + end -- Create the buffer local bufnr = vim.api.nvim_create_buf(false, true) From 0f386bb69c73e11f146f504524e28a1834e6e1f2 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:29:47 -0500 Subject: [PATCH 60/77] fix: show float title when border is nil (#78) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: show float title when border is nil Problem: the float title was only shown via the native `nvim_win_set_config` path, which requires a border to render. The guard `config.float.border ~= 'none'` did not account for `nil`, which is the default — so users with no explicit `border` config never saw the path title in the floating window. Solution: require both `~= nil` and `~= 'none'` before using the native title. In all other cases (border nil, 'none', or nvim < 0.9), fall back to `util.add_title_to_win`, which renders a child floating window for the title. Based on: stevearc/oil.nvim#683 * refactor: drop nvim-0.9 version checks in float title logic --- doc/upstream.md | 2 +- lua/canola/init.lua | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index bdfe20c..5b13643 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -148,7 +148,7 @@ Bugs fixed in this fork that remain open upstream. | [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | | [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | | [#682](https://github.com/stevearc/oil.nvim/issues/682) | open | `get_current_dir()` nil in non-telescope context | -| [#683](https://github.com/stevearc/oil.nvim/issues/683) | open | Path not shown in floating mode | +| [#683](https://github.com/stevearc/oil.nvim/issues/683) | fixed | Path not shown in floating mode — title shown via fallback when border is nil | | [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | | [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | | [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/canola.nvim/commit/ce64ae1) | diff --git a/lua/canola/init.lua b/lua/canola/init.lua index aacebe2..c0e77d9 100644 --- a/lua/canola/init.lua +++ b/lua/canola/init.lua @@ -305,8 +305,7 @@ M.open_float = function(dir, opts, cb) vim.api.nvim_set_option_value(k, v, { scope = 'local', win = winid }) end - -- Update the floating window title - if vim.fn.has('nvim-0.9') == 1 and config.float.border ~= 'none' then + if config.float.border ~= nil and config.float.border ~= 'none' then local cur_win_opts = vim.api.nvim_win_get_config(winid) vim.api.nvim_win_set_config(winid, { relative = 'editor', @@ -316,6 +315,8 @@ M.open_float = function(dir, opts, cb) height = cur_win_opts.height, title = util.get_title(winid), }) + else + util.add_title_to_win(winid) end end, }) @@ -335,7 +336,7 @@ M.open_float = function(dir, opts, cb) end end) - if vim.fn.has('nvim-0.9') == 0 then + if config.float.border == nil or config.float.border == 'none' then util.add_title_to_win(winid) end end From 01f10e1d79690feb37116093b0031e799a842b1e Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:36:37 -0500 Subject: [PATCH 61/77] refactor: drop nvim 0.8/0.9 compat shims from `init.lua` (#79) --- .gitignore | 1 + lua/canola/init.lua | 20 ++------------------ 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 43aea5a..6cb6d15 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ venv/ perf/tmp/ scripts/benchmark.nvim profile.json +.worktrees/ diff --git a/lua/canola/init.lua b/lua/canola/init.lua index c0e77d9..6a3a990 100644 --- a/lua/canola/init.lua +++ b/lua/canola/init.lua @@ -525,15 +525,13 @@ M.open_preview = function(opts, callback) style = 'minimal', } - if vim.fn.has('nvim-0.9') == 1 then - win_opts.title = entry_title - end + win_opts.title = entry_title preview_win = vim.api.nvim_open_win(bufnr, true, win_opts) vim.api.nvim_set_option_value('previewwindow', true, { scope = 'local', win = preview_win }) vim.api.nvim_win_set_var(preview_win, 'canola_preview', true) vim.api.nvim_set_current_win(prev_win) - elseif vim.fn.has('nvim-0.9') == 1 then + else vim.api.nvim_win_set_config(preview_win, { title = entry_title }) end end @@ -995,20 +993,6 @@ local function set_colors() vim.api.nvim_set_hl(0, conf.name, { default = true, link = conf.link }) end end - -- TODO can remove this call once we drop support for Neovim 0.8. FloatTitle was introduced as a - -- built-in highlight group in 0.9, and we can start to rely on colorschemes setting it. - ---@diagnostic disable-next-line: deprecated - if vim.fn.has('nvim-0.9') == 0 and not pcall(vim.api.nvim_get_hl_by_name, 'FloatTitle', true) then - ---@diagnostic disable-next-line: deprecated - local border = vim.api.nvim_get_hl_by_name('FloatBorder', true) - ---@diagnostic disable-next-line: deprecated - local normal = vim.api.nvim_get_hl_by_name('Normal', true) - vim.api.nvim_set_hl( - 0, - 'FloatTitle', - { fg = normal.foreground, bg = border.background or normal.background } - ) - end end ---Save all changes From 5b742108948d7c6c18524fa75f56ffdba5362a96 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:43:55 -0500 Subject: [PATCH 62/77] docs(upstream): mark #615 fixed, #650 and #682 resolved (#80) --- doc/upstream.md | 218 ++++++++++++++++++++++++------------------------ 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index 5b13643..e136f96 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -51,112 +51,112 @@ Bugs fixed in this fork that remain open upstream. ## Upstream issues -| Issue | Status | Notes | -| ------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | -| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | -| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | -| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | -| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | -| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | -| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | -| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | -| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | -| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | -| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | -| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | -| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | -| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | -| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | -| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | -| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | -| [#302](https://github.com/stevearc/oil.nvim/issues/302) | fixed | `buflisted=true` after jumplist nav — [#71](https://github.com/barrettruth/canola.nvim/pull/71) ([`a078bcf`](https://github.com/barrettruth/canola.nvim/commit/a078bcf)) | -| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | -| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | -| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | -| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | -| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | -| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | -| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | -| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | -| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | -| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | -| [#363](https://github.com/stevearc/oil.nvim/issues/363) | fixed | `prompt_save_on_select_new_entry` uses wrong prompt — escape now cancels select | -| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | -| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | -| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | -| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | -| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | -| [#392](https://github.com/stevearc/oil.nvim/issues/392) | fixed | Option to skip delete prompt — fixed — `skip_confirm_for_delete` option | -| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | -| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | -| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | -| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | -| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | -| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | -| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | -| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | -| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | -| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | -| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | -| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | -| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | -| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | -| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | -| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | -| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | -| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | -| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | -| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | -| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | -| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | -| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | -| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | -| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | -| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/canola.nvim/commit/38db6cf) | -| [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | -| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | -| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | -| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | -| [#612](https://github.com/stevearc/oil.nvim/issues/612) | fixed | Delete buffers on file delete — `cleanup_buffers_on_delete` option | -| [#615](https://github.com/stevearc/oil.nvim/issues/615) | open | Cursor at name column on o/O (P2) | -| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | -| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | -| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | -| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | -| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | -| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | -| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | -| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | -| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | -| [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | -| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/canola.nvim/commit/f6bcdda) | -| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | -| [#650](https://github.com/stevearc/oil.nvim/issues/650) | open | Emit LSP `workspace.fileOperations` events | -| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | -| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | -| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | -| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | -| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | -| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | -| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | -| [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | -| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | -| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | -| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#682](https://github.com/stevearc/oil.nvim/issues/682) | open | `get_current_dir()` nil in non-telescope context | -| [#683](https://github.com/stevearc/oil.nvim/issues/683) | fixed | Path not shown in floating mode — title shown via fallback when border is nil | -| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | -| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | -| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/canola.nvim/commit/ce64ae1) | -| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | -| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | -| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | -| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | -| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | -| [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | -| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | feature request: make icons virtual text | +| Issue | Status | Notes | +| ------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | +| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | +| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | +| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | +| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | +| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | +| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | +| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | +| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | +| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | +| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | +| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | +| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | +| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | +| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | +| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | +| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | +| [#302](https://github.com/stevearc/oil.nvim/issues/302) | fixed | `buflisted=true` after jumplist nav — [#71](https://github.com/barrettruth/canola.nvim/pull/71) ([`a078bcf`](https://github.com/barrettruth/canola.nvim/commit/a078bcf)) | +| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | +| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | +| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | +| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | +| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | +| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | +| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | +| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | +| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | +| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | +| [#363](https://github.com/stevearc/oil.nvim/issues/363) | fixed | `prompt_save_on_select_new_entry` uses wrong prompt — escape now cancels select | +| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | +| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | +| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | +| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | +| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | +| [#392](https://github.com/stevearc/oil.nvim/issues/392) | fixed | Option to skip delete prompt — fixed — `skip_confirm_for_delete` option | +| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | +| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | +| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | +| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | +| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | +| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | +| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | +| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | +| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | +| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | +| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | +| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | +| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | +| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | +| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | +| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | +| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | +| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | +| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | +| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | +| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | +| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | +| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | +| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | +| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | +| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/canola.nvim/commit/38db6cf) | +| [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | +| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | +| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | +| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | +| [#612](https://github.com/stevearc/oil.nvim/issues/612) | fixed | Delete buffers on file delete — `cleanup_buffers_on_delete` option | +| [#615](https://github.com/stevearc/oil.nvim/issues/615) | fixed | Cursor at name column on o/O — [#72](https://github.com/barrettruth/canola.nvim/pull/72) ([`69d85b8`](https://github.com/barrettruth/canola.nvim/commit/69d85b8)) | +| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | +| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | +| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | +| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | +| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | +| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | +| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | +| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | +| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | +| [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | +| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/canola.nvim/commit/f6bcdda) | +| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | +| [#650](https://github.com/stevearc/oil.nvim/issues/650) | resolved | LSP `workspace.fileOperations` events — implemented in `lua/canola/lsp/workspace.lua` | +| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | +| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | +| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | +| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | +| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | +| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | +| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | +| [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | +| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | +| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | +| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#682](https://github.com/stevearc/oil.nvim/issues/682) | resolved | `get_current_dir()` nil — clarified via [`eed6697`](https://github.com/barrettruth/canola.nvim/commit/eed6697) (cherry-pick of [#727](https://github.com/stevearc/oil.nvim/pull/727)) | +| [#683](https://github.com/stevearc/oil.nvim/issues/683) | fixed | Path not shown in floating mode — title shown via fallback when border is nil | +| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | +| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | +| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/canola.nvim/commit/ce64ae1) | +| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | +| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | +| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | +| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | +| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | +| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | +| [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | +| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | feature request: make icons virtual text | From 6d19b5c8f5303d62fa301b22f387f3e3fdc5a960 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 6 Mar 2026 17:58:41 -0500 Subject: [PATCH 63/77] correct canola q&a format --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b736772..122216e 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,10 @@ After (`barrettruth/canola.nvim`): **Q: Why "canola"?** +Canola oil! But... + +**Q: Why "oil"?** + From the [vim-vinegar](https://github.com/tpope/vim-vinegar) README, a quote by Drew Neil: From 082573d7794637efe3d5ab9cc91bf7420365efc6 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sat, 7 Mar 2026 15:45:23 -0500 Subject: [PATCH 64/77] feat: add open_split/toggle_split API and upstream triage batch (#83) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(upstream): triage batch — #739 cherry-pick, 10 issue updates * feat: add `open_split` and `toggle_split` API Problem: canola had no way to open a browser in a normal split window; only floating windows were supported via `open_float`/`toggle_float`. `M.close` also crashed with E444 when called from the last window. Solution: port stevearc/oil.nvim#728 — add `open_split(dir, opts, cb)` and `toggle_split(dir, opts, cb)` mirroring the float API. Use `is_canola_win`/`canola_original_win` window vars (not the upstream `is_oil_win` names). Wrap `nvim_win_close` in `pcall` with `enew()` fallback to handle the last-window E444 case. Based on: stevearc/oil.nvim#728 * docs: add vimdoc for `open_split`/`toggle_split` and macOS trash recipe Cherry-picked from: stevearc/oil.nvim#739 * docs(upstream): fix prettier formatting --- doc/canola.txt | 35 ++++++++++++++++++++ doc/upstream.md | 16 ++++++---- lua/canola/init.lua | 78 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 121 insertions(+), 8 deletions(-) diff --git a/doc/canola.txt b/doc/canola.txt index 28ecd11..5de8a52 100644 --- a/doc/canola.txt +++ b/doc/canola.txt @@ -404,6 +404,32 @@ toggle_float({dir}, {opts}, {cb}) *canola.toggle_f plit modifier {cb} `nil|fun()` Called after the canola buffer is ready +open_split({dir}, {opts}, {cb}) *canola.open_split* + Open canola browser in a split window + + Parameters: + {dir} `nil|string` When nil, open the parent of the current buffer, or + the cwd if current buffer is not a file + {opts} `nil|canola.OpenSplitOpts` + {vertical} `nil|boolean` Open the buffer in a vertical split + {horizontal} `nil|boolean` Open the buffer in a horizontal split + {split} `nil|"aboveleft"|"belowright"|"topleft"|"botright"` Split + modifier + {cb} `nil|fun()` Called after the canola buffer is ready + +toggle_split({dir}, {opts}, {cb}) *canola.toggle_split* + Open canola browser in a split window, or close it if open + + Parameters: + {dir} `nil|string` When nil, open the parent of the current buffer, or + the cwd if current buffer is not a file + {opts} `nil|canola.OpenSplitOpts` + {vertical} `nil|boolean` Open the buffer in a vertical split + {horizontal} `nil|boolean` Open the buffer in a horizontal split + {split} `nil|"aboveleft"|"belowright"|"topleft"|"botright"` Split + modifier + {cb} `nil|fun()` Called after the canola buffer is ready + open({dir}, {opts}, {cb}) *canola.open* Open canola browser for a directory @@ -1109,6 +1135,15 @@ variant after calling `setup()`: end < +Use FreeDesktop trash on macOS ~ + *canola-recipe-macos-freedesktop-trash* + +For full FreeDesktop spec compliance on macOS (list, restore operations), or +for compatibility with FreeDesktop-compliant trash programs like gtrash: +>lua + package.loaded["canola.adapters.trash.mac"] = require("canola.adapters.trash.freedesktop") +< + -------------------------------------------------------------------------------- EVENTS *canola-events* diff --git a/doc/upstream.md b/doc/upstream.md index e136f96..9600c74 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -21,6 +21,7 @@ Upstream PRs cherry-picked or adapted into this fork. | [#723](https://github.com/stevearc/oil.nvim/pull/723) | Emit `OilReadPost` event after render | [`29239d5`](https://github.com/barrettruth/canola.nvim/commit/29239d5) | | [#725](https://github.com/stevearc/oil.nvim/pull/725) | Normalize keymap keys before config merge | [`723145c`](https://github.com/barrettruth/canola.nvim/commit/723145c) | | [#727](https://github.com/stevearc/oil.nvim/pull/727) | Clarify `get_current_dir` nil + Telescope recipe | [`eed6697`](https://github.com/barrettruth/canola.nvim/commit/eed6697) | +| [#739](https://github.com/stevearc/oil.nvim/pull/739) | macOS FreeDesktop trash recipe | `doc/canola.txt` (`canola-recipe-macos-freedesktop-trash`) | ## Original fixes @@ -67,29 +68,29 @@ Bugs fixed in this fork that remain open upstream. | [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | | [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | | [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | -| [#288](https://github.com/stevearc/oil.nvim/issues/288) | open | Oil failing to load (P2) | +| [#288](https://github.com/stevearc/oil.nvim/issues/288) | not actionable | No reliable repro; likely lazy.nvim timing issue — setting `lazy = false` resolves it for affected users | | [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | | [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | | [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | | [#302](https://github.com/stevearc/oil.nvim/issues/302) | fixed | `buflisted=true` after jumplist nav — [#71](https://github.com/barrettruth/canola.nvim/pull/71) ([`a078bcf`](https://github.com/barrettruth/canola.nvim/commit/a078bcf)) | | [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | | [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | -| [#330](https://github.com/stevearc/oil.nvim/issues/330) | open | File opens in floating modal | +| [#330](https://github.com/stevearc/oil.nvim/issues/330) | not actionable | Telescope opens file in oil float — cross-plugin interaction, no repro provided | | [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | | [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | | [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | | [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | | [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | | [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | -| [#362](https://github.com/stevearc/oil.nvim/issues/362) | open | "Could not find oil adapter for scheme" error | +| [#362](https://github.com/stevearc/oil.nvim/issues/362) | not actionable | "Could not find oil adapter for scheme" — no minimal repro provided, old nvim version (0.9.5) | | [#363](https://github.com/stevearc/oil.nvim/issues/363) | fixed | `prompt_save_on_select_new_entry` uses wrong prompt — escape now cancels select | | [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | | [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | | [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | -| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show file in oil when editing hidden file | +| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show currently-edited hidden files in listing even when `show_hidden = false`; no upstream response, nice to have | | [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | | [#392](https://github.com/stevearc/oil.nvim/issues/392) | fixed | Option to skip delete prompt — fixed — `skip_confirm_for_delete` option | -| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry | +| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry; no upstream design yet, possible interaction gap with `prompt_save_on_select_new_entry` + `skip_confirm_for_simple_edits` | | [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | | [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | | [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | @@ -108,7 +109,7 @@ Bugs fixed in this fork that remain open upstream. | [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | | [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | | [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | -| [#507](https://github.com/stevearc/oil.nvim/issues/507) | open | lacasitos.nvim conflict (P1) | +| [#507](https://github.com/stevearc/oil.nvim/issues/507) | not actionable | lacasitos.nvim conflict on Windows — cross-plugin + Windows-only, no actionable fix | | [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | | [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | | [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | @@ -159,4 +160,5 @@ Bugs fixed in this fork that remain open upstream. | [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | | [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | | [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | -| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | feature request: make icons virtual text | +| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | Make icons virtual text — related to [#667](https://github.com/stevearc/oil.nvim/pull/667) (virtual text columns, deferred) | +| [#738](https://github.com/stevearc/oil.nvim/issues/738) | open | Allow changing mtime/atime via time column (P2) | diff --git a/lua/canola/init.lua b/lua/canola/init.lua index 6a3a990..40165ca 100644 --- a/lua/canola/init.lua +++ b/lua/canola/init.lua @@ -356,6 +356,79 @@ M.toggle_float = function(dir, opts, cb) end end +---@class (exact) canola.OpenSplitOpts : canola.OpenOpts +---@field vertical? boolean Open the buffer in a vertical split +---@field horizontal? boolean Open the buffer in a horizontal split +---@field split? "aboveleft"|"belowright"|"topleft"|"botright" Split modifier + +---Open canola browser in a split window +---@param dir? string When nil, open the parent of the current buffer, or the cwd if current buffer is not a file +---@param opts? canola.OpenSplitOpts +---@param cb? fun() Called after the canola buffer is ready +M.open_split = function(dir, opts, cb) + opts = opts or {} + local config = require('canola.config') + local util = require('canola.util') + local view = require('canola.view') + + local parent_url, basename = M.get_url_for_path(dir) + if basename then + view.set_last_cursor(parent_url, basename) + end + + if not opts.vertical and opts.horizontal == nil then + opts.horizontal = true + end + if not opts.split then + if opts.horizontal then + opts.split = vim.o.splitbelow and 'belowright' or 'aboveleft' + else + opts.split = vim.o.splitright and 'belowright' or 'aboveleft' + end + end + + local mods = { + vertical = opts.vertical, + horizontal = opts.horizontal, + split = opts.split, + } + + local original_winid = vim.api.nvim_get_current_win() + vim.cmd.split({ mods = mods }) + local winid = vim.api.nvim_get_current_win() + + vim.w[winid].is_canola_win = true + vim.w[winid].canola_original_win = original_winid + + vim.cmd.edit({ args = { util.escape_filename(parent_url) }, mods = { keepalt = true } }) + if config.buf_options.buflisted ~= nil then + vim.api.nvim_set_option_value('buflisted', config.buf_options.buflisted, { buf = 0 }) + end + + util.run_after_load(0, function() + if opts.preview then + M.open_preview(opts.preview, cb) + elseif cb then + cb() + end + end) +end + +---Open canola browser in a split window, or close it if open +---@param dir nil|string When nil, open the parent of the current buffer, or the cwd if current buffer is not a file +---@param opts? canola.OpenSplitOpts +---@param cb? fun() Called after the canola buffer is ready +M.toggle_split = function(dir, opts, cb) + if vim.w.is_canola_win then + M.close() + if cb then + cb() + end + else + M.open_split(dir, opts, cb) + end +end + ---@param canola_bufnr? integer local function update_preview_window(canola_bufnr) canola_bufnr = canola_bufnr or 0 @@ -419,7 +492,10 @@ M.close = function(opts) -- If we're in a floating canola window, close it and try to restore focus to the original window if vim.w.is_canola_win then local original_winid = vim.w.canola_original_win - vim.api.nvim_win_close(0, true) + local ok, _ = pcall(vim.api.nvim_win_close, 0, true) + if not ok then + vim.cmd.enew() + end if original_winid and vim.api.nvim_win_is_valid(original_winid) then vim.api.nvim_set_current_win(original_winid) end From a9a06b8f3ba1486bb1ca6dd465f95586567264a4 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sat, 7 Mar 2026 16:08:34 -0500 Subject: [PATCH 65/77] feat: add `auto_save_on_select_new_entry` config option (#84) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: users who want hands-off behaviour had no way to skip the `prompt_save_on_select_new_entry` confirmation dialog — enabling the prompt meant always being asked, with no silent auto-save path. Solution: add `auto_save_on_select_new_entry` (default `false`) which, when true, calls `M.save()` and proceeds immediately instead of showing the confirm dialog. Includes type annotations, vimdoc, and upstream tracker update for stevearc/oil.nvim#393. --- doc/canola.txt | 6 ++++++ doc/upstream.md | 2 +- lua/canola/config.lua | 3 +++ lua/canola/init.lua | 4 ++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/canola.txt b/doc/canola.txt index 5de8a52..0c3f7a2 100644 --- a/doc/canola.txt +++ b/doc/canola.txt @@ -316,6 +316,12 @@ prompt_save_on_select_new_entry *canola.prompt_save_on_select_new_e When this option is `true`, Canola will prompt you to save before entering a file or directory that is pending within canola, but does not exist on disk. +auto_save_on_select_new_entry *canola.auto_save_on_select_new_entry* + type: `boolean` default: `false` + When `prompt_save_on_select_new_entry` is true and you select a + new/moved/renamed entry, automatically save without prompting instead of + showing a confirmation dialog. + cleanup_buffers_on_delete *canola.cleanup_buffers_on_delete* type: `boolean` default: `false` When `true`, canola will wipe any open buffer whose path matches a file that diff --git a/doc/upstream.md b/doc/upstream.md index 9600c74..ac13a9a 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -90,7 +90,7 @@ Bugs fixed in this fork that remain open upstream. | [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show currently-edited hidden files in listing even when `show_hidden = false`; no upstream response, nice to have | | [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | | [#392](https://github.com/stevearc/oil.nvim/issues/392) | fixed | Option to skip delete prompt — fixed — `skip_confirm_for_delete` option | -| [#393](https://github.com/stevearc/oil.nvim/issues/393) | open | Auto-save new buffer on entry; no upstream design yet, possible interaction gap with `prompt_save_on_select_new_entry` + `skip_confirm_for_simple_edits` | +| [#393](https://github.com/stevearc/oil.nvim/issues/393) | fixed | Auto-save on select — `auto_save_on_select_new_entry` option | | [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | | [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | | [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | diff --git a/lua/canola/config.lua b/lua/canola/config.lua index 12d2751..3b8e0c1 100644 --- a/lua/canola/config.lua +++ b/lua/canola/config.lua @@ -36,6 +36,7 @@ local default_config = { -- Selecting a new/moved/renamed file or directory will prompt you to save changes first -- (:help prompt_save_on_select_new_entry) prompt_save_on_select_new_entry = true, + auto_save_on_select_new_entry = false, -- Canola will automatically delete hidden buffers after this delay -- You can set the delay to false to disable cleanup entirely -- Note that the cleanup process only starts when none of the canola buffers are currently displayed @@ -239,6 +240,7 @@ default_config.view_options.highlight_filename = nil ---@field skip_confirm_for_simple_edits boolean ---@field skip_confirm_for_delete boolean ---@field prompt_save_on_select_new_entry boolean +---@field auto_save_on_select_new_entry boolean ---@field cleanup_delay_ms integer ---@field lsp_file_methods canola.LspFileMethods ---@field constrain_cursor false|"name"|"editable" @@ -272,6 +274,7 @@ local M = {} ---@field skip_confirm_for_simple_edits? boolean Skip the confirmation popup for simple operations (:help canola.skip_confirm_for_simple_edits). ---@field skip_confirm_for_delete? boolean Skip the confirmation popup when all pending actions are deletes (:help canola.skip_confirm_for_delete). ---@field prompt_save_on_select_new_entry? boolean Selecting a new/moved/renamed file or directory will prompt you to save changes first (:help prompt_save_on_select_new_entry). +---@field auto_save_on_select_new_entry? boolean Automatically save changes when selecting a new/moved/renamed entry, instead of prompting (:help canola.auto_save_on_select_new_entry). ---@field cleanup_delay_ms? integer Canola will automatically delete hidden buffers after this delay. You can set the delay to false to disable cleanup entirely. Note that the cleanup process only starts when none of the canola buffers are currently displayed. ---@field lsp_file_methods? canola.SetupLspFileMethods Configure LSP file operation integration. ---@field constrain_cursor? false|"name"|"editable" Constrain the cursor to the editable parts of the canola buffer. Set to `false` to disable, or "name" to keep it on the file names. diff --git a/lua/canola/init.lua b/lua/canola/init.lua index 40165ca..e5e510b 100644 --- a/lua/canola/init.lua +++ b/lua/canola/init.lua @@ -788,6 +788,10 @@ M.select = function(opts, callback) end end if any_moved and config.prompt_save_on_select_new_entry then + if config.auto_save_on_select_new_entry then + M.save() + return finish() + end local ok, choice = pcall(vim.fn.confirm, 'Save changes?', 'Yes\nNo', 1) if not ok then return finish() From 4a8d57a269db08074050711dbb39e3921dfea153 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sat, 7 Mar 2026 16:52:57 -0500 Subject: [PATCH 66/77] feat: add max_file_size preview limit and show_hidden_when_empty (#85) * feat(preview): add `max_file_size` config to skip large file previews Problem: previewing large files (e.g. 500 MB logs, binaries) loads them into a buffer and can freeze or OOM Neovim. `disable_preview` only receives the filename, so users cannot gate on file size. Solution: add `preview_win.max_file_size` (number, MB, default 10). In `open_preview`, check `entry.meta.stat.size` and fall back to `vim.uv.fs_stat` when the cached stat is absent. If the file exceeds the limit and a preview window is already open, render "File too large to preview" in it; if not, emit a WARN notify and return early. The cursor-moved auto-update path only fires when a window already exists, so no flag threading is needed to distinguish explicit from implicit. Based on: stevearc/oil.nvim#213 * feat(view): add `show_hidden_when_empty` for hidden-only directories Problem: with `show_hidden = false`, a directory containing only dotfiles renders as just `..`, giving no indication that entries exist. Solution: add `view_options.show_hidden_when_empty` (boolean, default false). After the main filter loop in `render_buffer`, if the option is set and `#line_table <= 1`, iterate `entry_list` again and render any entry not matched by `is_always_hidden`, using `is_hidden = true` so they render with the dimmed hidden style. Based on: stevearc/oil.nvim#473 * docs(upstream): fix formatting * docs(upstream): update #213 and #473 with PR and commit links --- doc/canola.txt | 20 ++++++++++++++++++++ doc/upstream.md | 6 ++++-- lua/canola/config.lua | 6 ++++++ lua/canola/init.lua | 18 +++++++++++++++++- lua/canola/view.lua | 15 +++++++++++++++ 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/doc/canola.txt b/doc/canola.txt index 0c3f7a2..bd302f0 100644 --- a/doc/canola.txt +++ b/doc/canola.txt @@ -152,6 +152,9 @@ The full list of options with their defaults: view_options = { -- Show files and directories that start with "." show_hidden = false, + -- When true and a directory has no visible entries, show hidden entries + -- instead of an empty listing. is_always_hidden entries are never shown. + show_hidden_when_empty = false, -- This function defines what is considered a "hidden" file is_hidden_file = function(name, bufnr) local m = name:match("^%.") @@ -227,6 +230,10 @@ The full list of options with their defaults: disable_preview = function(filename) return false end, + -- Maximum file size in MB to load into the preview window. Files larger + -- than this limit will show a placeholder message instead of being loaded. + -- Set to nil to disable the limit. + max_file_size = 10, -- Window-local options to use for preview window buffers win_options = {}, }, @@ -328,6 +335,19 @@ cleanup_buffers_on_delete *canola.cleanup_buffers_on_de was successfully deleted via canola. This prevents stale buffers from appearing in the jumplist after a deletion. +show_hidden_when_empty *canola.show_hidden_when_empty* + type: `boolean` default: `false` + When `true` and a directory contains no visible entries (because all + entries are hidden), canola will display the hidden entries anyway. + Entries matching `is_always_hidden` are never shown. Hidden entries + are still rendered with the dimmed hidden style. + +preview_win.max_file_size *canola.preview_win* + type: `number` default: `10` + Maximum file size in MB to load into the preview window. Files larger + than this limit will show a placeholder message instead of being loaded. + Set to `nil` to disable the limit. + -------------------------------------------------------------------------------- API *canola-api* diff --git a/doc/upstream.md b/doc/upstream.md index ac13a9a..1e4d541 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -35,6 +35,8 @@ Bugs fixed in this fork that remain open upstream. | [#670](https://github.com/stevearc/oil.nvim/issues/670) | Multi-directory cmdline args ignored | [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | | [#673](https://github.com/stevearc/oil.nvim/issues/673) | Symlink newlines crash | [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | | [#710](https://github.com/stevearc/oil.nvim/issues/710) | buftype empty on BufEnter | [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | +| [#213](https://github.com/stevearc/oil.nvim/issues/213) | Max file size for preview | [#85](https://github.com/barrettruth/canola.nvim/pull/85) ([`4b32ada`](https://github.com/barrettruth/canola.nvim/commit/4b32ada)) | +| [#473](https://github.com/stevearc/oil.nvim/issues/473) | Show hidden when dir is all-hidden | [#85](https://github.com/barrettruth/canola.nvim/pull/85) ([`2fe4e78`](https://github.com/barrettruth/canola.nvim/commit/2fe4e78)) | ## Open upstream PRs @@ -61,7 +63,7 @@ Bugs fixed in this fork that remain open upstream. | [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | | [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | | [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | -| [#213](https://github.com/stevearc/oil.nvim/issues/213) | open | Disable preview for large files (P1) | +| [#213](https://github.com/stevearc/oil.nvim/issues/213) | fixed | Disable preview for large files — `preview_win.max_file_size` (P1) | | [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | | [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | | [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | @@ -104,7 +106,7 @@ Bugs fixed in this fork that remain open upstream. | [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | | [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | | [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | -| [#473](https://github.com/stevearc/oil.nvim/issues/473) | open | Show all hidden files if dir only has hidden | +| [#473](https://github.com/stevearc/oil.nvim/issues/473) | fixed | Show all hidden files if dir only has hidden — `view_options.show_hidden_when_empty` | | [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | | [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | | [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | diff --git a/lua/canola/config.lua b/lua/canola/config.lua index 3b8e0c1..25e8876 100644 --- a/lua/canola/config.lua +++ b/lua/canola/config.lua @@ -84,6 +84,7 @@ local default_config = { view_options = { -- Show files and directories that start with "." show_hidden = false, + show_hidden_when_empty = false, -- This function defines what is considered a "hidden" file is_hidden_file = function(name, bufnr) local m = name:match('^%.') @@ -159,6 +160,7 @@ local default_config = { disable_preview = function(filename) return false end, + max_file_size = 10, -- Window-local options to use for preview window buffers win_options = {}, }, @@ -306,6 +308,7 @@ local M = {} ---@class (exact) canola.ViewOptions ---@field show_hidden boolean +---@field show_hidden_when_empty boolean ---@field is_hidden_file fun(name: string, bufnr: integer, entry: canola.Entry): boolean ---@field is_always_hidden fun(name: string, bufnr: integer, entry: canola.Entry): boolean ---@field natural_order boolean|"fast" @@ -315,6 +318,7 @@ local M = {} ---@class (exact) canola.SetupViewOptions ---@field show_hidden? boolean Show files and directories that start with "." +---@field show_hidden_when_empty? boolean When true and the directory has no visible entries, show hidden entries instead of an empty listing (:help canola.show_hidden_when_empty). ---@field is_hidden_file? fun(name: string, bufnr: integer): boolean This function defines what is considered a "hidden" file ---@field is_always_hidden? fun(name: string, bufnr: integer): boolean This function defines what will never be shown, even when `show_hidden` is set ---@field natural_order? boolean|"fast" Sort file names with numbers in a more intuitive order for humans. Can be slow for large directories. @@ -371,6 +375,7 @@ local M = {} ---@field update_on_cursor_moved boolean ---@field preview_method canola.PreviewMethod ---@field disable_preview fun(filename: string): boolean +---@field max_file_size number Maximum file size (in MB) to preview. Files larger than this will show a placeholder. ---@field win_options table ---@class (exact) canola.ConfirmationWindowConfig : canola.WindowConfig @@ -378,6 +383,7 @@ local M = {} ---@class (exact) canola.SetupPreviewWindowConfig ---@field update_on_cursor_moved? boolean Whether the preview window is automatically updated when the cursor is moved ---@field disable_preview? fun(filename: string): boolean A function that returns true to disable preview on a file e.g. to avoid lag +---@field max_file_size? number Maximum file size in MB to show in preview. Files exceeding this will not be loaded (:help canola.preview_win). Set to nil to disable the limit. ---@field preview_method? canola.PreviewMethod How to open the preview window ---@field win_options? table Window-local options to use for preview window buffers diff --git a/lua/canola/init.lua b/lua/canola/init.lua index e5e510b..18d9896 100644 --- a/lua/canola/init.lua +++ b/lua/canola/init.lua @@ -642,7 +642,23 @@ M.open_preview = function(opts, callback) local entry_is_file = not vim.endswith(normalized_url, '/') local filebufnr if entry_is_file then - if config.preview_win.disable_preview(normalized_url) then + local max_mb = config.preview_win.max_file_size + local _size = entry.meta and entry.meta.stat and entry.meta.stat.size + if not _size then + local _st = vim.uv.fs_stat(normalized_url) + _size = _st and _st.size + end + if max_mb and _size and _size > max_mb * 1024 * 1024 then + if preview_win then + filebufnr = vim.api.nvim_create_buf(false, true) + vim.bo[filebufnr].bufhidden = 'wipe' + vim.bo[filebufnr].buftype = 'nofile' + util.render_text(filebufnr, 'File too large to preview', { winid = preview_win }) + else + vim.notify('File too large to preview', vim.log.levels.WARN) + return finish() + end + elseif config.preview_win.disable_preview(normalized_url) then filebufnr = vim.api.nvim_create_buf(false, true) vim.bo[filebufnr].bufhidden = 'wipe' vim.bo[filebufnr].buftype = 'nofile' diff --git a/lua/canola/view.lua b/lua/canola/view.lua index 0f75faf..7a7ac89 100644 --- a/lua/canola/view.lua +++ b/lua/canola/view.lua @@ -807,6 +807,21 @@ local function render_buffer(bufnr, opts) end end + if config.view_options.show_hidden_when_empty and #line_table <= 1 then + for _, entry in ipairs(entry_list) do + local name = entry[FIELD_NAME] + local public_entry = util.export_entry(entry) + if not config.view_options.is_always_hidden(name, bufnr, public_entry) then + local cols = M.format_entry_cols(entry, column_defs, col_width, adapter, true, bufnr) + table.insert(line_table, cols) + if seek_after_render == name then + seek_after_render_found = true + jump_idx = #line_table + end + end + end + end + local lines, highlights = util.render_table(line_table, col_width, col_align) vim.bo[bufnr].modifiable = true From 91562016c88cf403cdfc2798a4bee94304aff833 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sat, 7 Mar 2026 17:05:46 -0500 Subject: [PATCH 67/77] docs(upstream): mark #380 not actionable (#86) --- doc/upstream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/upstream.md b/doc/upstream.md index 1e4d541..81c4311 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -89,7 +89,7 @@ Bugs fixed in this fork that remain open upstream. | [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | | [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | | [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | -| [#380](https://github.com/stevearc/oil.nvim/issues/380) | open | Show currently-edited hidden files in listing even when `show_hidden = false`; no upstream response, nice to have | +| [#380](https://github.com/stevearc/oil.nvim/issues/380) | not actionable | Silently overriding `show_hidden` based on buffer state is counter to the config's intent | | [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | | [#392](https://github.com/stevearc/oil.nvim/issues/392) | fixed | Option to skip delete prompt — fixed — `skip_confirm_for_delete` option | | [#393](https://github.com/stevearc/oil.nvim/issues/393) | fixed | Auto-save on select — `auto_save_on_select_new_entry` option | From abc4879688e88d4d9aea81de85eedc22e3520bbf Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sat, 7 Mar 2026 21:12:45 -0500 Subject: [PATCH 68/77] Fix require statement for oil.nvim setup --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 122216e..121a52f 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Before (`stevearc/oil.nvim`): 'stevearc/oil.nvim', opts = { ... }, config = function(_, opts) - require('canola').setup(opts) + require('oil').setup(opts) end, } ``` @@ -67,8 +67,9 @@ After (`barrettruth/canola.nvim`): ```lua { 'barrettruth/canola.nvim', - init = function() - vim.g.canola = { ... } + opts = { ... }, + config = function(_, opts) + require('canola').setup(opts) end, } ``` From fc43684bbd5ce97596a376c2a4f157129b9a3881 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 8 Mar 2026 15:31:43 -0400 Subject: [PATCH 69/77] fix(columns): hide misleading directory sizes (#87) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(columns): hide misleading directory sizes in size column Problem: the size column shows the filesystem inode size (typically 4096 = 4.1k) for directories, which is misleading — users expect no size for directories. Solution: add an early return for directory entries in the size render function of the files, SSH, and S3 adapters. Co-Authored-By: Claude Opus 4.6 * docs(upstream): mark #486 fixed --------- Co-authored-by: Claude Opus 4.6 --- doc/upstream.md | 3 ++- lua/canola/adapters/files.lua | 3 +++ lua/canola/adapters/s3.lua | 7 ++++++- lua/canola/adapters/ssh.lua | 7 ++++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index 81c4311..a485041 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -37,6 +37,7 @@ Bugs fixed in this fork that remain open upstream. | [#710](https://github.com/stevearc/oil.nvim/issues/710) | buftype empty on BufEnter | [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | | [#213](https://github.com/stevearc/oil.nvim/issues/213) | Max file size for preview | [#85](https://github.com/barrettruth/canola.nvim/pull/85) ([`4b32ada`](https://github.com/barrettruth/canola.nvim/commit/4b32ada)) | | [#473](https://github.com/stevearc/oil.nvim/issues/473) | Show hidden when dir is all-hidden | [#85](https://github.com/barrettruth/canola.nvim/pull/85) ([`2fe4e78`](https://github.com/barrettruth/canola.nvim/commit/2fe4e78)) | +| [#486](https://github.com/stevearc/oil.nvim/issues/486) | Directory sizes show misleading 4.1k | [#87](https://github.com/barrettruth/canola.nvim/pull/87) ([`2aff22a`](https://github.com/barrettruth/canola.nvim/commit/2aff22a)) | ## Open upstream PRs @@ -109,7 +110,7 @@ Bugs fixed in this fork that remain open upstream. | [#473](https://github.com/stevearc/oil.nvim/issues/473) | fixed | Show all hidden files if dir only has hidden — `view_options.show_hidden_when_empty` | | [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | | [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | -| [#486](https://github.com/stevearc/oil.nvim/issues/486) | open | All directory sizes show 4.1k | +| [#486](https://github.com/stevearc/oil.nvim/issues/486) | fixed | Directory sizes show 4.1k — [#87](https://github.com/barrettruth/canola.nvim/pull/87) ([`2aff22a`](https://github.com/barrettruth/canola.nvim/commit/2aff22a)) | | [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | | [#507](https://github.com/stevearc/oil.nvim/issues/507) | not actionable | lacasitos.nvim conflict on Windows — cross-plugin + Windows-only, no actionable fix | | [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | diff --git a/lua/canola/adapters/files.lua b/lua/canola/adapters/files.lua index dff8e1a..f828b37 100644 --- a/lua/canola/adapters/files.lua +++ b/lua/canola/adapters/files.lua @@ -60,6 +60,9 @@ file_columns.size = { if not stat then return columns.EMPTY end + if entry[FIELD_TYPE] == 'directory' then + return columns.EMPTY + end if stat.size >= 1e9 then return string.format('%.1fG', stat.size / 1e9) elseif stat.size >= 1e6 then diff --git a/lua/canola/adapters/s3.lua b/lua/canola/adapters/s3.lua index bc3e614..d1d82f1 100644 --- a/lua/canola/adapters/s3.lua +++ b/lua/canola/adapters/s3.lua @@ -8,6 +8,7 @@ local s3fs = require('canola.adapters.s3.s3fs') local util = require('canola.util') local M = {} +local FIELD_TYPE = constants.FIELD_TYPE local FIELD_META = constants.FIELD_META ---@class (exact) canola.s3Url @@ -84,7 +85,11 @@ s3_columns.size = { local meta = entry[FIELD_META] if not meta or not meta.size then return '' - elseif meta.size >= 1e9 then + end + if entry[FIELD_TYPE] == 'directory' then + return '' + end + if meta.size >= 1e9 then return string.format('%.1fG', meta.size / 1e9) elseif meta.size >= 1e6 then return string.format('%.1fM', meta.size / 1e6) diff --git a/lua/canola/adapters/ssh.lua b/lua/canola/adapters/ssh.lua index 4654b32..a0750e9 100644 --- a/lua/canola/adapters/ssh.lua +++ b/lua/canola/adapters/ssh.lua @@ -11,6 +11,7 @@ local util = require('canola.util') local M = {} local FIELD_NAME = constants.FIELD_NAME +local FIELD_TYPE = constants.FIELD_TYPE local FIELD_META = constants.FIELD_META ---@class (exact) canola.sshUrl @@ -152,7 +153,11 @@ ssh_columns.size = { local meta = entry[FIELD_META] if not meta or not meta.size then return '' - elseif meta.size >= 1e9 then + end + if entry[FIELD_TYPE] == 'directory' then + return '' + end + if meta.size >= 1e9 then return string.format('%.1fG', meta.size / 1e9) elseif meta.size >= 1e6 then return string.format('%.1fM', meta.size / 1e6) From 94db584f81aef95d2b5c2b23d5d3b925fda0b281 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 8 Mar 2026 15:33:45 -0400 Subject: [PATCH 70/77] feat: add `toggle()` API for regular windows (#88) * feat: add `toggle()` API for regular windows Problem: `toggle_float()` and `toggle_split()` exist but there is no `toggle()` for regular windows, forcing users to write their own filetype-checking wrapper. Solution: add `M.toggle()` that delegates to `close()` or `open()` based on whether the current buffer is a canola buffer. Includes vimdoc entry. * docs(upstream): mark #621 fixed --- doc/canola.txt | 15 +++++++++++++++ doc/upstream.md | 3 ++- lua/canola/init.lua | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/doc/canola.txt b/doc/canola.txt index bd302f0..d716997 100644 --- a/doc/canola.txt +++ b/doc/canola.txt @@ -479,6 +479,21 @@ close({opts}) *canola.c {exit_if_last_buf} `nil|boolean` Exit vim if this canola buffer is the last open buffer +toggle({dir}, {opts}, {cb}) *canola.toggle* + Open canola browser for a directory, or close it if already open + + Parameters: + {dir} `nil|string` When nil, open the parent of the current buffer, or + the cwd if current buffer is not a file + {opts} `nil|canola.OpenOpts` + {preview} `nil|canola.OpenPreviewOpts` When present, open the preview + window after opening canola + {vertical} `nil|boolean` Open the buffer in a vertical split + {horizontal} `nil|boolean` Open the buffer in a horizontal split + {split} `nil|"aboveleft"|"belowright"|"topleft"|"botright"` S + plit modifier + {cb} `nil|fun()` Called after the canola buffer is ready + open_preview({opts}, {callback}) *canola.open_preview* Preview the entry under the cursor in a split diff --git a/doc/upstream.md b/doc/upstream.md index a485041..af99bc0 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -38,6 +38,7 @@ Bugs fixed in this fork that remain open upstream. | [#213](https://github.com/stevearc/oil.nvim/issues/213) | Max file size for preview | [#85](https://github.com/barrettruth/canola.nvim/pull/85) ([`4b32ada`](https://github.com/barrettruth/canola.nvim/commit/4b32ada)) | | [#473](https://github.com/stevearc/oil.nvim/issues/473) | Show hidden when dir is all-hidden | [#85](https://github.com/barrettruth/canola.nvim/pull/85) ([`2fe4e78`](https://github.com/barrettruth/canola.nvim/commit/2fe4e78)) | | [#486](https://github.com/stevearc/oil.nvim/issues/486) | Directory sizes show misleading 4.1k | [#87](https://github.com/barrettruth/canola.nvim/pull/87) ([`2aff22a`](https://github.com/barrettruth/canola.nvim/commit/2aff22a)) | +| [#621](https://github.com/stevearc/oil.nvim/issues/621) | `toggle()` for regular windows | [#88](https://github.com/barrettruth/canola.nvim/pull/88) ([`385bd82`](https://github.com/barrettruth/canola.nvim/commit/385bd82)) | ## Open upstream PRs @@ -127,7 +128,7 @@ Bugs fixed in this fork that remain open upstream. | [#612](https://github.com/stevearc/oil.nvim/issues/612) | fixed | Delete buffers on file delete — `cleanup_buffers_on_delete` option | | [#615](https://github.com/stevearc/oil.nvim/issues/615) | fixed | Cursor at name column on o/O — [#72](https://github.com/barrettruth/canola.nvim/pull/72) ([`69d85b8`](https://github.com/barrettruth/canola.nvim/commit/69d85b8)) | | [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | -| [#621](https://github.com/stevearc/oil.nvim/issues/621) | open | Toggle function for regular windows (P2) | +| [#621](https://github.com/stevearc/oil.nvim/issues/621) | fixed | `toggle()` for regular windows — [#88](https://github.com/barrettruth/canola.nvim/pull/88) ([`385bd82`](https://github.com/barrettruth/canola.nvim/commit/385bd82)) | | [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | | [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | | [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | diff --git a/lua/canola/init.lua b/lua/canola/init.lua index 18d9896..e556920 100644 --- a/lua/canola/init.lua +++ b/lua/canola/init.lua @@ -526,6 +526,20 @@ M.close = function(opts) vim.api.nvim_buf_delete(canolabuf, { force = true }) end +---@param dir? string +---@param opts? canola.OpenOpts +---@param cb? fun() +M.toggle = function(dir, opts, cb) + if vim.w.is_canola_win or vim.bo.filetype == 'canola' then + M.close() + if cb then + cb() + end + else + M.open(dir, opts, cb) + end +end + ---@class canola.OpenPreviewOpts ---@field vertical? boolean Open the buffer in a vertical split ---@field horizontal? boolean Open the buffer in a horizontal split From 76e1aacde0f68b3fa29c6d40c5d3bcc864fa76d5 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 8 Mar 2026 15:41:37 -0400 Subject: [PATCH 71/77] docs(upstream): reorganize tracker into grouped tables (#89) Problem: the upstream tracker had duplicate entries across tables, fragile commit hash references, a 108-row flat table mixing all statuses, and inconsistent formatting. Solution: merge PR tables into one, split issues by status (fixed, resolved, open, not actionable), drop all commit hashes in favor of stable PR numbers, and eliminate duplication so each entry appears exactly once. --- doc/upstream.md | 303 ++++++++++++++++++++++++------------------------ 1 file changed, 149 insertions(+), 154 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index af99bc0..8aa9b27 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -3,166 +3,161 @@ Triage of [stevearc/oil.nvim](https://github.com/stevearc/oil.nvim) PRs and issues against this fork. -## Cherry-picked PRs +## Upstream PRs -Upstream PRs cherry-picked or adapted into this fork. +| PR | Description | Status | +|----|-------------|--------| +| [#495](https://github.com/stevearc/oil.nvim/pull/495) | Cancel visual/operator-pending mode on close | cherry-picked | +| [#537](https://github.com/stevearc/oil.nvim/pull/537) | Configurable file/directory creation permissions | cherry-picked | +| [#618](https://github.com/stevearc/oil.nvim/pull/618) | Opt-in filetype detection for icons | cherry-picked | +| [#644](https://github.com/stevearc/oil.nvim/pull/644) | Pass entry to `is_hidden_file`/`is_always_hidden` | cherry-picked | +| [#697](https://github.com/stevearc/oil.nvim/pull/697) | Recipe for file extension column | cherry-picked | +| [#698](https://github.com/stevearc/oil.nvim/pull/698) | Executable file highlighting | cherry-picked | +| [#717](https://github.com/stevearc/oil.nvim/pull/717) | Add oil-git.nvim to extensions | cherry-picked | +| [#720](https://github.com/stevearc/oil.nvim/pull/720) | Gate `BufAdd` autocmd behind config check | cherry-picked | +| [#722](https://github.com/stevearc/oil.nvim/pull/722) | Fix freedesktop trash URL | cherry-picked | +| [#723](https://github.com/stevearc/oil.nvim/pull/723) | Emit `OilReadPost` event after render | cherry-picked | +| [#725](https://github.com/stevearc/oil.nvim/pull/725) | Normalize keymap keys before config merge | cherry-picked | +| [#727](https://github.com/stevearc/oil.nvim/pull/727) | Clarify `get_current_dir` nil + Telescope recipe | cherry-picked | +| [#739](https://github.com/stevearc/oil.nvim/pull/739) | macOS FreeDesktop trash recipe | cherry-picked | +| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | +| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | +| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | +| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with selection | not actionable — hardcoded Linux-only, incomplete | +| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | +| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | +| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | +| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | deferred — fixing via autocmd event | +| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | deferred — tracked as [#2](https://github.com/barrettruth/canola.nvim/issues/2) | -| PR | Description | Commit | -| ----------------------------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| [#495](https://github.com/stevearc/oil.nvim/pull/495) | Cancel visual/operator-pending mode on close | [`16f3d7b`](https://github.com/barrettruth/canola.nvim/commit/16f3d7b) | -| [#537](https://github.com/stevearc/oil.nvim/pull/537) | Configurable file/directory creation permissions | [`c6b4a7a`](https://github.com/barrettruth/canola.nvim/commit/c6b4a7a) | -| [#618](https://github.com/stevearc/oil.nvim/pull/618) | Opt-in filetype detection for icons | [`ded1725`](https://github.com/barrettruth/canola.nvim/commit/ded1725) | -| [#644](https://github.com/stevearc/oil.nvim/pull/644) | Pass entry to `is_hidden_file`/`is_always_hidden` | [`4ab4765`](https://github.com/barrettruth/canola.nvim/commit/4ab4765) | -| [#697](https://github.com/stevearc/oil.nvim/pull/697) | Recipe for file extension column | [`dcb3a08`](https://github.com/barrettruth/canola.nvim/commit/dcb3a08) | -| [#698](https://github.com/stevearc/oil.nvim/pull/698) | Executable file highlighting | [`41556ec`](https://github.com/barrettruth/canola.nvim/commit/41556ec), [`85ed9b8`](https://github.com/barrettruth/canola.nvim/commit/85ed9b8) | -| [#717](https://github.com/stevearc/oil.nvim/pull/717) | Add oil-git.nvim to extensions | [`582d9fc`](https://github.com/barrettruth/canola.nvim/commit/582d9fc) | -| [#720](https://github.com/stevearc/oil.nvim/pull/720) | Gate `BufAdd` autocmd behind config check | [`2228f80`](https://github.com/barrettruth/canola.nvim/commit/2228f80) | -| [#722](https://github.com/stevearc/oil.nvim/pull/722) | Fix freedesktop trash URL | [`b92ecb0`](https://github.com/barrettruth/canola.nvim/commit/b92ecb0) | -| [#723](https://github.com/stevearc/oil.nvim/pull/723) | Emit `OilReadPost` event after render | [`29239d5`](https://github.com/barrettruth/canola.nvim/commit/29239d5) | -| [#725](https://github.com/stevearc/oil.nvim/pull/725) | Normalize keymap keys before config merge | [`723145c`](https://github.com/barrettruth/canola.nvim/commit/723145c) | -| [#727](https://github.com/stevearc/oil.nvim/pull/727) | Clarify `get_current_dir` nil + Telescope recipe | [`eed6697`](https://github.com/barrettruth/canola.nvim/commit/eed6697) | -| [#739](https://github.com/stevearc/oil.nvim/pull/739) | macOS FreeDesktop trash recipe | `doc/canola.txt` (`canola-recipe-macos-freedesktop-trash`) | +## Issues — fixed (original) -## Original fixes +Issues fixed in this fork that remain open upstream. -Bugs fixed in this fork that remain open upstream. +| Issue | Description | PR | +|-------|-------------|----| +| [#213](https://github.com/stevearc/oil.nvim/issues/213) | Disable preview for large files | [#85](https://github.com/barrettruth/canola.nvim/pull/85) | +| [#302](https://github.com/stevearc/oil.nvim/issues/302) | `buflisted=true` after jumplist nav | [#71](https://github.com/barrettruth/canola.nvim/pull/71) | +| [#363](https://github.com/stevearc/oil.nvim/issues/363) | `prompt_save_on_select_new_entry` wrong prompt | — | +| [#392](https://github.com/stevearc/oil.nvim/issues/392) | Option to skip delete prompt | — | +| [#393](https://github.com/stevearc/oil.nvim/issues/393) | Auto-save on select | — | +| [#473](https://github.com/stevearc/oil.nvim/issues/473) | Show hidden when dir is all-hidden | [#85](https://github.com/barrettruth/canola.nvim/pull/85) | +| [#486](https://github.com/stevearc/oil.nvim/issues/486) | Directory sizes show misleading 4.1k | [#87](https://github.com/barrettruth/canola.nvim/pull/87) | +| [#578](https://github.com/stevearc/oil.nvim/issues/578) | Hidden file dimming recipe | — | +| [#612](https://github.com/stevearc/oil.nvim/issues/612) | Delete buffers on file delete | — | +| [#615](https://github.com/stevearc/oil.nvim/issues/615) | Cursor at name column on o/O | [#72](https://github.com/barrettruth/canola.nvim/pull/72) | +| [#621](https://github.com/stevearc/oil.nvim/issues/621) | `toggle()` for regular windows | [#88](https://github.com/barrettruth/canola.nvim/pull/88) | +| [#632](https://github.com/stevearc/oil.nvim/issues/632) | Preview + move = copy | [#12](https://github.com/barrettruth/canola.nvim/pull/12) | +| [#642](https://github.com/stevearc/oil.nvim/issues/642) | W10 warning under `nvim -R` | — | +| [#645](https://github.com/stevearc/oil.nvim/issues/645) | `close_float` action | — | +| [#650](https://github.com/stevearc/oil.nvim/issues/650) | LSP `workspace.fileOperations` events | — | +| [#670](https://github.com/stevearc/oil.nvim/issues/670) | Multi-directory cmdline args ignored | [#11](https://github.com/barrettruth/canola.nvim/pull/11) | +| [#673](https://github.com/stevearc/oil.nvim/issues/673) | Symlink newlines crash | — | +| [#683](https://github.com/stevearc/oil.nvim/issues/683) | Path not shown in floating mode | — | +| [#690](https://github.com/stevearc/oil.nvim/issues/690) | `OilFileIcon` highlight group | — | +| [#710](https://github.com/stevearc/oil.nvim/issues/710) | buftype empty on BufEnter | [#10](https://github.com/barrettruth/canola.nvim/pull/10) | -| Upstream issue | Description | PR | -| ------------------------------------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | -| [#302](https://github.com/stevearc/oil.nvim/issues/302) | `buflisted=true` after jumplist nav | [#71](https://github.com/barrettruth/canola.nvim/pull/71) ([`a078bcf`](https://github.com/barrettruth/canola.nvim/commit/a078bcf)) | -| [#632](https://github.com/stevearc/oil.nvim/issues/632) | Preview + move = copy | [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | -| [#642](https://github.com/stevearc/oil.nvim/issues/642) | W10 warning under `nvim -R` | [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | -| [#670](https://github.com/stevearc/oil.nvim/issues/670) | Multi-directory cmdline args ignored | [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | -| [#673](https://github.com/stevearc/oil.nvim/issues/673) | Symlink newlines crash | [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | -| [#710](https://github.com/stevearc/oil.nvim/issues/710) | buftype empty on BufEnter | [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | -| [#213](https://github.com/stevearc/oil.nvim/issues/213) | Max file size for preview | [#85](https://github.com/barrettruth/canola.nvim/pull/85) ([`4b32ada`](https://github.com/barrettruth/canola.nvim/commit/4b32ada)) | -| [#473](https://github.com/stevearc/oil.nvim/issues/473) | Show hidden when dir is all-hidden | [#85](https://github.com/barrettruth/canola.nvim/pull/85) ([`2fe4e78`](https://github.com/barrettruth/canola.nvim/commit/2fe4e78)) | -| [#486](https://github.com/stevearc/oil.nvim/issues/486) | Directory sizes show misleading 4.1k | [#87](https://github.com/barrettruth/canola.nvim/pull/87) ([`2aff22a`](https://github.com/barrettruth/canola.nvim/commit/2aff22a)) | -| [#621](https://github.com/stevearc/oil.nvim/issues/621) | `toggle()` for regular windows | [#88](https://github.com/barrettruth/canola.nvim/pull/88) ([`385bd82`](https://github.com/barrettruth/canola.nvim/commit/385bd82)) | +## Issues — resolved (cherry-pick) -## Open upstream PRs +Issues addressed by cherry-picking upstream PRs. -| PR | Description | Status | -| ----------------------------------------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| [#488](https://github.com/stevearc/oil.nvim/pull/488) | Parent directory in a split | not actionable — empty PR | -| [#493](https://github.com/stevearc/oil.nvim/pull/493) | UNC paths on Windows | not actionable — superseded by [#686](https://github.com/stevearc/oil.nvim/pull/686) | -| [#591](https://github.com/stevearc/oil.nvim/pull/591) | release-please changelog | not applicable | -| [#667](https://github.com/stevearc/oil.nvim/pull/667) | Virtual text columns + headers | deferred — WIP, conflicting | -| [#686](https://github.com/stevearc/oil.nvim/pull/686) | Windows path conversion fix | not actionable — Windows-only | -| [#708](https://github.com/stevearc/oil.nvim/pull/708) | Move file into new dir by renaming | deferred — needs rewrite | -| [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | deferred — fixing via autocmd event on file create | -| [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | tracked — [#2](https://github.com/barrettruth/canola.nvim/issues/2) | -| [#735](https://github.com/stevearc/oil.nvim/pull/735) | gX opens external program with selection | not actionable — hardcoded Linux-only program list, no config surface, author-acknowledged incomplete | +| Issue | Description | Upstream PR | +|-------|-------------|-------------| +| [#446](https://github.com/stevearc/oil.nvim/issues/446) | Executable highlighting | [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#679](https://github.com/stevearc/oil.nvim/issues/679) | Executable file sign | [#698](https://github.com/stevearc/oil.nvim/pull/698) | +| [#682](https://github.com/stevearc/oil.nvim/issues/682) | `get_current_dir()` nil | [#727](https://github.com/stevearc/oil.nvim/pull/727) | +| [#692](https://github.com/stevearc/oil.nvim/issues/692) | Keymap normalization | [#725](https://github.com/stevearc/oil.nvim/pull/725) | -## Upstream issues +## Issues — open -| Issue | Status | Notes | -| ------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [#85](https://github.com/stevearc/oil.nvim/issues/85) | open | Git status column (P2) | -| [#95](https://github.com/stevearc/oil.nvim/issues/95) | open | Undo after renaming files (P1) | -| [#117](https://github.com/stevearc/oil.nvim/issues/117) | open | Move file into new dir via slash in name (P1, related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#156](https://github.com/stevearc/oil.nvim/issues/156) | open | Paste path of files into oil buffer (P2) | -| [#200](https://github.com/stevearc/oil.nvim/issues/200) | open | Highlights not working when opening a file (P2) | -| [#207](https://github.com/stevearc/oil.nvim/issues/207) | open | Suppress "no longer available" message (P1) | -| [#210](https://github.com/stevearc/oil.nvim/issues/210) | open | FTP support (P2) | -| [#213](https://github.com/stevearc/oil.nvim/issues/213) | fixed | Disable preview for large files — `preview_win.max_file_size` (P1) | -| [#226](https://github.com/stevearc/oil.nvim/issues/226) | open | K8s/Docker adapter (P2) | -| [#232](https://github.com/stevearc/oil.nvim/issues/232) | open | Cannot close last window (P2) | -| [#254](https://github.com/stevearc/oil.nvim/issues/254) | open | Buffer modified highlight group (P2) | -| [#263](https://github.com/stevearc/oil.nvim/issues/263) | open | Diff mode (P2) | -| [#276](https://github.com/stevearc/oil.nvim/issues/276) | open | Archives manipulation (P2) | -| [#280](https://github.com/stevearc/oil.nvim/issues/280) | open | vim-projectionist support (P2) | -| [#288](https://github.com/stevearc/oil.nvim/issues/288) | not actionable | No reliable repro; likely lazy.nvim timing issue — setting `lazy = false` resolves it for affected users | -| [#289](https://github.com/stevearc/oil.nvim/issues/289) | open | Show absolute path toggle (P2) | -| [#294](https://github.com/stevearc/oil.nvim/issues/294) | open | Can't handle emojis in filenames (P2) | -| [#298](https://github.com/stevearc/oil.nvim/issues/298) | open | Open float on neovim directory startup (P2) | -| [#302](https://github.com/stevearc/oil.nvim/issues/302) | fixed | `buflisted=true` after jumplist nav — [#71](https://github.com/barrettruth/canola.nvim/pull/71) ([`a078bcf`](https://github.com/barrettruth/canola.nvim/commit/a078bcf)) | -| [#303](https://github.com/stevearc/oil.nvim/issues/303) | open | Preview in float window mode (P2) | -| [#325](https://github.com/stevearc/oil.nvim/issues/325) | open | oil-ssh error from command line (P0) | -| [#330](https://github.com/stevearc/oil.nvim/issues/330) | not actionable | Telescope opens file in oil float — cross-plugin interaction, no repro provided | -| [#332](https://github.com/stevearc/oil.nvim/issues/332) | open | Buffer not fixed to floating window (P2) | -| [#335](https://github.com/stevearc/oil.nvim/issues/335) | open | Disable editing outside root dir | -| [#349](https://github.com/stevearc/oil.nvim/issues/349) | open | Parent directory as column/vsplit (P2) | -| [#351](https://github.com/stevearc/oil.nvim/issues/351) | open | Paste deleted file from register | -| [#359](https://github.com/stevearc/oil.nvim/issues/359) | open | Parse error on filenames differing by space (P1) | -| [#360](https://github.com/stevearc/oil.nvim/issues/360) | open | Pick window to open file into | -| [#362](https://github.com/stevearc/oil.nvim/issues/362) | not actionable | "Could not find oil adapter for scheme" — no minimal repro provided, old nvim version (0.9.5) | -| [#363](https://github.com/stevearc/oil.nvim/issues/363) | fixed | `prompt_save_on_select_new_entry` uses wrong prompt — escape now cancels select | -| [#371](https://github.com/stevearc/oil.nvim/issues/371) | open | Constrain cursor in insert mode | -| [#373](https://github.com/stevearc/oil.nvim/issues/373) | open | Dir from quickfix with bqf/trouble broken (P1) | -| [#375](https://github.com/stevearc/oil.nvim/issues/375) | open | Highlights for file types and permissions (P2) | -| [#380](https://github.com/stevearc/oil.nvim/issues/380) | not actionable | Silently overriding `show_hidden` based on buffer state is counter to the config's intent | -| [#382](https://github.com/stevearc/oil.nvim/issues/382) | open | Relative path in window title (P2) | -| [#392](https://github.com/stevearc/oil.nvim/issues/392) | fixed | Option to skip delete prompt — fixed — `skip_confirm_for_delete` option | -| [#393](https://github.com/stevearc/oil.nvim/issues/393) | fixed | Auto-save on select — `auto_save_on_select_new_entry` option | -| [#396](https://github.com/stevearc/oil.nvim/issues/396) | open | Customize preview content (P2) | -| [#399](https://github.com/stevearc/oil.nvim/issues/399) | open | Open file without closing Oil (P1) | -| [#404](https://github.com/stevearc/oil.nvim/issues/404) | not actionable | Restricted UNC paths — Windows-only (P2) | -| [#416](https://github.com/stevearc/oil.nvim/issues/416) | open | Cannot remap key to open split | -| [#431](https://github.com/stevearc/oil.nvim/issues/431) | open | More SSH adapter documentation | -| [#435](https://github.com/stevearc/oil.nvim/issues/435) | open | Error previewing with semantic tokens LSP | -| [#436](https://github.com/stevearc/oil.nvim/issues/436) | open | Owner and group columns (P2) | -| [#444](https://github.com/stevearc/oil.nvim/issues/444) | open | Opening behaviour customization | -| [#446](https://github.com/stevearc/oil.nvim/issues/446) | resolved | Executable highlighting — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#449](https://github.com/stevearc/oil.nvim/issues/449) | open | Renaming TypeScript files stopped working | -| [#450](https://github.com/stevearc/oil.nvim/issues/450) | open | Highlight opened file in directory listing | -| [#457](https://github.com/stevearc/oil.nvim/issues/457) | open | Custom column API | -| [#466](https://github.com/stevearc/oil.nvim/issues/466) | open | Select into window on right | -| [#473](https://github.com/stevearc/oil.nvim/issues/473) | fixed | Show all hidden files if dir only has hidden — `view_options.show_hidden_when_empty` | -| [#479](https://github.com/stevearc/oil.nvim/issues/479) | open | Harpoon integration recipe | -| [#483](https://github.com/stevearc/oil.nvim/issues/483) | not actionable | Spell downloads depend on netrw — fixed in [neovim#34940](https://github.com/neovim/neovim/pull/34940) | -| [#486](https://github.com/stevearc/oil.nvim/issues/486) | fixed | Directory sizes show 4.1k — [#87](https://github.com/barrettruth/canola.nvim/pull/87) ([`2aff22a`](https://github.com/barrettruth/canola.nvim/commit/2aff22a)) | -| [#492](https://github.com/stevearc/oil.nvim/issues/492) | not actionable | j/k remapping question — answered in comments | -| [#507](https://github.com/stevearc/oil.nvim/issues/507) | not actionable | lacasitos.nvim conflict on Windows — cross-plugin + Windows-only, no actionable fix | -| [#521](https://github.com/stevearc/oil.nvim/issues/521) | open | oil-ssh connection issues | -| [#525](https://github.com/stevearc/oil.nvim/issues/525) | open | SSH adapter documentation (P2) | -| [#531](https://github.com/stevearc/oil.nvim/issues/531) | not actionable | Windows — incomplete drive letters (P1) | -| [#533](https://github.com/stevearc/oil.nvim/issues/533) | not actionable | `constrain_cursor` — needs repro | -| [#570](https://github.com/stevearc/oil.nvim/issues/570) | open | Improve c0/d0 for renaming | -| [#571](https://github.com/stevearc/oil.nvim/issues/571) | open | Callback before `highlight_filename` (P2) | -| [#578](https://github.com/stevearc/oil.nvim/issues/578) | resolved | Hidden file dimming recipe — [`38db6cf`](https://github.com/barrettruth/canola.nvim/commit/38db6cf) | -| [#587](https://github.com/stevearc/oil.nvim/issues/587) | not actionable | Alt+h keymap — user config issue | -| [#599](https://github.com/stevearc/oil.nvim/issues/599) | open | user:group display and manipulation (P2) | -| [#607](https://github.com/stevearc/oil.nvim/issues/607) | open | Per-host SCP args (P2) | -| [#609](https://github.com/stevearc/oil.nvim/issues/609) | open | Cursor placement via Snacks picker | -| [#612](https://github.com/stevearc/oil.nvim/issues/612) | fixed | Delete buffers on file delete — `cleanup_buffers_on_delete` option | -| [#615](https://github.com/stevearc/oil.nvim/issues/615) | fixed | Cursor at name column on o/O — [#72](https://github.com/barrettruth/canola.nvim/pull/72) ([`69d85b8`](https://github.com/barrettruth/canola.nvim/commit/69d85b8)) | -| [#617](https://github.com/stevearc/oil.nvim/issues/617) | open | Filetype by actual filetype (P2) | -| [#621](https://github.com/stevearc/oil.nvim/issues/621) | fixed | `toggle()` for regular windows — [#88](https://github.com/barrettruth/canola.nvim/pull/88) ([`385bd82`](https://github.com/barrettruth/canola.nvim/commit/385bd82)) | -| [#623](https://github.com/stevearc/oil.nvim/issues/623) | not actionable | bufferline.nvim interaction — cross-plugin | -| [#624](https://github.com/stevearc/oil.nvim/issues/624) | not actionable | Mutation race — no reliable repro | -| [#625](https://github.com/stevearc/oil.nvim/issues/625) | not actionable | E19 mark invalid line — intractable without neovim API changes | -| [#632](https://github.com/stevearc/oil.nvim/issues/632) | fixed | Preview + move = copy — [#12](https://github.com/barrettruth/canola.nvim/pull/12) ([`fe16993`](https://github.com/barrettruth/canola.nvim/commit/fe16993)) | -| [#636](https://github.com/stevearc/oil.nvim/issues/636) | open | Telescope picker opens in active buffer | -| [#637](https://github.com/stevearc/oil.nvim/issues/637) | open | Inconsistent symlink resolution | -| [#641](https://github.com/stevearc/oil.nvim/issues/641) | open | Flicker on `actions.parent` | -| [#642](https://github.com/stevearc/oil.nvim/issues/642) | fixed | W10 warning under `nvim -R` — [`ca834cf`](https://github.com/barrettruth/canola.nvim/commit/ca834cf) | -| [#645](https://github.com/stevearc/oil.nvim/issues/645) | resolved | `close_float` action — [`f6bcdda`](https://github.com/barrettruth/canola.nvim/commit/f6bcdda) | -| [#646](https://github.com/stevearc/oil.nvim/issues/646) | open | `get_current_dir` nil on SSH | -| [#650](https://github.com/stevearc/oil.nvim/issues/650) | resolved | LSP `workspace.fileOperations` events — implemented in `lua/canola/lsp/workspace.lua` | -| [#655](https://github.com/stevearc/oil.nvim/issues/655) | open | File statistics as virtual text | -| [#659](https://github.com/stevearc/oil.nvim/issues/659) | open | Mark and diff files in buffer | -| [#664](https://github.com/stevearc/oil.nvim/issues/664) | not actionable | Session reload extra buffer — no repro | -| [#665](https://github.com/stevearc/oil.nvim/issues/665) | open | Hot load preview fast-scratch buffers | -| [#668](https://github.com/stevearc/oil.nvim/issues/668) | open | Custom yes/no confirmation | -| [#670](https://github.com/stevearc/oil.nvim/issues/670) | fixed | Multi-directory cmdline — [#11](https://github.com/barrettruth/canola.nvim/pull/11) ([`70861e5`](https://github.com/barrettruth/canola.nvim/commit/70861e5)) | -| [#671](https://github.com/stevearc/oil.nvim/issues/671) | open | Yanking between nvim instances | -| [#673](https://github.com/stevearc/oil.nvim/issues/673) | fixed | Symlink newlines crash — [`9110a1a`](https://github.com/barrettruth/canola.nvim/commit/9110a1a) | -| [#675](https://github.com/stevearc/oil.nvim/issues/675) | open | Move file into folder by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#676](https://github.com/stevearc/oil.nvim/issues/676) | not actionable | Windows — path conversion | -| [#678](https://github.com/stevearc/oil.nvim/issues/678) | tracking | `buftype='acwrite'` causes `mksession` to skip oil windows | -| [#679](https://github.com/stevearc/oil.nvim/issues/679) | resolved | Executable file sign — PR [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#682](https://github.com/stevearc/oil.nvim/issues/682) | resolved | `get_current_dir()` nil — clarified via [`eed6697`](https://github.com/barrettruth/canola.nvim/commit/eed6697) (cherry-pick of [#727](https://github.com/stevearc/oil.nvim/pull/727)) | -| [#683](https://github.com/stevearc/oil.nvim/issues/683) | fixed | Path not shown in floating mode — title shown via fallback when border is nil | -| [#684](https://github.com/stevearc/oil.nvim/issues/684) | open | User and group columns | -| [#685](https://github.com/stevearc/oil.nvim/issues/685) | open | Plain directory paths in buffer names | -| [#690](https://github.com/stevearc/oil.nvim/issues/690) | resolved | `OilFileIcon` highlight group — [`ce64ae1`](https://github.com/barrettruth/canola.nvim/commit/ce64ae1) | -| [#692](https://github.com/stevearc/oil.nvim/issues/692) | resolved | Keymap normalization — PR [#725](https://github.com/stevearc/oil.nvim/pull/725) | -| [#699](https://github.com/stevearc/oil.nvim/issues/699) | open | `select` blocks UI with slow FileType autocmd | -| [#707](https://github.com/stevearc/oil.nvim/issues/707) | open | Move file/dir into new dir by renaming (related to [#708](https://github.com/stevearc/oil.nvim/pull/708)) | -| [#710](https://github.com/stevearc/oil.nvim/issues/710) | fixed | buftype empty on BufEnter — [#10](https://github.com/barrettruth/canola.nvim/pull/10) ([`01b860e`](https://github.com/barrettruth/canola.nvim/commit/01b860e)) | -| [#714](https://github.com/stevearc/oil.nvim/issues/714) | not actionable | Support question — answered | -| [#719](https://github.com/stevearc/oil.nvim/issues/719) | not actionable | Neovim crash on node_modules — libuv/neovim bug | -| [#726](https://github.com/stevearc/oil.nvim/issues/726) | not actionable | Meta discussion/roadmap | -| [#736](https://github.com/stevearc/oil.nvim/issues/736) | open | Make icons virtual text — related to [#667](https://github.com/stevearc/oil.nvim/pull/667) (virtual text columns, deferred) | -| [#738](https://github.com/stevearc/oil.nvim/issues/738) | open | Allow changing mtime/atime via time column (P2) | +| Issue | Description | +|-------|-------------| +| [#85](https://github.com/stevearc/oil.nvim/issues/85) | Git status column | +| [#95](https://github.com/stevearc/oil.nvim/issues/95) | Undo after renaming files | +| [#117](https://github.com/stevearc/oil.nvim/issues/117) | Move file into new dir via slash in name | +| [#156](https://github.com/stevearc/oil.nvim/issues/156) | Paste path of files into oil buffer | +| [#200](https://github.com/stevearc/oil.nvim/issues/200) | Highlights not working when opening a file | +| [#207](https://github.com/stevearc/oil.nvim/issues/207) | Suppress "no longer available" message | +| [#210](https://github.com/stevearc/oil.nvim/issues/210) | FTP support | +| [#226](https://github.com/stevearc/oil.nvim/issues/226) | K8s/Docker adapter | +| [#232](https://github.com/stevearc/oil.nvim/issues/232) | Cannot close last window | +| [#254](https://github.com/stevearc/oil.nvim/issues/254) | Buffer modified highlight group | +| [#263](https://github.com/stevearc/oil.nvim/issues/263) | Diff mode | +| [#276](https://github.com/stevearc/oil.nvim/issues/276) | Archives manipulation | +| [#280](https://github.com/stevearc/oil.nvim/issues/280) | vim-projectionist support | +| [#289](https://github.com/stevearc/oil.nvim/issues/289) | Show absolute path toggle | +| [#294](https://github.com/stevearc/oil.nvim/issues/294) | Can't handle emojis in filenames | +| [#298](https://github.com/stevearc/oil.nvim/issues/298) | Open float on neovim directory startup | +| [#303](https://github.com/stevearc/oil.nvim/issues/303) | Preview in float window mode | +| [#325](https://github.com/stevearc/oil.nvim/issues/325) | oil-ssh error from command line | +| [#332](https://github.com/stevearc/oil.nvim/issues/332) | Buffer not fixed to floating window | +| [#335](https://github.com/stevearc/oil.nvim/issues/335) | Disable editing outside root dir | +| [#349](https://github.com/stevearc/oil.nvim/issues/349) | Parent directory as column/vsplit | +| [#351](https://github.com/stevearc/oil.nvim/issues/351) | Paste deleted file from register | +| [#359](https://github.com/stevearc/oil.nvim/issues/359) | Parse error on filenames differing by space | +| [#360](https://github.com/stevearc/oil.nvim/issues/360) | Pick window to open file into | +| [#371](https://github.com/stevearc/oil.nvim/issues/371) | Constrain cursor in insert mode | +| [#373](https://github.com/stevearc/oil.nvim/issues/373) | Dir from quickfix with bqf/trouble broken | +| [#375](https://github.com/stevearc/oil.nvim/issues/375) | Highlights for file types and permissions | +| [#382](https://github.com/stevearc/oil.nvim/issues/382) | Relative path in window title | +| [#396](https://github.com/stevearc/oil.nvim/issues/396) | Customize preview content | +| [#399](https://github.com/stevearc/oil.nvim/issues/399) | Open file without closing Oil | +| [#416](https://github.com/stevearc/oil.nvim/issues/416) | Cannot remap key to open split | +| [#431](https://github.com/stevearc/oil.nvim/issues/431) | More SSH adapter documentation | +| [#435](https://github.com/stevearc/oil.nvim/issues/435) | Error previewing with semantic tokens LSP | +| [#436](https://github.com/stevearc/oil.nvim/issues/436) | Owner and group columns | +| [#444](https://github.com/stevearc/oil.nvim/issues/444) | Opening behaviour customization | +| [#449](https://github.com/stevearc/oil.nvim/issues/449) | Renaming TypeScript files stopped working | +| [#450](https://github.com/stevearc/oil.nvim/issues/450) | Highlight opened file in directory listing | +| [#457](https://github.com/stevearc/oil.nvim/issues/457) | Custom column API | +| [#466](https://github.com/stevearc/oil.nvim/issues/466) | Select into window on right | +| [#479](https://github.com/stevearc/oil.nvim/issues/479) | Harpoon integration recipe | +| [#521](https://github.com/stevearc/oil.nvim/issues/521) | oil-ssh connection issues | +| [#525](https://github.com/stevearc/oil.nvim/issues/525) | SSH adapter documentation | +| [#570](https://github.com/stevearc/oil.nvim/issues/570) | Improve c0/d0 for renaming | +| [#571](https://github.com/stevearc/oil.nvim/issues/571) | Callback before `highlight_filename` | +| [#599](https://github.com/stevearc/oil.nvim/issues/599) | user:group display and manipulation | +| [#607](https://github.com/stevearc/oil.nvim/issues/607) | Per-host SCP args | +| [#609](https://github.com/stevearc/oil.nvim/issues/609) | Cursor placement via Snacks picker | +| [#617](https://github.com/stevearc/oil.nvim/issues/617) | Filetype by actual filetype | +| [#636](https://github.com/stevearc/oil.nvim/issues/636) | Telescope picker opens in active buffer | +| [#637](https://github.com/stevearc/oil.nvim/issues/637) | Inconsistent symlink resolution | +| [#641](https://github.com/stevearc/oil.nvim/issues/641) | Flicker on `actions.parent` | +| [#646](https://github.com/stevearc/oil.nvim/issues/646) | `get_current_dir` nil on SSH | +| [#655](https://github.com/stevearc/oil.nvim/issues/655) | File statistics as virtual text | +| [#659](https://github.com/stevearc/oil.nvim/issues/659) | Mark and diff files in buffer | +| [#665](https://github.com/stevearc/oil.nvim/issues/665) | Hot load preview fast-scratch buffers | +| [#668](https://github.com/stevearc/oil.nvim/issues/668) | Custom yes/no confirmation | +| [#671](https://github.com/stevearc/oil.nvim/issues/671) | Yanking between nvim instances | +| [#675](https://github.com/stevearc/oil.nvim/issues/675) | Move file into folder by renaming | +| [#678](https://github.com/stevearc/oil.nvim/issues/678) | `buftype='acwrite'` causes `mksession` to skip oil windows | +| [#684](https://github.com/stevearc/oil.nvim/issues/684) | User and group columns | +| [#685](https://github.com/stevearc/oil.nvim/issues/685) | Plain directory paths in buffer names | +| [#699](https://github.com/stevearc/oil.nvim/issues/699) | `select` blocks UI with slow FileType autocmd | +| [#707](https://github.com/stevearc/oil.nvim/issues/707) | Move file/dir into new dir by renaming | +| [#736](https://github.com/stevearc/oil.nvim/issues/736) | Make icons virtual text | +| [#738](https://github.com/stevearc/oil.nvim/issues/738) | Allow changing mtime/atime via time column | + +## Issues — not actionable + +| Issue | Reason | +|-------|--------| +| [#288](https://github.com/stevearc/oil.nvim/issues/288) | No reliable repro; likely lazy.nvim timing | +| [#330](https://github.com/stevearc/oil.nvim/issues/330) | Telescope opens file in oil float — cross-plugin, no repro | +| [#362](https://github.com/stevearc/oil.nvim/issues/362) | No minimal repro, old nvim version (0.9.5) | +| [#380](https://github.com/stevearc/oil.nvim/issues/380) | Silently overriding `show_hidden` counter to config intent | +| [#404](https://github.com/stevearc/oil.nvim/issues/404) | Windows-only | +| [#483](https://github.com/stevearc/oil.nvim/issues/483) | Spell downloads depend on netrw — fixed in neovim#34940 | +| [#492](https://github.com/stevearc/oil.nvim/issues/492) | j/k remapping question — answered | +| [#507](https://github.com/stevearc/oil.nvim/issues/507) | lacasitos.nvim conflict — cross-plugin + Windows-only | +| [#531](https://github.com/stevearc/oil.nvim/issues/531) | Windows — incomplete drive letters | +| [#533](https://github.com/stevearc/oil.nvim/issues/533) | `constrain_cursor` — needs repro | +| [#587](https://github.com/stevearc/oil.nvim/issues/587) | Alt+h keymap — user config issue | +| [#623](https://github.com/stevearc/oil.nvim/issues/623) | bufferline.nvim interaction — cross-plugin | +| [#624](https://github.com/stevearc/oil.nvim/issues/624) | Mutation race — no reliable repro | +| [#625](https://github.com/stevearc/oil.nvim/issues/625) | E19 mark invalid line — intractable without neovim API changes | +| [#664](https://github.com/stevearc/oil.nvim/issues/664) | Session reload extra buffer — no repro | +| [#676](https://github.com/stevearc/oil.nvim/issues/676) | Windows — path conversion | +| [#714](https://github.com/stevearc/oil.nvim/issues/714) | Support question — answered | +| [#719](https://github.com/stevearc/oil.nvim/issues/719) | Neovim crash on node_modules — libuv/neovim bug | +| [#726](https://github.com/stevearc/oil.nvim/issues/726) | Meta discussion/roadmap | From 0424ab3e65cc0669fe267fb9cd741c663b151db8 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 8 Mar 2026 15:44:32 -0400 Subject: [PATCH 72/77] fix(ci): update digest script for reorganized upstream tracker (#90) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: the upstream digest script referenced old section headings (`## Open upstream PRs`, `## Upstream issues`) and a 3-column issue row format that no longer exist after the tracker reorganization. Solution: update headings to `## Upstream PRs` and `## Issues — open`, and change issue row format to the new 2-column layout. --- .github/scripts/upstream_digest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/scripts/upstream_digest.py b/.github/scripts/upstream_digest.py index 2f0e949..72cb02e 100644 --- a/.github/scripts/upstream_digest.py +++ b/.github/scripts/upstream_digest.py @@ -10,8 +10,8 @@ from datetime import date, timedelta UPSTREAM = "stevearc/oil.nvim" UPSTREAM_MD = "doc/upstream.md" -PRS_HEADING = "## Open upstream PRs" -ISSUES_HEADING = "## Upstream issues" +PRS_HEADING = "## Upstream PRs" +ISSUES_HEADING = "## Issues — open" def get_last_tracked_number(): @@ -128,7 +128,7 @@ def main(): issue_rows = [] for issue in open_issues: issue_rows.append( - f"| [#{issue['number']}]({issue['url']}) | open | {issue['title']} |" + f"| [#{issue['number']}]({issue['url']}) | {issue['title']} |" ) if pr_rows: From ac48ce20f5b3f8e687d6816e4fa6fb14038aa2d3 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 8 Mar 2026 15:52:25 -0400 Subject: [PATCH 73/77] docs(upstream): collapse issue sections into single table (#91) Problem: issues were split across four separate sections by status, requiring moves between sections on every status change. Solution: merge all issues into one `## Issues` table sorted by number with an inline status column. Update digest script heading and row format to match. --- .github/scripts/upstream_digest.py | 4 +- doc/upstream.md | 241 +++++++++++++---------------- 2 files changed, 113 insertions(+), 132 deletions(-) diff --git a/.github/scripts/upstream_digest.py b/.github/scripts/upstream_digest.py index 72cb02e..fc0ae71 100644 --- a/.github/scripts/upstream_digest.py +++ b/.github/scripts/upstream_digest.py @@ -11,7 +11,7 @@ UPSTREAM = "stevearc/oil.nvim" UPSTREAM_MD = "doc/upstream.md" PRS_HEADING = "## Upstream PRs" -ISSUES_HEADING = "## Issues — open" +ISSUES_HEADING = "## Issues" def get_last_tracked_number(): @@ -128,7 +128,7 @@ def main(): issue_rows = [] for issue in open_issues: issue_rows.append( - f"| [#{issue['number']}]({issue['url']}) | {issue['title']} |" + f"| [#{issue['number']}]({issue['url']}) | {issue['title']} | open |" ) if pr_rows: diff --git a/doc/upstream.md b/doc/upstream.md index 8aa9b27..3ef3378 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -30,134 +30,115 @@ issues against this fork. | [#721](https://github.com/stevearc/oil.nvim/pull/721) | `create_hook` to populate file contents | deferred — fixing via autocmd event | | [#728](https://github.com/stevearc/oil.nvim/pull/728) | `open_split` for opening oil in a split | deferred — tracked as [#2](https://github.com/barrettruth/canola.nvim/issues/2) | -## Issues — fixed (original) +## Issues -Issues fixed in this fork that remain open upstream. - -| Issue | Description | PR | -|-------|-------------|----| -| [#213](https://github.com/stevearc/oil.nvim/issues/213) | Disable preview for large files | [#85](https://github.com/barrettruth/canola.nvim/pull/85) | -| [#302](https://github.com/stevearc/oil.nvim/issues/302) | `buflisted=true` after jumplist nav | [#71](https://github.com/barrettruth/canola.nvim/pull/71) | -| [#363](https://github.com/stevearc/oil.nvim/issues/363) | `prompt_save_on_select_new_entry` wrong prompt | — | -| [#392](https://github.com/stevearc/oil.nvim/issues/392) | Option to skip delete prompt | — | -| [#393](https://github.com/stevearc/oil.nvim/issues/393) | Auto-save on select | — | -| [#473](https://github.com/stevearc/oil.nvim/issues/473) | Show hidden when dir is all-hidden | [#85](https://github.com/barrettruth/canola.nvim/pull/85) | -| [#486](https://github.com/stevearc/oil.nvim/issues/486) | Directory sizes show misleading 4.1k | [#87](https://github.com/barrettruth/canola.nvim/pull/87) | -| [#578](https://github.com/stevearc/oil.nvim/issues/578) | Hidden file dimming recipe | — | -| [#612](https://github.com/stevearc/oil.nvim/issues/612) | Delete buffers on file delete | — | -| [#615](https://github.com/stevearc/oil.nvim/issues/615) | Cursor at name column on o/O | [#72](https://github.com/barrettruth/canola.nvim/pull/72) | -| [#621](https://github.com/stevearc/oil.nvim/issues/621) | `toggle()` for regular windows | [#88](https://github.com/barrettruth/canola.nvim/pull/88) | -| [#632](https://github.com/stevearc/oil.nvim/issues/632) | Preview + move = copy | [#12](https://github.com/barrettruth/canola.nvim/pull/12) | -| [#642](https://github.com/stevearc/oil.nvim/issues/642) | W10 warning under `nvim -R` | — | -| [#645](https://github.com/stevearc/oil.nvim/issues/645) | `close_float` action | — | -| [#650](https://github.com/stevearc/oil.nvim/issues/650) | LSP `workspace.fileOperations` events | — | -| [#670](https://github.com/stevearc/oil.nvim/issues/670) | Multi-directory cmdline args ignored | [#11](https://github.com/barrettruth/canola.nvim/pull/11) | -| [#673](https://github.com/stevearc/oil.nvim/issues/673) | Symlink newlines crash | — | -| [#683](https://github.com/stevearc/oil.nvim/issues/683) | Path not shown in floating mode | — | -| [#690](https://github.com/stevearc/oil.nvim/issues/690) | `OilFileIcon` highlight group | — | -| [#710](https://github.com/stevearc/oil.nvim/issues/710) | buftype empty on BufEnter | [#10](https://github.com/barrettruth/canola.nvim/pull/10) | - -## Issues — resolved (cherry-pick) - -Issues addressed by cherry-picking upstream PRs. - -| Issue | Description | Upstream PR | -|-------|-------------|-------------| -| [#446](https://github.com/stevearc/oil.nvim/issues/446) | Executable highlighting | [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#679](https://github.com/stevearc/oil.nvim/issues/679) | Executable file sign | [#698](https://github.com/stevearc/oil.nvim/pull/698) | -| [#682](https://github.com/stevearc/oil.nvim/issues/682) | `get_current_dir()` nil | [#727](https://github.com/stevearc/oil.nvim/pull/727) | -| [#692](https://github.com/stevearc/oil.nvim/issues/692) | Keymap normalization | [#725](https://github.com/stevearc/oil.nvim/pull/725) | - -## Issues — open - -| Issue | Description | -|-------|-------------| -| [#85](https://github.com/stevearc/oil.nvim/issues/85) | Git status column | -| [#95](https://github.com/stevearc/oil.nvim/issues/95) | Undo after renaming files | -| [#117](https://github.com/stevearc/oil.nvim/issues/117) | Move file into new dir via slash in name | -| [#156](https://github.com/stevearc/oil.nvim/issues/156) | Paste path of files into oil buffer | -| [#200](https://github.com/stevearc/oil.nvim/issues/200) | Highlights not working when opening a file | -| [#207](https://github.com/stevearc/oil.nvim/issues/207) | Suppress "no longer available" message | -| [#210](https://github.com/stevearc/oil.nvim/issues/210) | FTP support | -| [#226](https://github.com/stevearc/oil.nvim/issues/226) | K8s/Docker adapter | -| [#232](https://github.com/stevearc/oil.nvim/issues/232) | Cannot close last window | -| [#254](https://github.com/stevearc/oil.nvim/issues/254) | Buffer modified highlight group | -| [#263](https://github.com/stevearc/oil.nvim/issues/263) | Diff mode | -| [#276](https://github.com/stevearc/oil.nvim/issues/276) | Archives manipulation | -| [#280](https://github.com/stevearc/oil.nvim/issues/280) | vim-projectionist support | -| [#289](https://github.com/stevearc/oil.nvim/issues/289) | Show absolute path toggle | -| [#294](https://github.com/stevearc/oil.nvim/issues/294) | Can't handle emojis in filenames | -| [#298](https://github.com/stevearc/oil.nvim/issues/298) | Open float on neovim directory startup | -| [#303](https://github.com/stevearc/oil.nvim/issues/303) | Preview in float window mode | -| [#325](https://github.com/stevearc/oil.nvim/issues/325) | oil-ssh error from command line | -| [#332](https://github.com/stevearc/oil.nvim/issues/332) | Buffer not fixed to floating window | -| [#335](https://github.com/stevearc/oil.nvim/issues/335) | Disable editing outside root dir | -| [#349](https://github.com/stevearc/oil.nvim/issues/349) | Parent directory as column/vsplit | -| [#351](https://github.com/stevearc/oil.nvim/issues/351) | Paste deleted file from register | -| [#359](https://github.com/stevearc/oil.nvim/issues/359) | Parse error on filenames differing by space | -| [#360](https://github.com/stevearc/oil.nvim/issues/360) | Pick window to open file into | -| [#371](https://github.com/stevearc/oil.nvim/issues/371) | Constrain cursor in insert mode | -| [#373](https://github.com/stevearc/oil.nvim/issues/373) | Dir from quickfix with bqf/trouble broken | -| [#375](https://github.com/stevearc/oil.nvim/issues/375) | Highlights for file types and permissions | -| [#382](https://github.com/stevearc/oil.nvim/issues/382) | Relative path in window title | -| [#396](https://github.com/stevearc/oil.nvim/issues/396) | Customize preview content | -| [#399](https://github.com/stevearc/oil.nvim/issues/399) | Open file without closing Oil | -| [#416](https://github.com/stevearc/oil.nvim/issues/416) | Cannot remap key to open split | -| [#431](https://github.com/stevearc/oil.nvim/issues/431) | More SSH adapter documentation | -| [#435](https://github.com/stevearc/oil.nvim/issues/435) | Error previewing with semantic tokens LSP | -| [#436](https://github.com/stevearc/oil.nvim/issues/436) | Owner and group columns | -| [#444](https://github.com/stevearc/oil.nvim/issues/444) | Opening behaviour customization | -| [#449](https://github.com/stevearc/oil.nvim/issues/449) | Renaming TypeScript files stopped working | -| [#450](https://github.com/stevearc/oil.nvim/issues/450) | Highlight opened file in directory listing | -| [#457](https://github.com/stevearc/oil.nvim/issues/457) | Custom column API | -| [#466](https://github.com/stevearc/oil.nvim/issues/466) | Select into window on right | -| [#479](https://github.com/stevearc/oil.nvim/issues/479) | Harpoon integration recipe | -| [#521](https://github.com/stevearc/oil.nvim/issues/521) | oil-ssh connection issues | -| [#525](https://github.com/stevearc/oil.nvim/issues/525) | SSH adapter documentation | -| [#570](https://github.com/stevearc/oil.nvim/issues/570) | Improve c0/d0 for renaming | -| [#571](https://github.com/stevearc/oil.nvim/issues/571) | Callback before `highlight_filename` | -| [#599](https://github.com/stevearc/oil.nvim/issues/599) | user:group display and manipulation | -| [#607](https://github.com/stevearc/oil.nvim/issues/607) | Per-host SCP args | -| [#609](https://github.com/stevearc/oil.nvim/issues/609) | Cursor placement via Snacks picker | -| [#617](https://github.com/stevearc/oil.nvim/issues/617) | Filetype by actual filetype | -| [#636](https://github.com/stevearc/oil.nvim/issues/636) | Telescope picker opens in active buffer | -| [#637](https://github.com/stevearc/oil.nvim/issues/637) | Inconsistent symlink resolution | -| [#641](https://github.com/stevearc/oil.nvim/issues/641) | Flicker on `actions.parent` | -| [#646](https://github.com/stevearc/oil.nvim/issues/646) | `get_current_dir` nil on SSH | -| [#655](https://github.com/stevearc/oil.nvim/issues/655) | File statistics as virtual text | -| [#659](https://github.com/stevearc/oil.nvim/issues/659) | Mark and diff files in buffer | -| [#665](https://github.com/stevearc/oil.nvim/issues/665) | Hot load preview fast-scratch buffers | -| [#668](https://github.com/stevearc/oil.nvim/issues/668) | Custom yes/no confirmation | -| [#671](https://github.com/stevearc/oil.nvim/issues/671) | Yanking between nvim instances | -| [#675](https://github.com/stevearc/oil.nvim/issues/675) | Move file into folder by renaming | -| [#678](https://github.com/stevearc/oil.nvim/issues/678) | `buftype='acwrite'` causes `mksession` to skip oil windows | -| [#684](https://github.com/stevearc/oil.nvim/issues/684) | User and group columns | -| [#685](https://github.com/stevearc/oil.nvim/issues/685) | Plain directory paths in buffer names | -| [#699](https://github.com/stevearc/oil.nvim/issues/699) | `select` blocks UI with slow FileType autocmd | -| [#707](https://github.com/stevearc/oil.nvim/issues/707) | Move file/dir into new dir by renaming | -| [#736](https://github.com/stevearc/oil.nvim/issues/736) | Make icons virtual text | -| [#738](https://github.com/stevearc/oil.nvim/issues/738) | Allow changing mtime/atime via time column | - -## Issues — not actionable - -| Issue | Reason | -|-------|--------| -| [#288](https://github.com/stevearc/oil.nvim/issues/288) | No reliable repro; likely lazy.nvim timing | -| [#330](https://github.com/stevearc/oil.nvim/issues/330) | Telescope opens file in oil float — cross-plugin, no repro | -| [#362](https://github.com/stevearc/oil.nvim/issues/362) | No minimal repro, old nvim version (0.9.5) | -| [#380](https://github.com/stevearc/oil.nvim/issues/380) | Silently overriding `show_hidden` counter to config intent | -| [#404](https://github.com/stevearc/oil.nvim/issues/404) | Windows-only | -| [#483](https://github.com/stevearc/oil.nvim/issues/483) | Spell downloads depend on netrw — fixed in neovim#34940 | -| [#492](https://github.com/stevearc/oil.nvim/issues/492) | j/k remapping question — answered | -| [#507](https://github.com/stevearc/oil.nvim/issues/507) | lacasitos.nvim conflict — cross-plugin + Windows-only | -| [#531](https://github.com/stevearc/oil.nvim/issues/531) | Windows — incomplete drive letters | -| [#533](https://github.com/stevearc/oil.nvim/issues/533) | `constrain_cursor` — needs repro | -| [#587](https://github.com/stevearc/oil.nvim/issues/587) | Alt+h keymap — user config issue | -| [#623](https://github.com/stevearc/oil.nvim/issues/623) | bufferline.nvim interaction — cross-plugin | -| [#624](https://github.com/stevearc/oil.nvim/issues/624) | Mutation race — no reliable repro | -| [#625](https://github.com/stevearc/oil.nvim/issues/625) | E19 mark invalid line — intractable without neovim API changes | -| [#664](https://github.com/stevearc/oil.nvim/issues/664) | Session reload extra buffer — no repro | -| [#676](https://github.com/stevearc/oil.nvim/issues/676) | Windows — path conversion | -| [#714](https://github.com/stevearc/oil.nvim/issues/714) | Support question — answered | -| [#719](https://github.com/stevearc/oil.nvim/issues/719) | Neovim crash on node_modules — libuv/neovim bug | -| [#726](https://github.com/stevearc/oil.nvim/issues/726) | Meta discussion/roadmap | +| Issue | Description | Status | +|-------|-------------|--------| +| [#85](https://github.com/stevearc/oil.nvim/issues/85) | Git status column | open | +| [#95](https://github.com/stevearc/oil.nvim/issues/95) | Undo after renaming files | open | +| [#117](https://github.com/stevearc/oil.nvim/issues/117) | Move file into new dir via slash in name | open | +| [#156](https://github.com/stevearc/oil.nvim/issues/156) | Paste path of files into oil buffer | open | +| [#200](https://github.com/stevearc/oil.nvim/issues/200) | Highlights not working when opening a file | open | +| [#207](https://github.com/stevearc/oil.nvim/issues/207) | Suppress "no longer available" message | open | +| [#210](https://github.com/stevearc/oil.nvim/issues/210) | FTP support | open | +| [#213](https://github.com/stevearc/oil.nvim/issues/213) | Disable preview for large files | fixed ([#85](https://github.com/barrettruth/canola.nvim/pull/85)) | +| [#226](https://github.com/stevearc/oil.nvim/issues/226) | K8s/Docker adapter | open | +| [#232](https://github.com/stevearc/oil.nvim/issues/232) | Cannot close last window | open | +| [#254](https://github.com/stevearc/oil.nvim/issues/254) | Buffer modified highlight group | open | +| [#263](https://github.com/stevearc/oil.nvim/issues/263) | Diff mode | open | +| [#276](https://github.com/stevearc/oil.nvim/issues/276) | Archives manipulation | open | +| [#280](https://github.com/stevearc/oil.nvim/issues/280) | vim-projectionist support | open | +| [#288](https://github.com/stevearc/oil.nvim/issues/288) | No reliable repro; likely lazy.nvim timing | not actionable | +| [#289](https://github.com/stevearc/oil.nvim/issues/289) | Show absolute path toggle | open | +| [#294](https://github.com/stevearc/oil.nvim/issues/294) | Can't handle emojis in filenames | open | +| [#298](https://github.com/stevearc/oil.nvim/issues/298) | Open float on neovim directory startup | open | +| [#302](https://github.com/stevearc/oil.nvim/issues/302) | `buflisted=true` after jumplist nav | fixed ([#71](https://github.com/barrettruth/canola.nvim/pull/71)) | +| [#303](https://github.com/stevearc/oil.nvim/issues/303) | Preview in float window mode | open | +| [#325](https://github.com/stevearc/oil.nvim/issues/325) | oil-ssh error from command line | open | +| [#330](https://github.com/stevearc/oil.nvim/issues/330) | Telescope opens file in oil float | not actionable — cross-plugin, no repro | +| [#332](https://github.com/stevearc/oil.nvim/issues/332) | Buffer not fixed to floating window | open | +| [#335](https://github.com/stevearc/oil.nvim/issues/335) | Disable editing outside root dir | open | +| [#349](https://github.com/stevearc/oil.nvim/issues/349) | Parent directory as column/vsplit | open | +| [#351](https://github.com/stevearc/oil.nvim/issues/351) | Paste deleted file from register | open | +| [#359](https://github.com/stevearc/oil.nvim/issues/359) | Parse error on filenames differing by space | open | +| [#360](https://github.com/stevearc/oil.nvim/issues/360) | Pick window to open file into | open | +| [#362](https://github.com/stevearc/oil.nvim/issues/362) | "Could not find oil adapter for scheme" | not actionable — no repro, old nvim (0.9.5) | +| [#363](https://github.com/stevearc/oil.nvim/issues/363) | `prompt_save_on_select_new_entry` wrong prompt | fixed | +| [#371](https://github.com/stevearc/oil.nvim/issues/371) | Constrain cursor in insert mode | open | +| [#373](https://github.com/stevearc/oil.nvim/issues/373) | Dir from quickfix with bqf/trouble broken | open | +| [#375](https://github.com/stevearc/oil.nvim/issues/375) | Highlights for file types and permissions | open | +| [#380](https://github.com/stevearc/oil.nvim/issues/380) | Silently overriding `show_hidden` | not actionable — counter to config intent | +| [#382](https://github.com/stevearc/oil.nvim/issues/382) | Relative path in window title | open | +| [#392](https://github.com/stevearc/oil.nvim/issues/392) | Option to skip delete prompt | fixed | +| [#393](https://github.com/stevearc/oil.nvim/issues/393) | Auto-save on select | fixed | +| [#396](https://github.com/stevearc/oil.nvim/issues/396) | Customize preview content | open | +| [#399](https://github.com/stevearc/oil.nvim/issues/399) | Open file without closing Oil | open | +| [#404](https://github.com/stevearc/oil.nvim/issues/404) | Restricted UNC paths | not actionable — Windows-only | +| [#416](https://github.com/stevearc/oil.nvim/issues/416) | Cannot remap key to open split | open | +| [#431](https://github.com/stevearc/oil.nvim/issues/431) | More SSH adapter documentation | open | +| [#435](https://github.com/stevearc/oil.nvim/issues/435) | Error previewing with semantic tokens LSP | open | +| [#436](https://github.com/stevearc/oil.nvim/issues/436) | Owner and group columns | open | +| [#444](https://github.com/stevearc/oil.nvim/issues/444) | Opening behaviour customization | open | +| [#446](https://github.com/stevearc/oil.nvim/issues/446) | Executable highlighting | cherry-picked ([#698](https://github.com/stevearc/oil.nvim/pull/698)) | +| [#449](https://github.com/stevearc/oil.nvim/issues/449) | Renaming TypeScript files stopped working | open | +| [#450](https://github.com/stevearc/oil.nvim/issues/450) | Highlight opened file in directory listing | open | +| [#457](https://github.com/stevearc/oil.nvim/issues/457) | Custom column API | open | +| [#466](https://github.com/stevearc/oil.nvim/issues/466) | Select into window on right | open | +| [#473](https://github.com/stevearc/oil.nvim/issues/473) | Show hidden when dir is all-hidden | fixed ([#85](https://github.com/barrettruth/canola.nvim/pull/85)) | +| [#479](https://github.com/stevearc/oil.nvim/issues/479) | Harpoon integration recipe | open | +| [#483](https://github.com/stevearc/oil.nvim/issues/483) | Spell downloads depend on netrw | not actionable — fixed in neovim#34940 | +| [#486](https://github.com/stevearc/oil.nvim/issues/486) | Directory sizes show misleading 4.1k | fixed ([#87](https://github.com/barrettruth/canola.nvim/pull/87)) | +| [#492](https://github.com/stevearc/oil.nvim/issues/492) | j/k remapping question | not actionable — answered | +| [#507](https://github.com/stevearc/oil.nvim/issues/507) | lacasitos.nvim conflict | not actionable — cross-plugin + Windows-only | +| [#521](https://github.com/stevearc/oil.nvim/issues/521) | oil-ssh connection issues | open | +| [#525](https://github.com/stevearc/oil.nvim/issues/525) | SSH adapter documentation | open | +| [#531](https://github.com/stevearc/oil.nvim/issues/531) | Incomplete drive letters | not actionable — Windows-only | +| [#533](https://github.com/stevearc/oil.nvim/issues/533) | `constrain_cursor` bug | not actionable — needs repro | +| [#570](https://github.com/stevearc/oil.nvim/issues/570) | Improve c0/d0 for renaming | open | +| [#571](https://github.com/stevearc/oil.nvim/issues/571) | Callback before `highlight_filename` | open | +| [#578](https://github.com/stevearc/oil.nvim/issues/578) | Hidden file dimming recipe | fixed | +| [#587](https://github.com/stevearc/oil.nvim/issues/587) | Alt+h keymap | not actionable — user config issue | +| [#599](https://github.com/stevearc/oil.nvim/issues/599) | user:group display and manipulation | open | +| [#607](https://github.com/stevearc/oil.nvim/issues/607) | Per-host SCP args | open | +| [#609](https://github.com/stevearc/oil.nvim/issues/609) | Cursor placement via Snacks picker | open | +| [#612](https://github.com/stevearc/oil.nvim/issues/612) | Delete buffers on file delete | fixed | +| [#615](https://github.com/stevearc/oil.nvim/issues/615) | Cursor at name column on o/O | fixed ([#72](https://github.com/barrettruth/canola.nvim/pull/72)) | +| [#617](https://github.com/stevearc/oil.nvim/issues/617) | Filetype by actual filetype | open | +| [#621](https://github.com/stevearc/oil.nvim/issues/621) | `toggle()` for regular windows | fixed ([#88](https://github.com/barrettruth/canola.nvim/pull/88)) | +| [#623](https://github.com/stevearc/oil.nvim/issues/623) | bufferline.nvim interaction | not actionable — cross-plugin | +| [#624](https://github.com/stevearc/oil.nvim/issues/624) | Mutation race | not actionable — no reliable repro | +| [#625](https://github.com/stevearc/oil.nvim/issues/625) | E19 mark invalid line | not actionable — intractable without neovim API changes | +| [#632](https://github.com/stevearc/oil.nvim/issues/632) | Preview + move = copy | fixed ([#12](https://github.com/barrettruth/canola.nvim/pull/12)) | +| [#636](https://github.com/stevearc/oil.nvim/issues/636) | Telescope picker opens in active buffer | open | +| [#637](https://github.com/stevearc/oil.nvim/issues/637) | Inconsistent symlink resolution | open | +| [#641](https://github.com/stevearc/oil.nvim/issues/641) | Flicker on `actions.parent` | open | +| [#642](https://github.com/stevearc/oil.nvim/issues/642) | W10 warning under `nvim -R` | fixed | +| [#645](https://github.com/stevearc/oil.nvim/issues/645) | `close_float` action | fixed | +| [#646](https://github.com/stevearc/oil.nvim/issues/646) | `get_current_dir` nil on SSH | open | +| [#650](https://github.com/stevearc/oil.nvim/issues/650) | LSP `workspace.fileOperations` events | fixed | +| [#655](https://github.com/stevearc/oil.nvim/issues/655) | File statistics as virtual text | open | +| [#659](https://github.com/stevearc/oil.nvim/issues/659) | Mark and diff files in buffer | open | +| [#664](https://github.com/stevearc/oil.nvim/issues/664) | Session reload extra buffer | not actionable — no repro | +| [#665](https://github.com/stevearc/oil.nvim/issues/665) | Hot load preview fast-scratch buffers | open | +| [#668](https://github.com/stevearc/oil.nvim/issues/668) | Custom yes/no confirmation | open | +| [#670](https://github.com/stevearc/oil.nvim/issues/670) | Multi-directory cmdline args ignored | fixed ([#11](https://github.com/barrettruth/canola.nvim/pull/11)) | +| [#671](https://github.com/stevearc/oil.nvim/issues/671) | Yanking between nvim instances | open | +| [#673](https://github.com/stevearc/oil.nvim/issues/673) | Symlink newlines crash | fixed | +| [#675](https://github.com/stevearc/oil.nvim/issues/675) | Move file into folder by renaming | open | +| [#676](https://github.com/stevearc/oil.nvim/issues/676) | Windows path conversion | not actionable — Windows-only | +| [#678](https://github.com/stevearc/oil.nvim/issues/678) | `buftype='acwrite'` causes `mksession` to skip oil windows | open | +| [#679](https://github.com/stevearc/oil.nvim/issues/679) | Executable file sign | cherry-picked ([#698](https://github.com/stevearc/oil.nvim/pull/698)) | +| [#682](https://github.com/stevearc/oil.nvim/issues/682) | `get_current_dir()` nil | cherry-picked ([#727](https://github.com/stevearc/oil.nvim/pull/727)) | +| [#683](https://github.com/stevearc/oil.nvim/issues/683) | Path not shown in floating mode | fixed | +| [#684](https://github.com/stevearc/oil.nvim/issues/684) | User and group columns | open | +| [#685](https://github.com/stevearc/oil.nvim/issues/685) | Plain directory paths in buffer names | open | +| [#690](https://github.com/stevearc/oil.nvim/issues/690) | `OilFileIcon` highlight group | fixed | +| [#692](https://github.com/stevearc/oil.nvim/issues/692) | Keymap normalization | cherry-picked ([#725](https://github.com/stevearc/oil.nvim/pull/725)) | +| [#699](https://github.com/stevearc/oil.nvim/issues/699) | `select` blocks UI with slow FileType autocmd | open | +| [#707](https://github.com/stevearc/oil.nvim/issues/707) | Move file/dir into new dir by renaming | open | +| [#710](https://github.com/stevearc/oil.nvim/issues/710) | buftype empty on BufEnter | fixed ([#10](https://github.com/barrettruth/canola.nvim/pull/10)) | +| [#714](https://github.com/stevearc/oil.nvim/issues/714) | Support question | not actionable — answered | +| [#719](https://github.com/stevearc/oil.nvim/issues/719) | Neovim crash on node_modules | not actionable — libuv/neovim bug | +| [#726](https://github.com/stevearc/oil.nvim/issues/726) | Meta discussion/roadmap | not actionable | +| [#736](https://github.com/stevearc/oil.nvim/issues/736) | Make icons virtual text | open | +| [#738](https://github.com/stevearc/oil.nvim/issues/738) | Allow changing mtime/atime via time column | open | From c972bbe9c4aac8c2b680122457a469a0db863f1b Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 8 Mar 2026 16:00:31 -0400 Subject: [PATCH 74/77] docs(upstream): mark #359 not actionable (#92) --- doc/upstream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/upstream.md b/doc/upstream.md index 3ef3378..e0029dd 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -60,7 +60,7 @@ issues against this fork. | [#335](https://github.com/stevearc/oil.nvim/issues/335) | Disable editing outside root dir | open | | [#349](https://github.com/stevearc/oil.nvim/issues/349) | Parent directory as column/vsplit | open | | [#351](https://github.com/stevearc/oil.nvim/issues/351) | Paste deleted file from register | open | -| [#359](https://github.com/stevearc/oil.nvim/issues/359) | Parse error on filenames differing by space | open | +| [#359](https://github.com/stevearc/oil.nvim/issues/359) | Parse error on filenames differing by space | not actionable — parser uses whitespace as column delimiter | | [#360](https://github.com/stevearc/oil.nvim/issues/360) | Pick window to open file into | open | | [#362](https://github.com/stevearc/oil.nvim/issues/362) | "Could not find oil adapter for scheme" | not actionable — no repro, old nvim (0.9.5) | | [#363](https://github.com/stevearc/oil.nvim/issues/363) | `prompt_save_on_select_new_entry` wrong prompt | fixed | From 425a53d2fa5cc55aa7779de8e9466ae6f4763e79 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 8 Mar 2026 16:02:09 -0400 Subject: [PATCH 75/77] fix(view): constrain cursor in insert mode (#93) Problem: `constrain_cursor` only fired on `CursorMoved` and `ModeChanged`, so arrow key navigation in insert mode could move the cursor into the concealed ID prefix area. Solution: add `CursorMovedI` to the autocmd event list. The `constrain_cursor()` function is already mode-agnostic. --- doc/upstream.md | 2 +- lua/canola/view.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/upstream.md b/doc/upstream.md index e0029dd..197aa76 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -64,7 +64,7 @@ issues against this fork. | [#360](https://github.com/stevearc/oil.nvim/issues/360) | Pick window to open file into | open | | [#362](https://github.com/stevearc/oil.nvim/issues/362) | "Could not find oil adapter for scheme" | not actionable — no repro, old nvim (0.9.5) | | [#363](https://github.com/stevearc/oil.nvim/issues/363) | `prompt_save_on_select_new_entry` wrong prompt | fixed | -| [#371](https://github.com/stevearc/oil.nvim/issues/371) | Constrain cursor in insert mode | open | +| [#371](https://github.com/stevearc/oil.nvim/issues/371) | Constrain cursor in insert mode | fixed ([#93](https://github.com/barrettruth/canola.nvim/pull/93)) | | [#373](https://github.com/stevearc/oil.nvim/issues/373) | Dir from quickfix with bqf/trouble broken | open | | [#375](https://github.com/stevearc/oil.nvim/issues/375) | Highlights for file types and permissions | open | | [#380](https://github.com/stevearc/oil.nvim/issues/380) | Silently overriding `show_hidden` | not actionable — counter to config intent | diff --git a/lua/canola/view.lua b/lua/canola/view.lua index 7a7ac89..e74ca17 100644 --- a/lua/canola/view.lua +++ b/lua/canola/view.lua @@ -552,7 +552,7 @@ M.initialize = function(bufnr) end end, }) - vim.api.nvim_create_autocmd({ 'CursorMoved', 'ModeChanged' }, { + vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI', 'ModeChanged' }, { desc = 'Update canola preview window', group = 'Canola', buffer = bufnr, From 3249bbfaa793430690ed333859faab926fcb2833 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Sun, 8 Mar 2026 16:03:05 -0400 Subject: [PATCH 76/77] docs(upstream): mark #207 fixed (#94) --- doc/upstream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/upstream.md b/doc/upstream.md index 197aa76..d32e7e0 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -39,7 +39,7 @@ issues against this fork. | [#117](https://github.com/stevearc/oil.nvim/issues/117) | Move file into new dir via slash in name | open | | [#156](https://github.com/stevearc/oil.nvim/issues/156) | Paste path of files into oil buffer | open | | [#200](https://github.com/stevearc/oil.nvim/issues/200) | Highlights not working when opening a file | open | -| [#207](https://github.com/stevearc/oil.nvim/issues/207) | Suppress "no longer available" message | open | +| [#207](https://github.com/stevearc/oil.nvim/issues/207) | Suppress "no longer available" message | fixed — `cleanup_buffers_on_delete` option | | [#210](https://github.com/stevearc/oil.nvim/issues/210) | FTP support | open | | [#213](https://github.com/stevearc/oil.nvim/issues/213) | Disable preview for large files | fixed ([#85](https://github.com/barrettruth/canola.nvim/pull/85)) | | [#226](https://github.com/stevearc/oil.nvim/issues/226) | K8s/Docker adapter | open | From b79c77bafe12057babb0c23a60e151874fb63822 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 8 Mar 2026 18:57:48 -0400 Subject: [PATCH 77/77] docs(upstream): mark #226 not actionable --- doc/upstream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/upstream.md b/doc/upstream.md index d32e7e0..e9e375b 100644 --- a/doc/upstream.md +++ b/doc/upstream.md @@ -42,7 +42,7 @@ issues against this fork. | [#207](https://github.com/stevearc/oil.nvim/issues/207) | Suppress "no longer available" message | fixed — `cleanup_buffers_on_delete` option | | [#210](https://github.com/stevearc/oil.nvim/issues/210) | FTP support | open | | [#213](https://github.com/stevearc/oil.nvim/issues/213) | Disable preview for large files | fixed ([#85](https://github.com/barrettruth/canola.nvim/pull/85)) | -| [#226](https://github.com/stevearc/oil.nvim/issues/226) | K8s/Docker adapter | open | +| [#226](https://github.com/stevearc/oil.nvim/issues/226) | K8s/Docker adapter | not actionable — no demand | | [#232](https://github.com/stevearc/oil.nvim/issues/232) | Cannot close last window | open | | [#254](https://github.com/stevearc/oil.nvim/issues/254) | Buffer modified highlight group | open | | [#263](https://github.com/stevearc/oil.nvim/issues/263) | Diff mode | open |