initial commit
This commit is contained in:
commit
5176a07a72
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<div align="center">
|
||||||
|
<h1 align="center">ODIS - Open Docs in Split</h1>
|
||||||
|
</div>
|
80
lua/odis/config.lua
Normal file
80
lua/odis/config.lua
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
-- config.lua
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
-- Display modes
|
||||||
|
M.modes = {
|
||||||
|
float = "float",
|
||||||
|
buffer = "buffer",
|
||||||
|
hsplit = "hsplit",
|
||||||
|
vsplit = "vsplit",
|
||||||
|
tab = "tab",
|
||||||
|
}
|
||||||
|
|
||||||
|
local defaults = {
|
||||||
|
display = {
|
||||||
|
default_mode = M.modes.float,
|
||||||
|
picker = true,
|
||||||
|
float = {
|
||||||
|
maxwidth = 80,
|
||||||
|
maxheight = 40,
|
||||||
|
border = "rounded",
|
||||||
|
title = true,
|
||||||
|
style = "minimal",
|
||||||
|
auto_focus = true,
|
||||||
|
anchor = "bottom_right",
|
||||||
|
offset = { row = -2, col = -2 },
|
||||||
|
},
|
||||||
|
window = {
|
||||||
|
width = 0.4,
|
||||||
|
height = 0.25,
|
||||||
|
position = "bottom|right",
|
||||||
|
floating = false,
|
||||||
|
border = "none",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
integrations = {
|
||||||
|
treesitter = {
|
||||||
|
enabled = true, -- Enable Treesitter integration
|
||||||
|
highlight = true, -- Enable syntax highlighting
|
||||||
|
langs = { -- Language mapping for different doc types
|
||||||
|
lsp = "markdown",
|
||||||
|
help = "vimdoc",
|
||||||
|
-- Remove man from default treesitter langs since it's not commonly available
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sources = {
|
||||||
|
lsp = { enabled = true },
|
||||||
|
vim = { enabled = true },
|
||||||
|
man = { enabled = true },
|
||||||
|
},
|
||||||
|
priority = { "LSP", "Vim", "Man" },
|
||||||
|
mappings = {
|
||||||
|
close = "<leader>dc",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local valid_positions = {
|
||||||
|
horizontal = { top = true, bottom = true },
|
||||||
|
vertical = { left = true, right = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
function M.setup(opts)
|
||||||
|
-- Validate split positions if provided
|
||||||
|
if opts and opts.display and opts.display.window and opts.display.window.position then
|
||||||
|
local pos = opts.display.window.position
|
||||||
|
if pos:find("|") then
|
||||||
|
local vsplit, hsplit = pos:match("([^|]+)|([^|]+)")
|
||||||
|
if not (valid_positions.vertical[vsplit] and valid_positions.horizontal[hsplit]) and
|
||||||
|
not (valid_positions.horizontal[vsplit] and valid_positions.vertical[hsplit]) then
|
||||||
|
error("Invalid position combination: " .. pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
M.options = vim.tbl_deep_extend("force", defaults, opts or {})
|
||||||
|
end
|
||||||
|
|
||||||
|
M.setup()
|
||||||
|
|
||||||
|
return M
|
31
lua/odis/health.lua
Normal file
31
lua/odis/health.lua
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
local M = {}
|
||||||
|
|
||||||
|
local health = vim.health or require("health")
|
||||||
|
|
||||||
|
function M.check()
|
||||||
|
health.report_start("odis.nvim")
|
||||||
|
|
||||||
|
-- Check for required dependencies
|
||||||
|
if vim.fn.executable("man") == 1 then
|
||||||
|
health.report_ok("man command is available")
|
||||||
|
else
|
||||||
|
health.report_warn("man command not found, man page documentation will be disabled")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check LSP
|
||||||
|
if #vim.lsp.get_active_clients() > 0 then
|
||||||
|
health.report_ok("LSP clients are active")
|
||||||
|
else
|
||||||
|
health.report_info("No active LSP clients found")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check UI requirements
|
||||||
|
local has_notify, _ = pcall(require, "notify")
|
||||||
|
if has_notify then
|
||||||
|
health.report_ok("nvim-notify is available")
|
||||||
|
else
|
||||||
|
health.report_info("nvim-notify not found, falling back to vim.notify")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
51
lua/odis/init.lua
Normal file
51
lua/odis/init.lua
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
local M = {}
|
||||||
|
local config = require("odis.config")
|
||||||
|
local window = require("odis.window")
|
||||||
|
local sources = require("odis.sources")
|
||||||
|
|
||||||
|
function M.setup(opts)
|
||||||
|
config.setup(opts)
|
||||||
|
if not M._maps_setup then
|
||||||
|
vim.keymap.set('n', config.options.mappings.close, window.close_window, { silent = true })
|
||||||
|
M._maps_setup = true
|
||||||
|
end
|
||||||
|
M.options = config.options
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Re-export modes
|
||||||
|
M.modes = config.modes
|
||||||
|
|
||||||
|
function M.show_documentation(display_mode, override_word)
|
||||||
|
local word = override_word or vim.fn.expand("<cword>")
|
||||||
|
if word == "" then return end
|
||||||
|
|
||||||
|
display_mode = display_mode or config.options.display.default_mode
|
||||||
|
|
||||||
|
sources.get_documentation(word, function(found_sources)
|
||||||
|
if #found_sources == 1 or not config.options.display.picker then
|
||||||
|
local source = found_sources[1]
|
||||||
|
local handlers = {
|
||||||
|
LSP = function() sources.display_documentation(source.doc, display_mode, "LSP") end,
|
||||||
|
Man = function() sources.display_man_page(word, display_mode) end,
|
||||||
|
Vim = function() sources.display_vim_help(word, display_mode) end,
|
||||||
|
}
|
||||||
|
if handlers[source.name] then handlers[source.name]() end
|
||||||
|
else
|
||||||
|
vim.ui.select(found_sources, {
|
||||||
|
prompt = "Select documentation source:",
|
||||||
|
format_item = function(item) return item.name end,
|
||||||
|
kind = "documentation_source"
|
||||||
|
}, function(choice)
|
||||||
|
if not choice then return end
|
||||||
|
local handlers = {
|
||||||
|
LSP = function() sources.display_documentation(choice.doc, display_mode, "LSP") end,
|
||||||
|
Man = function() sources.display_man_page(word, display_mode) end,
|
||||||
|
Vim = function() sources.display_vim_help(word, display_mode) end,
|
||||||
|
}
|
||||||
|
if handlers[choice.name] then handlers[choice.name]() end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
221
lua/odis/sources.lua
Normal file
221
lua/odis/sources.lua
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
local M = {}
|
||||||
|
local config = require("odis.config")
|
||||||
|
local window = require("odis.window")
|
||||||
|
local utils = require("odis.utils")
|
||||||
|
|
||||||
|
function M.display_documentation(doc_lines, display_mode, source_type)
|
||||||
|
if not doc_lines or #doc_lines == 0 then return false end
|
||||||
|
|
||||||
|
if display_mode == config.modes.float then
|
||||||
|
return window.display_float(doc_lines, {
|
||||||
|
title = string.format(" %s Documentation ", source_type),
|
||||||
|
filetype = source_type:lower(),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local buf = vim.api.nvim_create_buf(false, true)
|
||||||
|
vim.api.nvim_buf_set_lines(buf, 0, -1, false, doc_lines)
|
||||||
|
|
||||||
|
for opt, value in pairs(window.buf_opts) do
|
||||||
|
vim.api.nvim_buf_set_option(buf, opt, value)
|
||||||
|
end
|
||||||
|
vim.api.nvim_buf_set_option(buf, "filetype", source_type:lower())
|
||||||
|
utils.setup_treesitter(buf, source_type)
|
||||||
|
|
||||||
|
return window.create_documentation_window(buf, display_mode, source_type or "generic")
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.display_vim_help(word, display_mode)
|
||||||
|
if display_mode == config.modes.float then
|
||||||
|
local ok, _ = pcall(vim.cmd, "help " .. word)
|
||||||
|
if not ok then return false end
|
||||||
|
|
||||||
|
local help_buf = vim.api.nvim_get_current_buf()
|
||||||
|
local cursor_pos = vim.api.nvim_win_get_cursor(0)
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(help_buf, 0, -1, false)
|
||||||
|
vim.cmd("bdelete " .. help_buf)
|
||||||
|
|
||||||
|
local win, buf = window.display_float(lines, {
|
||||||
|
title = " Vim Help: " .. word .. " ",
|
||||||
|
filetype = "help",
|
||||||
|
})
|
||||||
|
|
||||||
|
if win then
|
||||||
|
vim.api.nvim_win_set_cursor(win, cursor_pos)
|
||||||
|
vim.api.nvim_win_call(win, function()
|
||||||
|
vim.cmd("normal! gg")
|
||||||
|
vim.cmd("/" .. vim.fn.escape(word, "/\\"))
|
||||||
|
vim.cmd("normal! zz")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return win, buf
|
||||||
|
end
|
||||||
|
|
||||||
|
local buf = vim.api.nvim_create_buf(false, true)
|
||||||
|
local ok, _ = pcall(vim.cmd, "help " .. word)
|
||||||
|
if not ok then return false end
|
||||||
|
|
||||||
|
local help_buf = vim.api.nvim_get_current_buf()
|
||||||
|
local cursor_pos = vim.api.nvim_win_get_cursor(0)
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(help_buf, 0, -1, false)
|
||||||
|
vim.cmd("bdelete " .. help_buf)
|
||||||
|
|
||||||
|
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
|
||||||
|
for opt, value in pairs(window.buf_opts) do
|
||||||
|
vim.api.nvim_buf_set_option(buf, opt, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.api.nvim_buf_set_option(buf, "filetype", "help")
|
||||||
|
vim.api.nvim_buf_set_option(buf, "iskeyword", "!-~,^*,^|,^\"")
|
||||||
|
vim.api.nvim_buf_set_option(buf, "tabstop", 8)
|
||||||
|
|
||||||
|
local win = window.create_documentation_window(buf, display_mode, "vim")
|
||||||
|
if win then
|
||||||
|
vim.api.nvim_win_set_option(win, "conceallevel", 2)
|
||||||
|
vim.api.nvim_win_set_option(win, "concealcursor", "nc")
|
||||||
|
vim.api.nvim_win_set_option(win, "spell", false)
|
||||||
|
|
||||||
|
vim.api.nvim_win_set_cursor(win, cursor_pos)
|
||||||
|
vim.api.nvim_win_call(win, function()
|
||||||
|
vim.cmd("normal! gg")
|
||||||
|
vim.cmd("/" .. vim.fn.escape(word, "/\\"))
|
||||||
|
vim.cmd("normal! zz")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return win
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.display_man_page(word, display_mode)
|
||||||
|
if display_mode == config.modes.float then
|
||||||
|
vim.cmd("Man " .. word)
|
||||||
|
local man_buf = vim.api.nvim_get_current_buf()
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(man_buf, 0, -1, false)
|
||||||
|
vim.cmd("bdelete")
|
||||||
|
|
||||||
|
return window.display_float(lines, {
|
||||||
|
title = " Man: " .. word .. " ",
|
||||||
|
filetype = "man",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local buf = vim.api.nvim_create_buf(false, true)
|
||||||
|
vim.cmd("Man " .. word)
|
||||||
|
local man_buf = vim.api.nvim_get_current_buf()
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(man_buf, 0, -1, false)
|
||||||
|
vim.cmd("bdelete")
|
||||||
|
|
||||||
|
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
|
||||||
|
for opt, value in pairs(window.buf_opts) do
|
||||||
|
vim.api.nvim_buf_set_option(buf, opt, value)
|
||||||
|
end
|
||||||
|
vim.api.nvim_buf_set_option(buf, "filetype", "man")
|
||||||
|
|
||||||
|
return window.create_documentation_window(buf, display_mode, "man")
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.get_documentation(word, callback)
|
||||||
|
local sources = {}
|
||||||
|
local opts = config.options.sources
|
||||||
|
local pending = 0
|
||||||
|
local completed = false
|
||||||
|
|
||||||
|
-- Track enabled sources
|
||||||
|
local enabled_count = 0
|
||||||
|
if opts.vim.enabled then enabled_count = enabled_count + 1 end
|
||||||
|
if opts.man.enabled then enabled_count = enabled_count + 1 end
|
||||||
|
if opts.lsp.enabled then enabled_count = enabled_count + 1 end
|
||||||
|
|
||||||
|
-- Early return if no sources are enabled
|
||||||
|
if enabled_count == 0 then
|
||||||
|
vim.notify("No documentation sources are enabled", vim.log.levels.WARN)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local function process_sources()
|
||||||
|
if completed and pending == 0 then
|
||||||
|
if #sources > 0 then
|
||||||
|
local priority_map = {}
|
||||||
|
for i, p in ipairs(config.options.priority) do
|
||||||
|
priority_map[p:lower()] = i
|
||||||
|
end
|
||||||
|
table.sort(sources, function(a, b)
|
||||||
|
return (priority_map[a.name:lower()] or 99) < (priority_map[b.name:lower()] or 99)
|
||||||
|
end)
|
||||||
|
callback(sources)
|
||||||
|
else
|
||||||
|
vim.notify("No documentation available for '" .. word .. "'", vim.log.levels.INFO)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Vim help check
|
||||||
|
if opts.vim.enabled then
|
||||||
|
pending = pending + 1
|
||||||
|
vim.schedule(function()
|
||||||
|
local temp_buf = vim.api.nvim_create_buf(false, true)
|
||||||
|
local ok = pcall(function()
|
||||||
|
vim.api.nvim_set_current_buf(temp_buf)
|
||||||
|
vim.cmd("help " .. word)
|
||||||
|
local help_buf = vim.api.nvim_get_current_buf()
|
||||||
|
if help_buf ~= temp_buf then
|
||||||
|
local lines = vim.api.nvim_buf_get_lines(help_buf, 0, -1, false)
|
||||||
|
if #lines > 0 then
|
||||||
|
table.insert(sources, { name = "Vim", doc = lines })
|
||||||
|
end
|
||||||
|
vim.cmd(help_buf .. "bdelete!")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
vim.cmd(temp_buf .. "bdelete!")
|
||||||
|
pending = pending - 1
|
||||||
|
process_sources()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Man page check
|
||||||
|
if opts.man.enabled then
|
||||||
|
pending = pending + 1
|
||||||
|
vim.fn.jobstart({"man", "-P", "cat", word}, {
|
||||||
|
stdout_buffered = true,
|
||||||
|
on_stdout = function(_, data)
|
||||||
|
if data and #data > 1 then
|
||||||
|
table.insert(sources, { name = "Man", doc = data })
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
on_exit = function(_, code)
|
||||||
|
vim.schedule(function()
|
||||||
|
pending = pending - 1
|
||||||
|
process_sources()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- LSP documentation
|
||||||
|
if opts.lsp.enabled then
|
||||||
|
local clients = vim.lsp.get_active_clients({ bufnr = 0 })
|
||||||
|
for _, client in ipairs(clients) do
|
||||||
|
if client.server_capabilities.hoverProvider then
|
||||||
|
pending = pending + 1
|
||||||
|
local params = vim.lsp.util.make_position_params()
|
||||||
|
vim.lsp.buf_request(0, "textDocument/hover", params, function(_, result)
|
||||||
|
if result and result.contents then
|
||||||
|
local doc_lines = vim.lsp.util.convert_input_to_markdown_lines(result.contents)
|
||||||
|
if doc_lines and #doc_lines > 0 then
|
||||||
|
table.insert(sources, { name = "LSP", doc = doc_lines })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
pending = pending - 1
|
||||||
|
process_sources()
|
||||||
|
end)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
completed = true
|
||||||
|
process_sources()
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
54
lua/odis/utils.lua
Normal file
54
lua/odis/utils.lua
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
local M = {}
|
||||||
|
local config = require("odis.config")
|
||||||
|
|
||||||
|
function M.setup_treesitter(buf, source_type)
|
||||||
|
if not config.options.integrations.treesitter.enabled then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Skip treesitter for source types that don't need it
|
||||||
|
if source_type:lower() == "man" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local has_ts, ts = pcall(require, "nvim-treesitter")
|
||||||
|
if not has_ts then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local lang = config.options.integrations.treesitter.langs[source_type:lower()]
|
||||||
|
if not lang then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, parser_ok = pcall(vim.treesitter.language.inspect, lang)
|
||||||
|
if ok and parser_ok and config.options.integrations.treesitter.highlight then
|
||||||
|
vim.api.nvim_buf_set_option(buf, "syntax", "") -- Disable regular syntax
|
||||||
|
pcall(vim.treesitter.start, buf, lang) -- Enable treesitter highlighting
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Escape special pattern characters in a string
|
||||||
|
function M.escape_pattern(text)
|
||||||
|
return text:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Safe string split with fallback
|
||||||
|
function M.split(str, sep)
|
||||||
|
if str == nil then return {} end
|
||||||
|
if sep == nil then sep = "%s" end
|
||||||
|
local t = {}
|
||||||
|
for s in string.gmatch(str, "([^"..sep.."]+)") do
|
||||||
|
table.insert(t, s)
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if a source type needs syntax highlighting
|
||||||
|
function M.needs_highlighting(source_type)
|
||||||
|
return source_type:lower() ~= "man" and
|
||||||
|
config.options.integrations.treesitter.enabled and
|
||||||
|
config.options.integrations.treesitter.highlight
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
223
lua/odis/window.lua
Normal file
223
lua/odis/window.lua
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
local M = {}
|
||||||
|
local config = require("odis.config")
|
||||||
|
local utils = require("odis.utils")
|
||||||
|
|
||||||
|
M.state = {
|
||||||
|
windows = {}, -- Stack of {win = win_id, buf = buf_id, mode = display_mode}
|
||||||
|
}
|
||||||
|
|
||||||
|
M.buf_opts = {
|
||||||
|
modified = false,
|
||||||
|
modifiable = false,
|
||||||
|
buftype = "nofile",
|
||||||
|
bufhidden = "wipe",
|
||||||
|
swapfile = false,
|
||||||
|
buflisted = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
M.win_opts = {
|
||||||
|
wrap = true,
|
||||||
|
number = false,
|
||||||
|
relativenumber = false,
|
||||||
|
cursorline = false,
|
||||||
|
signcolumn = "no",
|
||||||
|
}
|
||||||
|
|
||||||
|
function M.track_window(win, buf, display_mode)
|
||||||
|
if win then
|
||||||
|
table.insert(M.state.windows, {
|
||||||
|
win = win,
|
||||||
|
buf = buf,
|
||||||
|
mode = display_mode
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.close_window()
|
||||||
|
local last = M.state.windows[#M.state.windows]
|
||||||
|
if not last or not vim.api.nvim_win_is_valid(last.win) then
|
||||||
|
table.remove(M.state.windows)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if last.mode == config.modes.buffer then
|
||||||
|
vim.cmd("buffer #")
|
||||||
|
else
|
||||||
|
vim.api.nvim_win_close(last.win, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.remove(M.state.windows)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.calculate_float_position(width, height, cfg)
|
||||||
|
local editor_height = vim.api.nvim_get_option("lines")
|
||||||
|
local editor_width = vim.api.nvim_get_option("columns")
|
||||||
|
local pos = {}
|
||||||
|
|
||||||
|
local border_space = cfg.border ~= "none" and 2 or 0
|
||||||
|
width = width + border_space
|
||||||
|
height = height + border_space
|
||||||
|
|
||||||
|
if cfg.anchor == "cursor" then
|
||||||
|
pos = {
|
||||||
|
relative = "cursor",
|
||||||
|
row = cfg.offset.row,
|
||||||
|
col = cfg.offset.col,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pos = {
|
||||||
|
relative = "editor",
|
||||||
|
row = 0,
|
||||||
|
col = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.anchor == "bottom_right" then
|
||||||
|
pos.row = editor_height - height - 2 + cfg.offset.row
|
||||||
|
pos.col = editor_width - width - 2 + cfg.offset.col
|
||||||
|
elseif cfg.anchor == "bottom_left" then
|
||||||
|
pos.row = editor_height - height - 2 + cfg.offset.row
|
||||||
|
pos.col = 1 + cfg.offset.col
|
||||||
|
elseif cfg.anchor == "top_right" then
|
||||||
|
pos.row = 1 + cfg.offset.row
|
||||||
|
pos.col = editor_width - width - 2 + cfg.offset.col
|
||||||
|
elseif cfg.anchor == "top_left" then
|
||||||
|
pos.row = 1 + cfg.offset.row
|
||||||
|
pos.col = 1 + cfg.offset.col
|
||||||
|
end
|
||||||
|
|
||||||
|
pos.row = math.max(0, math.min(pos.row, editor_height - height - 2))
|
||||||
|
pos.col = math.max(0, math.min(pos.col, editor_width - width - 2))
|
||||||
|
end
|
||||||
|
|
||||||
|
return pos
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.display_float(content, opts)
|
||||||
|
local float_config = config.options.display.float
|
||||||
|
local buf = vim.api.nvim_create_buf(false, true)
|
||||||
|
|
||||||
|
content = type(content) == "string" and vim.split(content, "\n") or content
|
||||||
|
vim.api.nvim_buf_set_lines(buf, 0, -1, false, content)
|
||||||
|
|
||||||
|
for k, v in pairs(M.buf_opts) do
|
||||||
|
vim.api.nvim_buf_set_option(buf, k, v)
|
||||||
|
end
|
||||||
|
|
||||||
|
local max_content_width = 0
|
||||||
|
for _, line in ipairs(content) do
|
||||||
|
max_content_width = math.max(max_content_width, vim.fn.strdisplaywidth(line))
|
||||||
|
end
|
||||||
|
|
||||||
|
local width = math.min(max_content_width + 2, float_config.maxwidth)
|
||||||
|
local height = math.min(#content, float_config.maxheight)
|
||||||
|
local pos = M.calculate_float_position(width, height, float_config)
|
||||||
|
|
||||||
|
local win = vim.api.nvim_open_win(buf, float_config.auto_focus, {
|
||||||
|
relative = pos.relative,
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
row = pos.row,
|
||||||
|
col = pos.col,
|
||||||
|
style = float_config.style,
|
||||||
|
border = float_config.border,
|
||||||
|
zindex = 50,
|
||||||
|
title = (float_config.title and opts and opts.title) and opts.title or nil,
|
||||||
|
title_pos = "center",
|
||||||
|
focusable = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
for k, v in pairs(M.win_opts) do
|
||||||
|
pcall(vim.api.nvim_win_set_option, win, k, v)
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.api.nvim_win_set_option(win, "winhighlight", "NormalFloat:Normal")
|
||||||
|
|
||||||
|
if opts and opts.filetype then
|
||||||
|
vim.api.nvim_buf_set_option(buf, "filetype", opts.filetype)
|
||||||
|
utils.setup_treesitter(buf, opts.filetype)
|
||||||
|
end
|
||||||
|
|
||||||
|
M.track_window(win, buf, config.modes.float)
|
||||||
|
return win, buf
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.setup_window_options(win, source_type, buf)
|
||||||
|
for k, v in pairs(M.win_opts) do
|
||||||
|
pcall(vim.api.nvim_win_set_option, win, k, v)
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.options.mappings.close then
|
||||||
|
vim.keymap.set("n", config.options.mappings.close, M.close_window, { buffer = buf, silent = true })
|
||||||
|
end
|
||||||
|
|
||||||
|
M.track_window(win, buf, source_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.get_split_position(display_mode, window_config)
|
||||||
|
local position = window_config.position
|
||||||
|
if position:find("|") then
|
||||||
|
local pos1, pos2 = position:match("([^|]+)|([^|]+)")
|
||||||
|
if display_mode == config.modes.vsplit then
|
||||||
|
return pos1 == "left" or pos1 == "right" and pos1 or pos2
|
||||||
|
else
|
||||||
|
return pos1 == "top" or pos1 == "bottom" and pos1 or pos2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return position
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.create_documentation_window(buf, display_mode, source_type)
|
||||||
|
local window_config = config.options.display.window
|
||||||
|
local cur_win = vim.api.nvim_get_current_win()
|
||||||
|
local win
|
||||||
|
|
||||||
|
if display_mode == config.modes.buffer then
|
||||||
|
M.state.origin_buf = vim.api.nvim_get_current_buf()
|
||||||
|
vim.api.nvim_win_set_buf(cur_win, buf)
|
||||||
|
win = cur_win
|
||||||
|
elseif display_mode == config.modes.tab then
|
||||||
|
vim.cmd("tabnew")
|
||||||
|
win = vim.api.nvim_get_current_win()
|
||||||
|
vim.api.nvim_win_set_buf(win, buf)
|
||||||
|
else
|
||||||
|
local dimensions = {
|
||||||
|
width = math.floor(vim.api.nvim_win_get_width(cur_win) * window_config.width),
|
||||||
|
height = math.floor(vim.api.nvim_win_get_height(cur_win) * window_config.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
if window_config.floating and window_config.border and window_config.border ~= "none" then
|
||||||
|
win = vim.api.nvim_open_win(buf, true, {
|
||||||
|
relative = 'editor',
|
||||||
|
width = dimensions.width,
|
||||||
|
height = dimensions.height,
|
||||||
|
border = window_config.border,
|
||||||
|
style = 'minimal',
|
||||||
|
title = " Documentation ",
|
||||||
|
title_pos = "center",
|
||||||
|
})
|
||||||
|
else
|
||||||
|
local position = M.get_split_position(display_mode, window_config)
|
||||||
|
local split_cmd = display_mode == config.modes.vsplit and
|
||||||
|
(position == "right" and "rightbelow vsplit" or "leftabove vsplit") or
|
||||||
|
(position == "bottom" and "rightbelow split" or "leftabove split")
|
||||||
|
|
||||||
|
vim.cmd(split_cmd)
|
||||||
|
win = vim.api.nvim_get_current_win()
|
||||||
|
vim.api.nvim_win_set_buf(win, buf)
|
||||||
|
|
||||||
|
local resize_cmd = display_mode == config.modes.vsplit and
|
||||||
|
"vertical resize " .. dimensions.width or
|
||||||
|
"resize " .. dimensions.height
|
||||||
|
vim.cmd(resize_cmd)
|
||||||
|
|
||||||
|
for k, v in pairs(M.win_opts) do
|
||||||
|
pcall(vim.api.nvim_win_set_option, win, k, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
M.setup_window_options(win, display_mode, buf)
|
||||||
|
return win
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
Loading…
x
Reference in New Issue
Block a user