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
* 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
* 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
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).
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`.
* 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
`<C-o>` and `<C-i>` 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
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.
* 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
* 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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
* 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
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.
* 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.