1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-03 12:40:05 +08:00
SpaceVim/bundle/hop.nvim/lua/hop/window.lua

141 lines
4.2 KiB
Lua
Raw Normal View History

local hint = require'hop.hint'
local M = {}
local function window_context(win_handle, cursor_pos)
-- get a bunch of information about the window and the cursor
local win_info = vim.fn.getwininfo(win_handle)[1]
local win_view = vim.fn.winsaveview()
local top_line = win_info.topline - 1
local bot_line = win_info.botline
-- NOTE: due to an (unknown yet) bug in neovim, the sign_width is not correctly reported when shifting the window
-- view inside a non-wrap window, so we cant rely on this; for this reason, we have to implement a weird hack that
-- is going to disable the signs while hop is running (Im sorry); the state is restored after jump
-- local left_col_offset = win_info.variables.context.number_width + win_info.variables.context.sign_width
local win_width = nil
-- hack to get the left column offset in nowrap
if not vim.wo.wrap then
vim.api.nvim_win_set_cursor(win_handle, { cursor_pos[1], 0 })
local left_col_offset = vim.fn.wincol() - 1
vim.fn.winrestview(win_view)
win_width = win_info.width - left_col_offset
end
return {
hwin = win_handle,
cursor_pos = cursor_pos,
top_line = top_line,
bot_line = bot_line,
win_width = win_width,
col_offset = win_view.leftcol
}
end
-- Collect all multi-windows's context:
--
-- {
-- { -- context list that each contains one buffer
-- hbuf = <buf-handle>,
-- { -- windows list that display the same buffer
-- hwin = <win-handle>,
-- ...
-- },
-- ...
-- },
-- ...
-- }
function M.get_window_context(multi_windows)
local all_ctxs = {}
-- Generate contexts of windows
local cur_hwin = vim.api.nvim_get_current_win()
local cur_hbuf = vim.api.nvim_win_get_buf(cur_hwin)
all_ctxs[#all_ctxs + 1] = {
hbuf = cur_hbuf,
contexts = { window_context(cur_hwin, vim.api.nvim_win_get_cursor(cur_hwin)) },
}
if not multi_windows then
return all_ctxs
end
for _, w in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
local b = vim.api.nvim_win_get_buf(w)
if w ~= cur_hwin then
-- check duplicated buffers; the way this is done is by accessing all the already known contexts and checking that
-- the buffer we are accessing is already present in; if it is, we then append the window context to that buffer
local bctx = nil
for _, buffer_ctx in ipairs(all_ctxs) do
if b == buffer_ctx.hbuf then
bctx = buffer_ctx.contexts
break
end
end
if bctx then
bctx[#bctx + 1] = window_context(w, vim.api.nvim_win_get_cursor(w))
else
all_ctxs[#all_ctxs + 1] = {
hbuf = b,
contexts = { window_context(w, vim.api.nvim_win_get_cursor(w)) }
}
end
end
end
-- Move cursor back to current window
vim.api.nvim_set_current_win(cur_hwin)
return all_ctxs
end
-- Collect visible and unfold lines of window context
--
-- {
-- { line_nr = 0, line = "" }
-- }
function M.get_lines_context(buf_handle, context)
local lines = {}
local lnr = context.top_line
while lnr < context.bot_line do -- top_line is inclusive and bot_line is exclusive
local fold_end = vim.api.nvim_win_call(context.hwin,
function()
return vim.fn.foldclosedend(lnr + 1) -- `foldclosedend()` use 1-based line number
end)
if fold_end == -1 then
lines[#lines + 1] = {
line_nr = lnr,
line = vim.api.nvim_buf_get_lines(buf_handle, lnr, lnr + 1, false)[1], -- `nvim_buf_get_lines()` use 0-based line index
}
lnr = lnr + 1
else
lines[#lines + 1] = {
line_nr = lnr,
line = "",
}
lnr = fold_end
end
end
return lines
end
-- Clip the window context based on the direction.
--
-- If the direction is HintDirection.BEFORE_CURSOR, then everything after the cursor will be clipped.
-- If the direction is HintDirection.AFTER_CURSOR, then everything before the cursor will be clipped.
function M.clip_window_context(context, direction)
if direction == hint.HintDirection.BEFORE_CURSOR then
context.bot_line = context.cursor_pos[1] - 1
elseif direction == hint.HintDirection.AFTER_CURSOR then
context.top_line = context.cursor_pos[1] - 1
end
end
return M