1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 06:30:03 +08:00
SpaceVim/bundle/deoplete-lsp/lua/hover.lua
2021-10-05 15:13:10 +08:00

161 lines
4.5 KiB
Lua

--
--------------------------------------------------------------------------------
-- File: hover.lua
--------------------------------------------------------------------------------
--
local vim = vim
local api = vim.api
local feature = 'textDocument/hover'
local default_response_handler = vim.lsp.handlers[feature]
local hover_initialise = {
buffer_changes = 0,
complete_item = nil,
complete_item_index = -1,
insert_mode = false,
window = nil
}
local hover = hover_initialise
local util = require 'util'
local complete_visible = function()
return vim.fn.pumvisible() ~= 0
end
local get_markdown_lines = function(result)
local markdown_lines = vim.lsp.util.convert_input_to_markdown_lines(result.contents)
return vim.lsp.util.trim_empty_lines(markdown_lines)
end
local get_window_alignment = function(complete_columns, screen_columns)
if complete_columns < screen_columns / 2 then
alignment = 'right'
else
alignment = 'left'
end
return alignment
end
local create_window = function(method, result)
return util.focusable_float(method, function()
local markdown_lines = get_markdown_lines(result)
if vim.tbl_isempty(markdown_lines) then return end
local complete_display_info = vim.fn.pum_getpos()
local alignment = get_window_alignment(complete_display_info['col'], api.nvim_get_option('columns'))
local hover_buffer, hover_window
hover_buffer, hover_window = util.fancy_floating_markdown(markdown_lines, {
pad_left = 1; pad_right = 1;
col = complete_display_info['col']; width = complete_display_info['width']; row = vim.fn.winline();
align = alignment;
})
hover.window = hover_window
if hover_window ~= nil and api.nvim_win_is_valid(hover_window) then
vim.lsp.util.close_preview_autocmd({"CursorMoved", "BufHidden", "InsertCharPre"}, hover_window)
end
return hover_buffer, hover_window
end)
end
local handle_response = function(_, method, result)
if complete_visible() == false then return default_response_handler(_, method, result, _) end
if not (result and result.contents) then return end
return create_window(method, result)
end
local set_response_handler = function()
for _, client in pairs(vim.lsp.buf_get_clients(0)) do
local current_response_handler = client.config.handlers[feature] or default_response_handler
if current_response_handler == handle_response then return end
client.config.handlers[feature] = handle_response
end
end
local decode_user_data = function(user_data)
if user_data == nil or (user_data ~= nil and #user_data == 0) then return end
return vim.fn.json_decode(user_data)
end
local client_with_hover = function()
for _, value in pairs(vim.lsp.buf_get_clients(0)) do
if value.resolved_capabilities.hover == false then return false end
end
return true
end
local buffer_changed = function()
buffer_changes = api.nvim_buf_get_changedtick(0)
if hover.buffer_changes == buffer_changes then return false end
hover.buffer_changes = buffer_changes
return hover.buffer_changes
end
local close_window = function()
if hover.window == nil or not api.nvim_win_is_valid(hover.window) then return end
api.nvim_win_close(hover.window, true)
end
local get_complete_item = function()
local complete_info = api.nvim_call_function('complete_info', {{ 'eval', 'selected', 'items', 'user_data' }})
if complete_info['selected'] == -1 or complete_info['selected'] == hover.complete_item_index then return false end
hover.complete_item_index = complete_info['selected']
return complete_info['items'][hover.complete_item_index + 1]
end
local request_hover = function()
local complete_item = get_complete_item()
if not complete_visible() or not buffer_changed() or not complete_item then return end
close_window()
if not client_with_hover() then return end
local decoded_user_data = decode_user_data(complete_item['user_data'])
if decoded_user_data == nil then return end
set_response_handler()
return vim.lsp.buf_request(api.nvim_get_current_buf(), 'textDocument/hover', util.make_position_params())
end
local insert_enter_handler = function()
hover.insert_mode = true
local timer = vim.loop.new_timer()
timer:start(100, 80, vim.schedule_wrap(function()
request_hover()
if hover.insert_mode == false and timer:is_closing() == false then
timer:stop()
timer:close()
end
end))
end
local insert_leave_handler = function()
hover.insert_mode = false
end
return {
insert_enter_handler = insert_enter_handler,
insert_leave_handler = insert_leave_handler
}