Virtual text columns #25
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#25
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?
Problem
Columns (icon, size, permissions, mtime, owner, group) are rendered as inline text prepended to each buffer line. This has several concrete consequences:
Buffer content is polluted. A typical line looks like
rwxr-xr-x 4.2k Mar 12 14:30 filename. Everything beforefilenameis column data baked into the buffer.Column data is editable by accident.
c0,d0, visual block, and similar motions can silently corrupt column text or the concealed ID prefix.constrain_cursoronly guards insert mode. The user sees a cryptic parse error on:wwith no indication of what went wrong.Yank includes column garbage.
yyyanks the full line: concealed ID, icon, permissions. Pasting duplicates all of it. There is no clean way to yank just the filename.Highlights require a workaround. Extmarks don't survive yank/paste, so a
TextChangedautocmd re-parses the entire buffer on every edit just to reapply column highlights. This is an expensive workaround for a problem that wouldn't exist if column text weren't in the buffer.Parsing is fragile.
parse_lineinmutator/parser.luaconsumes column text segment by segment, using each column'sparse()function to peel off its portion of the line. Every column must have aparse()implementation with a correct regex. Byte offset tracking (ranges) propagates throughconstrain_cursor,show_insert_guide, andupdate_insert_boundary. Any column width variation (e.g. variable-width timestamps) can introduce off-by-one bugs.Proposed approach
Render non-name columns as virtual text via
nvim_buf_set_extmarkwith thevirt_textfield, anchored inline before or after the name. Buffer lines contain only/{id} {name}.This eliminates all four problems by design: virtual text is not editable, not yankable, not part of the buffer diff, and re-renders automatically via Neovim's extmark invalidation without a
TextChangedworkaround.Column classification
Columns split into two categories:
Physical columns — text that lives in the buffer and participates in
parse_line. Only the filename (and symlink target) is physical after this change. The concealed ID prefix stays physical too, since it is the anchor for all extmarks.Virtual columns — display-only, rendered as
virt_texton the same extmark that currently handles ID concealment. Noparse()function needed. Includes: icon, size, permissions, mtime, owner, group, and any third-party column that opts in.The
oil.ColumnDefinitioninterface gains an optionalvirtualfield. Whenvirtual = true,columns.render_colreturns avirt_text-compatible chunk list;parse_colis never called for that column.Implementation scope
columns.lua— addvirtualfield tooil.ColumnDefinition;render_colreturns virt_text chunks whenvirtual = truemutator/parser.lua—parse_lineskips virtual columns entirely;rangesno longer tracks their byte offsetsview.lua—format_entry_colsplaces virtual column chunks on the extmark instead of prepending to the line string;constrain_cursor,show_insert_guide, andupdate_insert_boundaryno longer need to account for column widthsutil.render_table/ column alignment — alignment is handled viavirt_text_win_col(fixed virtual column position) or padding in the virt_text chunk list, not by padding the buffer stringTextChangedhighlight-reapplication autocmd — removed; extmarks handle invalidation automaticallyInteraction notes
constrain_cursor— cursor is already constrained toranges.name. With virtual columns gone from the buffer,ranges.namestarts at position 1 after the ID prefix space. The constrain logic simplifies.Virtual text at EOL — columns rendered after the name (e.g. size, mtime) use
virt_text_pos = "eol"or"inline". EOL virtual text is not reachable by the cursor, so it doesn't affectconstrain_cursor.Performance — extmarks are cheap. The expensive part is the
nvim_buf_set_extmarkcall per entry on re-render, which is the same cost as today's highlight extmarks. No net regression.Backwards compatibility — the
virtualfield is optional. Existing columns without it remain physical and continue to work. The publicregister_columnAPI (see #192) exposesvirtualas a first-class option.Supersedes
Closes #136 (inline editing guard via
on_bytes) — that was a weaker mitigation for the same root cause.Consolidates
Implemented in #224.