From ca959c9437d13ca06f178b0f7daad62fc35efe9f Mon Sep 17 00:00:00 2001 From: Greg Hurrell Date: Sun, 28 Aug 2022 17:42:03 +0200 Subject: [PATCH] fix: fix rendering glitches due to interaction with vim-dirvish This isn't a bug in vim-dirvish, but there is something about the way it operates that triggers this undesired behavior in Command-T. The repro isn't 100% reliable but it almost is: 1. Create a tmux split in order to have a narrow window to test inside. 2. Open vim-dirvish with `nvim .`. 3. Split the buffer vertically to make it even thinner (strictly speaking, you don't have to do this, but it makes it more likely to reproduce). 4. Open Command-T; see that the match listing is acting as though it were scrolled to the right (ie. you can't see the text on the left, or you can only see the tail end of it). Now, what vim-dirvish is doing is having potentially very long absolute paths in its buffer that are very wide, and hiding the bit that corresponds to the current working directory using Vim's "conceal" feature. So, you only see relative paths (relative to the current working directory), but each line in the buffer may be much longer. So, given a `'textwidth'` of, say, 80, it's easily possibly for you to have lines longer than that, even if they don't look that long. This becomes more obvious if you set `'colorcolumn'` to "+0,+1" etc; you might have a path that looks like "README.md" in the visible spectrum, but the line is actually prefixed by something way longer, and you can see the colorcolumn columns not in column 80 (assuming `'textwidth'` is 80) like you would expect, but in something way farther to the left, like "column" 15 or 20. If you jump the cursor all the way to the start of the line (with `^`) then you see the colorcolumn highlighting move to the right, and Command-T works without the rendering glitch. If you jump to the end (with `$`), the colorcolumn highlighting moves back to the left and the bug returns. I tried various settings of `'sidescroll'` and `'sidescrolloff'` but the only way I could get the problem to go away was to turn `'wrap'` _on_, and then trim my lines to avoid the unwanted wrapping. Moving the cursor to column 0 with `nvim_win_set_cursor` does not solve this problem, even thought he docs say it will scroll the window if necessary (note: we were already doing this). I tried to repro this without vim-dirvish, and didn't succeed. For example I got a big Markdown file with long lines and tried various values of all the settings without reproducing the bug. I turned off various bells and whistles. I updated vim-dirvish. In the end, I don't have a smoking gun, but I have a correlation. It's a mystery how the state of the vim-dirvish window could/would affect an independent buffer (the match listing); that does feel like a bug, in Neovim most likely. But it seem so edge-casey and speculative that I don't think I can even formulate a bug report. --- doc/command-t.txt | 3 - ftplugin/CommandTMatchListing.lua | 7 ++- .../commandt/private/match_listing.lua | 60 +++++++++++-------- 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/doc/command-t.txt b/doc/command-t.txt index 52d641e2..0347d65c 100644 --- a/doc/command-t.txt +++ b/doc/command-t.txt @@ -240,9 +240,6 @@ KNOWN ISSUES *command-t-known-issues* to force a re-scan. 6.x does not implement any such caching (which means that results are always fresh, but on large directories the re-scanning may introduce a noticeable delay). -- Sometimes the results in the match listing are scrolled to the right, - causing the left edge to be cut off; I would love to fix this but haven't - identified a cause yet. - The documentation for 6.x (ie. this document) is still a work in progress. diff --git a/ftplugin/CommandTMatchListing.lua b/ftplugin/CommandTMatchListing.lua index 275592db..8b2d617a 100644 --- a/ftplugin/CommandTMatchListing.lua +++ b/ftplugin/CommandTMatchListing.lua @@ -6,4 +6,9 @@ vim.bo.textwidth = 0 vim.wo.concealcursor = '' vim.wo.conceallevel = 0 vim.wo.winhighlight = 'IncSearch:Normal,Search:Normal' -vim.wo.wrap = false + +-- Would like this to be false, but that produces rendering glitches in +-- conjunction with vim-dirvish, so instead we turn wrapping on but trim our +-- match listing text so that it is never wide enough to actually cause +-- wrapping. +vim.wo.wrap = true diff --git a/lua/wincent/commandt/private/match_listing.lua b/lua/wincent/commandt/private/match_listing.lua index 60304736..90b4af82 100644 --- a/lua/wincent/commandt/private/match_listing.lua +++ b/lua/wincent/commandt/private/match_listing.lua @@ -43,19 +43,45 @@ function MatchListing:close() end end +local format_line = function(line, width, selected) + local prefix = selected and '> ' or ' ' + + -- Right pad so that selection highlighting is shown across full width. + if width < 104 then + if #line > 99 then + -- No padding needed. + line = prefix .. line + else + line = prefix .. string.format('%-' .. (width - #prefix) .. 's', line) + end + else + -- Avoid: "invalid option" caused by format argument > 99. + line = prefix .. string.format('%-99s', line) + local diff = width - line:len() + if diff > 0 then + line = line .. string.rep(' ', diff) + end + end + + -- Trim right to make sure we never wrap. + return line:sub(1, width) +end + function MatchListing:select(selected) assert(type(selected) == 'number') assert(selected > 0) - assert(selected <= #self._lines) + assert(selected <= #self._results) if self._window then - local selection = ' ' .. self._lines[self._selected]:sub(3) - self._window:replace_line(selection, self._selected) + local width = self._window:width() or vim.o.columns -- BUG: width may be cached/stale + + local previous_selection = format_line(self._results[self._selected], width, false) + self._window:replace_line(previous_selection, self._selected) self._window:unhighlight_line(self._selected) self._selected = selected - selection = '> ' .. self._lines[self._selected]:sub(3) - self._window:replace_line(selection, selected) - self._window:highlight_line(selected) + local new_selection = format_line(self._results[self._selected], width, true) + self._window:replace_line(new_selection, self._selected) + self._window:highlight_line(self._selected) end end @@ -112,26 +138,8 @@ function MatchListing:update(results, options) local width = self._window:width() or vim.o.columns self._lines = {} for i, result in ipairs(results) do - local prefix = i == self._selected and '> ' or ' ' - local line = nil - - -- Right pad so that selection highlighting is shown across full width. - if width < 104 then - if #result > 99 then - -- No padding needed. - line = prefix .. result - else - line = prefix .. string.format('%-' .. (width - #prefix) .. 's', result) - end - else - -- Avoid: "invalid option" caused by format argument > 99. - line = prefix .. string.format('%-99s', result) - local diff = width - line:len() - if diff > 0 then - line = line .. string.rep(' ', diff) - end - end - + local selected = i == self._selected + local line = format_line(result, width, selected) table.insert(self._lines, line) end self._window:unhighlight()