mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-03 12:40:05 +08:00
141 lines
4.2 KiB
Lua
141 lines
4.2 KiB
Lua
|
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 can’t rely on this; for this reason, we have to implement a weird hack that
|
|||
|
-- is going to disable the signs while hop is running (I’m 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
|