Skip to content

Conversation

@cosmicbuffalo
Copy link

I'm a huge fan of oil, I use it constantly. Recently I turned on some of the metadata columns though and they've been bugging me enough that I desperately want to fix these problems:

A - Metadata columns should be able to be on the right (I totally agree with #496)
B - Columns should be able to have headers
C - metadata columns should be formattable with Lua functions

I previously tried to hack together a fix for B over here: #662 but it was pretty half baked and also only partially solved these problems for me.

So instead I set out on the goal of achieving all of the above in one go, by moving all the immutable metadata columns into virtual text. With virtual text, the constraint on the filename being at the end of a line and the constraint on column formats being parseable via string formats go away. The header row could still in theory be added separately, but the implementation of a header row with/without virtual columns are pretty different so I figured it be best to knock them both out at once in the same PR.

This PR is still a WIP, but I figured I'd open a draft to motivate myself to keep working on it, and potentially get a little help from anyone else interested in fixing these issues.

The current implementation is mostly working pretty well, but there are a couple quirks I've discovered about virtual text in neovim in the process of building it. I've documented some of the major learnings below to save anyone else wanting to dive in some time:

  • I discovered early in the process that putting extmarks into the buffer on the normal render loop looked fine at first, but breaks down once you start making changes
    • for example, rendering extmarks on lines based on their content "works", but then if you delete that line, the content disappears but leaves behind the extmark. BAD experience for sure
    • another example, if you were to copy a line and paste it directly below the original, for example, you'd copy the buffer text but not the extmarks, meaning the freshly pasted line would be missing all of its virtual columns and alignment until the buffer is saved. also BAD, imo
    • The fix that I discovered for this was to use a decoration provider instead of rendering extmarks inside the existing render calls
      • With a decoration provider, neovim will render the extmarks on each redraw, which ensures all the columns and alignments and whatnot stay consistent, even for rows actively being edited (with the exception of new files created from scratch)
      • since the decoration provider uses the underlying entry objects cached for a given oil buffer, copying and pasting a line containing a file results in the same virtual columns as the original line being rendered, with metadata being updated accordingly on save
  • I also discovered that rendering of extmarks with decoration providers on the neovim redraw loop doesn't update the cursor position correctly in some cases
    • for example, say the oil buffer renders the id and filename of a file on the first line and places the cursor on the first character of the filename.
      • then the decoration provider comes in and renders the icon for the file with inline virtual text in front of the filename.
        • I've seen that this can result in the buffer text moving over to accommodate the virtual text as expected, but the cursor block stays where it was before the virtual text was rendered, resulting in the cursor being incorrectly positioned on the virtual text.
        • This seems to be a visual glitch only, as the actual cursor position in the buffer according to vim.api.nvim_win_get_cursor returns the correct column
  • The hardest part of this whole project has been figuring out how to deal with cursor positioning, and especially glitches like the one above
    • it seems kinda janky, but putting delays and commands like normal! 0 to trigger cursor moved events and whatnot in various places is required to get the cursor to behave as expected

Anyways, the included changes in this PR are the following: (again, still WIP)

  • New config option virtual_text_columns
    • when set to true, immutable columns will be rendered with virtual text
    • this also allows the name column to be configured in the existing columns config, so that virtual columns may be placed on the right side of the name column
  • New config option show_header
    • when set to true, an empty line will be added to the top of every oil buffer and a header row will be rendered there with virtual text
    • This will also slightly change the behavior of some functionality like constrain_cursor, to prevent the header row from interfering with existing oil features
  • New config option header_format
    • This one is an optional function that takes a raw column header string and should return a formatted custom header string to be used instead of the default raw column header
    • for example, your header format function can take in BIRTHTIME and spit out Created at to be rendered instead
  • New capability to set a function for format in the columns config
    • This is only available when virtual_text_columns is true, otherwise buffer text metadata columns must remain parseable
    • for example, take a timestamp and spit out a string like X days ago

Here's an example of what my oil buffers look like on this branch:

Screenshot 2025-09-18 at 2 28 32 PM

@github-actions github-actions bot requested a review from stevearc September 18, 2025 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant