feat(table): add cell wrapping using virt lines#617
feat(table): add cell wrapping using virt lines#617MaxDillon wants to merge 2 commits intoMeanderingProgrammer:mainfrom
Conversation
MeanderingProgrammer
left a comment
There was a problem hiding this comment.
This is a really interesting PR, it's going to take me a bit of time to parse through it.
I appreciate the effort! This could be a truly awesome feature.
| end | ||
|
|
||
| -- Table already fits; use existing renderer | ||
| if total_natural <= text_budget then |
There was a problem hiding this comment.
I haven't dug in much here but this seems to not handle the case where concealing results in the rows fitting within the available width. At least in the specific case of this repos README:
| Screenshot | Video |
| ---------- | --------- |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
When I reduce the window size it renders as:
It gets caught on this line as it thinks the width is enough to hold the content. But that would need to based on the unconcealed width rather than the visible width.
There was a problem hiding this comment.
I think I figured out what is going wrong here and it is a bug. Try this to fix it:
Go into any one of the link names (Heading, Table, Quote, Callout, or Latex) and write a bunch more text in there
100iLatex<esc>
This should cause that cell to have enough rendered text to enable wrapping, and that should resolve the issue.
When we are in wrapping mode, the solution mentioned in #616 works for wrapping even with concealed text, but when there is not enough text, I am falling back on the old wrapping strategy. In this scenario, where the un-rendered content is wrapping but the table hasn't entered into wrapping mode, we get this issue.
For now, test with at least one cell having enough rendered content to wrap, and I can either
A) Always use the wrapping renderer regardless of whether any text is getting wrapped
or
B) Include a check to enable wrap mode if any unrendered row content is wrapping
There was a problem hiding this comment.
Should be fixed by fb51061
Just disabling early exit here. We will still default to nowrap if applicable, it will just use the full range of checks now. Try your old experiment with the README
| -- | 0.1–1.0 | fraction of window width, e.g. 0.8 = 80% | | ||
| -- | 2+ | absolute character width, e.g. 80 = 80 columns | | ||
| -- | < 0 | window width minus N, e.g. -10 = width minus 10 | | ||
| max_table_width = 0, |
There was a problem hiding this comment.
One minor thing is if this does get merged in we'd definitely enable it by default, probably set the default to 1.0. Unless we feel it's unstable and want to keep stress testing it before switching it on for everyone.
fa67526 to
fb51061
Compare
| end, | ||
| }) | ||
| -- terminal / GUI resize — re-render all visible attached windows | ||
| vim.api.nvim_create_autocmd('VimResized', { |
There was a problem hiding this comment.
Is this not covered by the WinResized autocmd?
| end | ||
| end | ||
|
|
||
| local total_natural = 0 |
| }) | ||
|
|
||
| -- Lines 1..height-1: overlay buffer wrap continuations, then virt_lines. | ||
| if height > 1 then |
There was a problem hiding this comment.
remove, if height <= 1 then the for vl = 1, height - 1 do will be skipped all on its own since the value will be < 1.
| -- uses the capped widths (padding is included in delim col width). | ||
| if self.layout.wrap then | ||
| for i, w in ipairs(self.layout.col_widths) do | ||
| self.data.delim.cols[i].width = w + 2 * self.config.padding |
There was a problem hiding this comment.
This implementation (along with the way the line is built) will always add additional padding to cells that do not need it. The point of padding is to make sure that each cell has space around it, i.e. |A| -> | A |.
However if the cell already has padding like | A | it can be kept as is. With this logic it gets changed to | A | (with 2 extra spaces).
| end | ||
|
|
||
| local filler = self.config.filler | ||
| local function build_line(visual_line) |
There was a problem hiding this comment.
This currently doesn't use the alignment signal, not strictly necessary from the start, but we probably wouldn't enable it by default without that. We would probably only try to align cells that are not wrapped.
| ---@param end_col integer | ||
| ---@return render.md.mark.Line | ||
| function Render:cell_segments(row, start_col, end_col) | ||
| local raw_full = vim.api.nvim_buf_get_text( |
There was a problem hiding this comment.
I've updated the parsed columns so now they store the node associated with them: bd482f9
So you can pass that along to this method and do col.node.text. You'll need to rebase against main, will probably have a few merge conflicts to resolve.
| local buf_line = vim.api.nvim_buf_get_lines( | ||
| self.context.buf, row.node.start_row, row.node.start_row + 1, false | ||
| )[1] or '' | ||
| local raw_screen_lines = math.max(1, math.ceil(str.width(buf_line) / win_width)) |
There was a problem hiding this comment.
local _, line = row.node:line('first', 0)
local raw_screen_lines = math.ceil(str.width(line) / win_width)| local buf_line = vim.api.nvim_buf_get_lines( | ||
| self.context.buf, row.node.start_row, row.node.start_row + 1, false | ||
| )[1] or '' |
There was a problem hiding this comment.
local _, buf_line = row.node:line('first', 0)
buf_line = buf_line or ''|
|
||
| ---@private | ||
| ---@return render.md.table.Layout | ||
| function Render:compute_layout() |
There was a problem hiding this comment.
Currently does not handle tables with leading spaces, i.e.
| Col | Col | Col |
| --- | --- | --- |
| Row | Row | Row |
Closes: #616
What it does
compute_layoutinRenderer:setup()calculates layout (column widths, row heights)