canola-collection: optional adapter backends as a separate plugin #31
Labels
No labels
autorelease: pending
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
upstream/digest
upstream/pr
wontfix
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
barrettruth/canola.nvim#31
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Introduce
barrettruth/canola-collection: a monorepo of optional adapters and extensions that live outside canola core.Motivation
Canola core currently bundles adapters for local files, SSH, S3, FTP/FTPS, and trash — plus a resession extension and git operation hooks. Most users only ever need the local filesystem adapter. Bundling everything bloats the install, loads code paths that never run, and makes core harder to reason about. The goal is a lean core with a rich, opt-in ecosystem.
What stays in core
filesadapter (oil://) — local filesystem via libuv. This is canola's raison d'être.testadapter (oil-test://) — in-memory mock filesystem used exclusively by the spec suite. Never shipped as a user-facing feature.git.lua— git operation hooks (git add/mv/rmon mutation). These fire synchronously inside the files adapter'sperform_actionand are tightly coupled to local filesystem mutations. Removing them would require a new hook API. Theconfig.git.{add,mv,rm}predicate functions remain as-is; they are not the same thing as git status display.Git status display (decorating buffer entries with their git status) is explicitly not in core. That belongs in
canola-gitin the collection.Adapter registration API
Core must expose a way for external adapters to register themselves. The current dispatch path is:
config.adaptersmaps URL scheme strings to adapter module name strings (e.g.['oil-ssh://'] = 'ssh').config.get_adapter_by_scheme(scheme)lazilyrequiresoil.adapters.<name>on first access.That path only works for adapters bundled inside core. External adapters need a public registration call:
Where
schemeis the full URL prefix (e.g.'canola-ssh://') andadapteris a table satisfying theoil.Adapterinterface. Calling this writes directly intoconfig._adapter_by_schemeso the scheme resolves without going through theoil.adapters.<name>require path.The
oil.AdapterinterfaceEvery adapter must implement:
namestringlistfun(path, column_defs, cb)cb(err?, entries?, fetch_more?)is_modifiablefun(bufnr): booleanget_columnfun(name): oil.ColumnDefinition?normalize_urlfun(url, cb)get_parentfun(bufname): stringget_entry_pathfun(url, entry, cb)render_actionfun(action): stringperform_actionfun(action, cb)read_filefun(bufnr)write_filefun(bufnr)supported_cross_adapter_actionstable<string, oil.CrossAdapterAction>"copy"or"move"filter_actionfun(action): booleanfilter_errorfun(action): booleanCross-adapter moves and copies require both adapters to declare the relationship via
supported_cross_adapter_actions. For example, the current ssh adapter declares{ files = 'copy' }, meaning it can copy to/from the files adapter.canola-collectionrepo structureEach subdirectory is an independently installable plugin with its own lazy.nvim spec, README, and test suite. A single CI workflow runs all test suites in the monorepo.
Plugins in the collection
canola-sshExtracted from
lua/oil/adapters/ssh.luaandlua/oil/adapters/ssh/. Registerscanola-ssh://(current schemeoil-ssh://). Depends onscpbeing in$PATH. On load:lazy.nvim spec:
canola-s3Extracted from
lua/oil/adapters/s3.luaandlua/oil/adapters/s3/. Registerscanola-s3://. Depends onawsCLI. Note: the current codebase usesoil-sss://as the scheme on Neovim < 0.12 because Neovim could not open buffers whose name contained a number adjacent to://; this workaround and its version guard should carry over.canola-ftpExtracted from
lua/oil/adapters/ftp.luaandlua/oil/adapters/ftps.lua. Registerscanola-ftp://andcanola-ftps://. Depends oncurl.canola-trashExtracted from
lua/oil/adapters/trash.luaandlua/oil/adapters/trash/(platform backends:freedesktop.lua,mac.lua,windows.lua,windows/). Registerscanola-trash://.Trash is common enough that keeping it in core was considered, but the platform-specific branching (three separate backends, PowerShell connection pool on Windows) adds meaningful complexity and maintenance surface to core. It belongs in the collection.
canola-gitGit status display: decorating oil buffer lines with their git status (modified, staged, untracked, etc.). This is distinct from the
git.luaoperation hooks that stay in core.The existing upstream plugin oil-git-status.nvim already does this well. The preferred approach is to coordinate with its author about adopting or co-maintaining it under the canola-collection umbrella rather than building from scratch. If that coordination fails, build fresh.
Either way, the collection plugin exposes decorations via virtual text or extmarks, not by modifying buffer content. Core exposes
OilMutationCompleteandOilReadPostuser autocmds thatcanola-gitlistens to in order to refresh status after mutations.canola-resessionThe existing
lua/resession/extensions/oil.luamoves tocanola-resession/lua/resession/extensions/canola.lua. It is a resession.nvim window extension that saves and restores oil buffer URLs across sessions. No behavior changes needed during extraction — it is already self-contained.Migration path
Users of the current adapters add the relevant collection plugin alongside canola:
URL schemes change from
oil-ssh://tocanola-ssh://, etc. A compatibility shim in each collection plugin can register the old scheme as an alias for one release cycle to give users time to update bookmarks and config.Work breakdown
require('canola').register_adapter(scheme, adapter)in corebarrettruth/canola-collectionrepo with monorepo skeleton and shared CIcanola-gitas new build or adoptioncanola-resession