diff --git a/OPTIONS.md b/OPTIONS.md index 0522c2da..12b6bdf1 100644 --- a/OPTIONS.md +++ b/OPTIONS.md @@ -382,7 +382,7 @@ Scrollbar style in the builtin previewer, set to `false` to disable, possible va #### globals.winopts.preview.scrolloff -Type: `number`, Default: `-2` +Type: `number`, Default: `-1` Float style scrollbar offset from the right edge of the preview window. diff --git a/doc/fzf-lua-opts.txt b/doc/fzf-lua-opts.txt index 60d0b233..a27089ac 100644 --- a/doc/fzf-lua-opts.txt +++ b/doc/fzf-lua-opts.txt @@ -1,4 +1,4 @@ -*fzf-lua-opts.txt* For Neovim >= 0.8.0 Last change: 2024 December 18 +*fzf-lua-opts.txt* For Neovim >= 0.8.0 Last change: 2024 December 27 ============================================================================== Table of Contents *fzf-lua-opts-table-of-contents* @@ -504,7 +504,7 @@ values are `float|border`. globals.winopts.preview.scrolloff*fzf-lua-opts-globals.winopts.preview.scrolloff* -Type: `number`, Default: `-2` +Type: `number`, Default: `-1` Float style scrollbar offset from the right edge of the preview window. diff --git a/lua/fzf-lua/defaults.lua b/lua/fzf-lua/defaults.lua index 08c58520..b9b8627f 100644 --- a/lua/fzf-lua/defaults.lua +++ b/lua/fzf-lua/defaults.lua @@ -65,7 +65,7 @@ M.defaults = { title = true, title_pos = "center", scrollbar = "border", - scrolloff = "-2", + scrolloff = "-1", -- default preview delay, fzf native previewers has a 100ms delay: -- https://github.com/junegunn/fzf/issues/2417#issuecomment-809886535 delay = 20, diff --git a/lua/fzf-lua/previewer/builtin.lua b/lua/fzf-lua/previewer/builtin.lua index 391d3aa4..e6884788 100644 --- a/lua/fzf-lua/previewer/builtin.lua +++ b/lua/fzf-lua/previewer/builtin.lua @@ -99,12 +99,18 @@ function TSContext.update(winid, bufnr, opts) TSContext._winids[tostring(winid)] = bufnr end end - if TSContext.is_attached(winid) == bufnr then + -- NOTE: when previewer win has border, calling `open` on the same win/buf combo + -- while using `winopts.previewer.border=none` or "noboder" works correctly, most + -- likely an upstream issue and we've seen no cooperation from upstream so defer + -- to the same "hack" + -- local open_once = false + local open_once = TSContext.is_attached(winid) == bufnr + if open_once then open() else -- HACK: but the entire nvim-treesitter-context is essentially a hack -- https://github.com/ibhagwan/fzf-lua/issues/1552#issuecomment-2525456813 - for _, t in ipairs({ 0, 20 }) do + for _, t in ipairs({ 0, 20, 50 }) do vim.defer_fn(function() open() end, t) end end @@ -322,8 +328,7 @@ function Previewer.base:clear_preview_buf(newbuf) retbuf = self:get_tmp_buffer() utils.win_set_buf_noautocmd(self.win.preview_winid, retbuf) -- redraw the title line and clear the scrollbar - self.win:redraw_preview_border() - self.win:update_scrollbar(true) + self.win:update_preview_scrollbar(true) end -- since our temp buffers have 'bufhidden=wipe' the tmp -- buffer will be automatically wiped and 'nvim_buf_is_valid' @@ -372,10 +377,6 @@ function Previewer.base:display_entry(entry_str) local populate_preview_buf = function(entry_str_) if not self.win or not self.win:validate_preview() then return end - -- redraw the preview border, resets title - -- border scrollbar and border highlights - self.win:redraw_preview_border() - -- specialized previewer populate function self:populate_preview_buf(entry_str_) @@ -519,7 +520,7 @@ function Previewer.base:scroll(direction) end self:update_ts_context() self:update_render_markdown() - self.win:update_scrollbar() + self.win:update_preview_scrollbar() end function Previewer.base:ts_ctx_toggle() @@ -1078,31 +1079,29 @@ function Previewer.buffer_or_file:set_cursor_hl(entry) end) end -function Previewer.buffer_or_file:update_border(entry) - if self.title then - local filepath = entry.path - if filepath then - if filepath:match("^%[DEBUG]") then - filepath = "[DEBUG]" - else - if self.opts.cwd then - filepath = path.relative_to(entry.path, self.opts.cwd) - end - filepath = path.HOME_to_tilde(filepath) +function Previewer.buffer_or_file:update_title(entry) + if not self.title then return end + local filepath = entry.path + if filepath then + if filepath:match("^%[DEBUG]") then + filepath = "[DEBUG]" + else + if self.opts.cwd then + filepath = path.relative_to(entry.path, self.opts.cwd) end + filepath = path.HOME_to_tilde(filepath) end - local title = filepath or entry.uri or entry.bufname - -- was transform function defined? - if self.title_fnamemodify then - local wincfg = vim.api.nvim_win_get_config(self.win.border_winid) - title = self.title_fnamemodify(title, wincfg and wincfg.width) - end - if entry.bufnr then - title = string.format("buf %d: %s", entry.bufnr, title) - end - self.win:update_title(" " .. title .. " ") end - self.win:update_scrollbar(entry.no_scrollbar) + local title = filepath or entry.uri or entry.bufname + -- was transform function defined? + if self.title_fnamemodify then + local wincfg = vim.api.nvim_win_get_config(self.win.preview_winid) + title = self.title_fnamemodify(title, wincfg and wincfg.width) + end + if entry.bufnr then + title = string.format("buf %d: %s", entry.bufnr, title) + end + self.win:update_preview_title(" " .. title .. " ") end function Previewer.buffer_or_file:preview_buf_post(entry, min_winopts) @@ -1127,7 +1126,8 @@ function Previewer.buffer_or_file:preview_buf_post(entry, min_winopts) end end - self:update_border(entry) + self:update_title(entry) + self.win:update_preview_scrollbar(entry.no_scrollbar) -- save the loaded entry so we can compare -- bufnr|path with the next entry. If equal @@ -1222,7 +1222,7 @@ function Previewer.man_pages:populate_preview_buf(entry_str) vim.api.nvim_buf_set_lines(tmpbuf, 0, -1, false, output) vim.bo[tmpbuf].filetype = self.filetype self:set_preview_buf(tmpbuf) - self.win:update_scrollbar() + self.win:update_preview_scrollbar() end Previewer.marks = Previewer.buffer_or_file:extend() @@ -1393,7 +1393,7 @@ function Previewer.highlights:populate_preview_buf(entry_str) self.orig_pos = api.nvim_win_get_cursor(0) utils.zz() end) - self.win:update_scrollbar() + self.win:update_preview_scrollbar() end Previewer.quickfix = Previewer.base:extend() @@ -1444,8 +1444,8 @@ function Previewer.quickfix:populate_preview_buf(entry_str) vim.api.nvim_buf_set_lines(self.tmpbuf, 0, -1, false, lines) vim.bo[self.tmpbuf].filetype = "qf" self:set_preview_buf(self.tmpbuf) - self.win:update_title(string.format("%s: %s", nr, qf_list.title)) - self.win:update_scrollbar() + self.win:update_preview_title(string.format("%s: %s", nr, qf_list.title)) + self.win:update_preview_scrollbar() end Previewer.autocmds = Previewer.buffer_or_file:extend() diff --git a/lua/fzf-lua/previewer/codeaction.lua b/lua/fzf-lua/previewer/codeaction.lua index bb2970df..14df6537 100644 --- a/lua/fzf-lua/previewer/codeaction.lua +++ b/lua/fzf-lua/previewer/codeaction.lua @@ -263,8 +263,8 @@ function M.builtin:populate_preview_buf(entry_str) vim.api.nvim_buf_set_lines(self.tmpbuf, 0, -1, false, lines) vim.bo[self.tmpbuf].filetype = "git" self:set_preview_buf(self.tmpbuf) - self.win:update_title(string.format(" Action #%d ", idx)) - self.win:update_scrollbar() + self.win:update_preview_title(string.format(" Action #%d ", idx)) + self.win:update_preview_scrollbar() end M.native = native.base:extend() diff --git a/lua/fzf-lua/win.lua b/lua/fzf-lua/win.lua index 72e9fcda..93071762 100644 --- a/lua/fzf-lua/win.lua +++ b/lua/fzf-lua/win.lua @@ -167,6 +167,44 @@ function FzfWin:setup_keybinds() end function FzfWin:generate_layout(winopts) + winopts = winopts or self.winopts + -- If previewer is hidden we use full fzf layout, when previewer toggle behavior + -- is "extend" we still reduce fzf main layout as if the previewer is displayed + if not self.previewer_is_builtin + or (self.preview_is_hidden and self._previewer.toggle_behavior ~= "extend") + then + self.layout = { + fzf = { + row = self.winopts.row, + col = self.winopts.col, + height = self.winopts.height, + width = self.winopts.width, + style = "minimal", + relative = self.winopts.relative or "editor", + zindex = self.winopts.zindex, + } + } + return + end + + if self.previewer_is_builtin and self.winopts.split then + local wininfo = utils.getwininfo(self.fzf_winid) + -- unlike floating win popups, split windows inherit the global + -- 'signcolumn' setting which affects the available width for fzf + -- 'generate_layout' will then use the sign column available width + -- to assure a perfect alignment of the builtin previewer window + -- and the dummy native fzf previewer window border underneath it + local signcol_width = vim.wo[self.fzf_winid].signcolumn == "yes" and 1 or 0 + winopts = { + row = wininfo.winrow, + col = wininfo.wincol + signcol_width, + height = wininfo.height, + width = api.nvim_win_get_width(self.fzf_winid) - signcol_width, + signcol_width = signcol_width, + split = self.winopts.split, + } + end + local pwopts local row, col = winopts.row, winopts.col local height, width = winopts.height, winopts.width @@ -188,12 +226,12 @@ function FzfWin:generate_layout(winopts) end)() if winopts.split then -- Custom "split" - pwopts = { relative = "win", anchor = "NW", row = 1, col = 1 } + pwopts = { relative = "win", anchor = "NW", row = 0, col = 0 } if preview_pos == "down" or preview_pos == "up" then pwopts.width = width - 2 pwopts.height = utils.round((height) * preview_size / 100, math.huge) - 2 if preview_pos == "down" then - pwopts.row = height - pwopts.height - 1 + pwopts.row = height - pwopts.height - 2 end else -- left|right pwopts.height = height - 2 @@ -207,35 +245,45 @@ function FzfWin:generate_layout(winopts) pwopts = { relative = "editor" } if preview_pos == "down" or preview_pos == "up" then height = height - 2 - pwopts.col = col + 1 -- +border + pwopts.col = col pwopts.width = width pwopts.height = utils.round((height) * preview_size / 100, 0.5) height = height - pwopts.height if preview_pos == "down" then - -- next row +2xborder - pwopts.row = row + 1 + height + 2 - else -- up - pwopts.row = row + 1 -- +border - row = pwopts.row + 1 + pwopts.height + -- next row + pwopts.row = row + 2 + height + else -- up + pwopts.row = row + row = pwopts.row + 2 + pwopts.height end - else -- left|right + else -- left|right width = width - 2 - pwopts.row = row + 1 -- +border + pwopts.row = row pwopts.height = height pwopts.width = utils.round(width * preview_size / 100, 0.5) width = width - pwopts.width if preview_pos == "right" then - -- next col +2xborder - pwopts.col = col + 1 + width + 2 - else -- left - pwopts.col = col + 1 -- +border - col = pwopts.col + 1 + pwopts.width + -- next col + pwopts.col = col + 2 + width + else -- left + pwopts.col = col + col = pwopts.col + 2 + pwopts.width end end end - return { - fzf = { row = row, col = col, height = height, width = width }, - preview = pwopts, + self.layout = { + fzf = vim.tbl_extend("force", { row = row, col = col, height = height, width = width }, { + style = "minimal", + relative = self.winopts.relative or "editor", + zindex = self.winopts.zindex, + }), + preview = vim.tbl_extend("force", pwopts, { + style = "minimal", + -- border = self.winopts.preview.border, + border = "rounded", + zindex = self.winopts.zindex, + focusable = true, + }) } end @@ -347,12 +395,6 @@ function FzfWin:normalize_winopts(fullscreen) { "CursorLine", o.hls.cursorline }, { "CursorLineNr", o.hls.cursorlinenr }, }, - -- our border is manually drawn so we need - -- to replace Normal with the border color - prev_border = { - { "Normal", o.hls.preview_border }, - { "NormalFloat", o.hls.preview_border } - }, } -- add title hl if wasn't provided by the user @@ -422,8 +464,6 @@ function FzfWin:reset_win_highlights(win) local key = "main" if win == self.preview_winid then key = "prev" - elseif win == self.border_winid then - key = "prev_border" end local hl for _, h in ipairs(self.winopts.__winhls[key]) do @@ -564,7 +604,7 @@ function FzfWin:new(o) self.fullscreen = o.winopts.fullscreen self.winopts = self:normalize_winopts(self.fullscreen) self.preview_wrap = not opt_matches(o, "wrap", "nowrap") - self.preview_hidden = not opt_matches(o, "hidden", "nohidden") + self.preview_is_hidden = not opt_matches(o, "hidden", "nohidden") self.preview_border = not opt_matches(o, "border", "noborder") self.keymap = o.keymap self.previewer = o.previewer @@ -573,7 +613,7 @@ function FzfWin:new(o) -- Backward compat since removal of "border" scrollbar if self.winopts.preview.scrollbar == "border" then self.winopts.preview.scrollbar = "float" - self.winopts.preview.scrolloff = -1 + self.winopts.preview.scrolloff = 0 self.winopts.preview._scroll_hide_empty = true self.hls.scrollfloat_f = false -- Reverse "FzfLuaScrollBorderFull" color @@ -648,92 +688,22 @@ function FzfWin:attach_previewer(previewer) self.previewer_is_builtin = previewer and type(previewer.display_entry) == "function" end -function FzfWin:preview_layout() - if self.winopts.split and self.previewer_is_builtin then - local wininfo = utils.getwininfo(self.fzf_winid) - -- unlike floating win popups, split windows inherit the global - -- 'signcolumn' setting which affects the available width for fzf - -- 'generate_layout' will then use the sign column available width - -- to assure a perfect alignment of the builtin previewer window - -- and the dummy native fzf previewer window border underneath it - local signcol_width = vim.wo[self.fzf_winid].signcolumn == "yes" and 1 or 0 - self.layout = self:generate_layout({ - row = wininfo.winrow, - col = wininfo.wincol + signcol_width, - height = wininfo.height, - width = api.nvim_win_get_width(self.fzf_winid) - signcol_width, - signcol_width = signcol_width, - split = self.winopts.split, - }) - end - if not self.layout then return {}, {} end - - local preview_opts = vim.tbl_extend("force", self.layout.preview, { - zindex = self.winopts.zindex, - style = "minimal", - focusable = true, - }) - local border_winopts = { - zindex = self.winopts.zindex - 1, - style = "minimal", - focusable = false, - relative = self.layout.preview.relative, - anchor = self.layout.preview.anchor, - width = self.layout.preview.width + 2, - height = self.layout.preview.height + 2, - col = self.layout.preview.col - 1, - row = self.layout.preview.row - 1, - } - return preview_opts, border_winopts -end - function FzfWin:validate_preview() return not self.closing - and self.preview_winid and self.preview_winid > 0 + and tonumber(self.preview_winid) + and self.preview_winid > 0 and api.nvim_win_is_valid(self.preview_winid) - and self.border_winid and self.border_winid > 0 - and api.nvim_win_is_valid(self.border_winid) -end - -function FzfWin:preview_winids() - return self.preview_winid, self.border_winid -end - -function FzfWin:redraw_preview_border() - local border_buf = self.border_buf - local border_winopts = self.border_winopts - local borderchars = self.winopts.nohl_borderchars - local width, height = border_winopts.width, border_winopts.height - local top = borderchars[1] .. borderchars[2]:rep(width - 2) .. borderchars[3] - local mid = borderchars[8] .. (" "):rep(width - 2) .. borderchars[4] - local bot = borderchars[7] .. borderchars[6]:rep(width - 2) .. borderchars[5] - local lines = { top } - for _ = 1, height - 2 do - table.insert(lines, mid) - end - table.insert(lines, bot) - if not border_buf then - border_buf = api.nvim_create_buf(false, true) - -- run nvim with `-M` will reset modifiable's default value to false - vim.bo[border_buf].modifiable = true - vim.bo[border_buf].bufhidden = "wipe" - end - api.nvim_buf_set_lines(border_buf, 0, -1, true, lines) - -- reset botder window highlights - if self.border_winid and vim.api.nvim_win_is_valid(self.border_winid) then - vim.fn.clearmatches(self.border_winid) - end - return border_buf end function FzfWin:redraw_preview() - if not self.previewer_is_builtin or self.preview_hidden then return end - - self.prev_winopts, self.border_winopts = self:preview_layout() - if utils.tbl_isempty(self.prev_winopts) or utils.tbl_isempty(self.border_winopts) then - return -1, -1 + if not self.previewer_is_builtin or self.preview_is_hidden then + return end + -- Generate the preview layout + self:generate_layout() + assert(type(self.layout.preview) == "table") + -- manual border chars looks horrible with ambiwdith="double", override border -- window with preview window dimensions and use builtin `nvim_open_win` border -- NOTES: @@ -746,35 +716,24 @@ function FzfWin:redraw_preview() row = self.border_winopts.row, border = self.winopts._border, }) - self.prev_single_win = true end if self:validate_preview() then - self.border_buf = api.nvim_win_get_buf(self.border_winid) - self:redraw_preview_border() - api.nvim_win_set_config(self.border_winid, self.border_winopts) -- since `nvim_win_set_config` removes all styling, save backup -- of the current options and restore after the call (#813) local style = self:get_winopts(self.preview_winid, self._previewer:gen_winopts()) - api.nvim_win_set_config(self.preview_winid, self.prev_winopts) + vim.api.nvim_win_set_config(self.preview_winid, self.layout.preview) self:set_winopts(self.preview_winid, style) else - local tmp_buf = api.nvim_create_buf(false, true) + local tmp_buf = self._previewer:get_tmp_buffer() -- No autocmds, can only be sent with 'nvim_open_win' - self.prev_winopts.noautocmd = true - self.border_winopts.noautocmd = true - vim.bo[tmp_buf].bufhidden = "wipe" - self.border_buf = self:redraw_preview_border() - self.preview_winid = api.nvim_open_win(tmp_buf, false, self.prev_winopts) - self.border_winid = api.nvim_open_win(self.border_buf, false, self.border_winopts) + self.preview_winid = api.nvim_open_win(tmp_buf, false, + vim.tbl_extend("force", self.layout.preview, { noautocmd = true })) -- Add win local var for the preview|border windows api.nvim_win_set_var(self.preview_winid, "fzf_lua_preview", true) - api.nvim_win_set_var(self.border_winid, "fzf_lua_preview", true) end - self:reset_win_highlights(self.border_winid) self:reset_win_highlights(self.preview_winid) self._previewer:display_last_entry() - return self.preview_winid, self.border_winid end function FzfWin:validate() @@ -784,9 +743,6 @@ end function FzfWin:redraw() self.winopts = self:normalize_winopts(self.fullscreen) - if not self.winopts.split and self.previewer_is_builtin then - self.layout = self:generate_layout(self.winopts) - end self:set_backdrop() self:hide_scrollbar() if self:validate() then @@ -799,38 +755,19 @@ end function FzfWin:redraw_main() if self.winopts.split then return end - local hidden = self._previewer - and self.preview_hidden - and self._previewer.toggle_behavior ~= "extend" - local relative = self.winopts.relative or "editor" - local columns, lines = vim.o.columns, vim.o.lines - if relative == "win" then - columns, lines = vim.api.nvim_win_get_width(0), vim.api.nvim_win_get_height(0) - end - -- must use clone or fullscreen overrides our values - local winopts = utils.tbl_deep_clone(self.winopts) - if self.layout and not hidden then - winopts = utils.tbl_deep_clone(self.layout.fzf) - end + self:generate_layout() - local win_opts = { - width = winopts.width or math.min(columns - 4, math.max(80, columns - 20)), - height = winopts.height or math.min(lines - 4, math.max(20, lines - 10)), - style = "minimal", - relative = relative, + local winopts = vim.tbl_extend("keep", {}, self.layout.fzf, { border = self.winopts.border, - zindex = self.winopts.zindex, title = utils.__HAS_NVIM_09 and self.winopts.title or nil, title_pos = utils.__HAS_NVIM_09 and self.winopts.title_pos or nil, - } - win_opts.row = winopts.row or math.floor(((lines - win_opts.height) / 2) - 1) - win_opts.col = winopts.col or math.floor((columns - win_opts.width) / 2) + }) -- When border chars are empty strings 'nvim_open_win' adjusts -- the layout to take all available space, we use these to adjust -- our main window height to use all available lines (#364) - if type(win_opts.border) == "table" then + if type(winopts.border) == "table" then local function is_empty_str(tbl, arr) for _, i in ipairs(arr) do if tbl[i] and #tbl[i] > 0 then @@ -840,12 +777,12 @@ function FzfWin:redraw_main() return true end - win_opts.height = win_opts.height - + (is_empty_str(win_opts.border, { 2 }) and 1 or 0) -- top border - + (is_empty_str(win_opts.border, { 6 }) and 1 or 0) -- bottom border - win_opts.width = win_opts.width - + (is_empty_str(win_opts.border, { 4 }) and 1 or 0) -- right border - + (is_empty_str(win_opts.border, { 8 }) and 1 or 0) -- left border + winopts.height = winopts.height + + (is_empty_str(winopts.border, { 2 }) and 1 or 0) -- top border + + (is_empty_str(winopts.border, { 6 }) and 1 or 0) -- bottom border + winopts.width = winopts.width + + (is_empty_str(winopts.border, { 4 }) and 1 or 0) -- right border + + (is_empty_str(winopts.border, { 8 }) and 1 or 0) -- left border end if self:validate() then @@ -855,12 +792,12 @@ function FzfWin:redraw_main() self._previewer:clear_preview_buf(true) self._previewer:clear_cached_buffers() end - api.nvim_win_set_config(self.fzf_winid, win_opts) + api.nvim_win_set_config(self.fzf_winid, winopts) else -- save 'cursorline' setting prior to opening the popup local cursorline = vim.o.cursorline self.fzf_bufnr = self.fzf_bufnr or vim.api.nvim_create_buf(false, true) - self.fzf_winid = utils.nvim_open_win(self.fzf_bufnr, true, win_opts) + self.fzf_winid = utils.nvim_open_win(self.fzf_bufnr, true, winopts) -- disable search highlights as they interfere with fzf's highlights if vim.o.hlsearch and vim.v.hlsearch == 1 then self.hls_on_close = true @@ -924,7 +861,7 @@ function FzfWin:treesitter_attach() -- the native fzf preview window local min_col, max_col, trim_right = (function() local min, max, tr = 0, nil, 4 - if not self.preview_hidden + if not self.preview_is_hidden and (not self.previewer_is_builtin or self.winopts.split) then local win_width = vim.api.nvim_win_get_width(self.fzf_winid) @@ -1073,9 +1010,6 @@ function FzfWin:create() -- Set backdrop self:set_backdrop() - if not self.winopts.split and self.previewer_is_builtin then - self.layout = self:generate_layout(self.winopts) - end -- save sending bufnr/winid self.src_bufnr = vim.api.nvim_get_current_buf() self.src_winid = vim.api.nvim_get_current_win() @@ -1134,12 +1068,6 @@ function FzfWin:close_preview(do_not_clear_cache) if self._previewer and self._previewer.close then self._previewer:close(do_not_clear_cache) end - if self.border_winid and vim.api.nvim_win_is_valid(self.border_winid) then - utils.nvim_win_close(self.border_winid, true) - end - if self.border_buf and vim.api.nvim_buf_is_valid(self.border_buf) then - vim.api.nvim_buf_delete(self.border_buf, { force = true }) - end if self.preview_winid and vim.api.nvim_win_is_valid(self.preview_winid) then utils.nvim_win_close(self.preview_winid, true) end @@ -1155,9 +1083,10 @@ function FzfWin:close_preview(do_not_clear_cache) if self._swin2 and vim.api.nvim_win_is_valid(self._swin2) then utils.nvim_win_close(self._swin2, true) end - self._sbuf1, self._sbuf2, self._swin1, self._swin2 = nil, nil, nil, nil - self.border_buf = nil - self.border_winid = nil + self._sbuf1 = nil + self._sbuf2 = nil + self._swin1 = nil + self._swin2 = nil self.preview_winid = nil end @@ -1252,7 +1181,7 @@ function FzfWin.hide() -- Note: we should never get here with a tmux profile as neovim binds (default: ) -- do not apply to tmux, validate anyways in case called directly using the API if not self or self._o._is_fzf_tmux then return end - if self:validate_preview() and not self.preview_hidden then + if self:validate_preview() and not self.preview_is_hidden then self:close_preview() self._hidden_had_preview = true end @@ -1313,7 +1242,7 @@ function FzfWin:hide_scrollbar() end end -function FzfWin:update_scrollbar(hide) +function FzfWin:update_preview_scrollbar(hide) if not self.winopts.preview.scrollbar or self.winopts.preview.scrollbar == "none" or not self:validate_preview() then @@ -1341,19 +1270,26 @@ function FzfWin:update_scrollbar(hide) return end - local offset = self.prev_single_win and 1 or 0 local info = o.wininfo local style1 = {} - style1.relative = "editor" style1.style = "minimal" style1.focusable = false style1.width = 1 style1.height = info.height - style1.row = info.winrow - 1 + offset - style1.col = info.wincol + info.width + offset + - (tonumber(self.winopts.preview.scrolloff) or -2) style1.zindex = self.winopts.zindex + 1 - -- We hide the "empty" win in `scrollbar="botder"` back compat + style1.row = 0 + style1.col = info.width + (tonumber(self.winopts.preview.scrolloff) or -1) + -- TODO: why is `getwininfo` returning wrong line on the first run when using a split? + if self.layout.preview.relative == "win" then + style1.relative = "win" + style1.anchor = "NW" + style1.win = self.preview_winid + else + style1.relative = "editor" + style1.row = style1.row + info.winrow + style1.col = style1.col + info.wincol + end + -- We hide the "empty" win in `scrollbar="border"` back compat if not self.winopts.preview._scroll_hide_empty then if self._swin1 and vim.api.nvim_win_is_valid(self._swin1) then vim.api.nvim_win_set_config(self._swin1, style1) @@ -1382,52 +1318,21 @@ function FzfWin:update_scrollbar(hide) end end -function FzfWin:update_title(title) - if self.prev_single_win then - -- we are using a single window, the border window is hidden - -- under the preview window and thus meaningless to update - -- if neovim >= 0.9 we can use the builtin title params instead - if utils.__HAS_NVIM_09 then - -- since `nvim_win_set_config` removes all styling, save backup - -- of the current options and restore after the call (#813) - local style = self:get_winopts(self.preview_winid, self._previewer:gen_winopts()) - -- `nvim_win_set_config`: Invalid key: 'noautocmd' - self.prev_winopts.noautocmd = nil - api.nvim_win_set_config(self.preview_winid, vim.tbl_extend("keep", { - title = type(self.hls.preview_title) == "string" - and { { title, self.hls.preview_title } } - or title, - title_pos = self.winopts.preview.title_pos, - }, - self.prev_winopts)) - self:set_winopts(self.preview_winid, style) - end - return - end - local right_pad = 7 - local border_buf = api.nvim_win_get_buf(self.border_winid) - local top = api.nvim_buf_get_lines(border_buf, 0, 1, false)[1] - local width = fn.strwidth(top) - if #title > width - right_pad then - title = title:sub(1, width - right_pad) .. " " - end - local width_title = fn.strwidth(title) - local prefix = fn.strcharpart(top, 0, 3) - if self.winopts.preview.title_pos == "center" then - prefix = fn.strcharpart(top, 0, utils.round((width - width_title) / 2)) - elseif self.winopts.preview.title_pos == "right" then - prefix = fn.strcharpart(top, 0, width - (width_title + 3)) - end - - local suffix = fn.strcharpart(top, width_title + fn.strwidth(prefix), width) - local line = ("%s%s%s"):format(prefix, title, suffix) - pcall(api.nvim_buf_set_lines, border_buf, 0, 1, true, { line }) - - if self.hls.preview_title and #title > 0 then - pcall(vim.api.nvim_win_call, self.border_winid, function() - fn.matchaddpos(self.hls.preview_title, { { 1, #prefix + 1, #title } }, 11) - end) - end +function FzfWin:update_preview_title(title) + -- neovim >= 0.9 added window title + if not utils.__HAS_NVIM_09 or not self.layout.preview.border then return end + -- since `nvim_win_set_config` removes all styling, save backup + -- of the current options and restore after the call (#813) + local style = self:get_winopts(self.preview_winid, self._previewer:gen_winopts()) + -- `noautocmd` can only be set within `nvim_open_win` + vim.api.nvim_win_set_config(self.preview_winid, + vim.tbl_extend("force", self.layout.preview, { + title = type(self.hls.preview_title) == "string" + and { { title, self.hls.preview_title } } + or title, + title_pos = self.winopts.preview.title_pos, + })) + self:set_winopts(self.preview_winid, style) end -- keybind methods below @@ -1441,7 +1346,7 @@ end function FzfWin.toggle_preview() if not _self then return end local self = _self - self.preview_hidden = not self.preview_hidden + self.preview_is_hidden = not self.preview_is_hidden if self._fzf_toggle_prev_bind then -- Toggle the empty preview window (under the neovim preview buffer) utils.feed_keys_termcodes(self._fzf_toggle_prev_bind) @@ -1451,10 +1356,10 @@ function FzfWin.toggle_preview() return end end - if self.preview_hidden and self:validate_preview() then + if self.preview_is_hidden and self:validate_preview() then self:close_preview(true) self:redraw_main() - elseif not self.preview_hidden then + elseif not self.preview_is_hidden then self:redraw_main() self:redraw_preview() end