Skip to content

Commit

Permalink
Merge pull request #47 from max397574/push-pyxwrotrozzo
Browse files Browse the repository at this point in the history
Add docs view
  • Loading branch information
max397574 authored Jul 14, 2024
2 parents 2c407a5 + 5cf3f93 commit 9d4fd1d
Show file tree
Hide file tree
Showing 12 changed files with 307 additions and 126 deletions.
4 changes: 3 additions & 1 deletion docs/config.norg
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ tangle: {
delimiter: none
}
created: 2023-11-17T16:29:17+0100
updated: 2024-06-22T17:04:13+0100
updated: 2024-07-13T10:21:09+0100
version: 1.1.1
@end

Expand Down Expand Up @@ -201,6 +201,8 @@ version: 1.1.1
@code lua
--- Maximum height of the documentation view
---@field max_height integer
--- Maximum width of the documentation view
---@field max_width integer
--- The border of the documentation view
---@field border string|string[]|string[][]
--- Character used for the scrollbar
Expand Down
30 changes: 27 additions & 3 deletions docs/menu.norg
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ categories: [
types
]
created: 2024-05-29T11:30:25+0100
updated: 2024-07-10T19:00:55+0100
updated: 2024-07-14T08:43:31+0100
tangle: {
languages: {
lua: ../lua/neocomplete/types/menu.lua
Expand Down Expand Up @@ -134,13 +134,37 @@ version: 1.1.1
---@field readjust_win fun(self: neocomplete.menu, offset: integer): nil
@end

** Docs Visible
Checks whether docs are visible or not
#tangle
@code lua
--- Checks if docs are open
---@field docs_visible fun(self: neocomplete.menu): boolean
@end

** Scroll docs
Scroll up or down in the docs window by `delta` lines.
#tangle
@code lua
--- Scroll in the docs window
---@field scroll_docs fun(self: neocomplete.menu, delta: integer): nil
@end

* Fields
** Window
** Menu Window
#tangle
@code lua
--- Wrapper for utilities for the window of the menu
---@field window neocomplete.menu_window
---@field menu_window neocomplete.window
@end

** Docs Window
#tangle
@code lua
--- Wrapper for utilities for the window of the docs
---@field docs_window neocomplete.window
@end

** Entries
This field is used to store all the entries of the completion menu.
#tangle
Expand Down
3 changes: 2 additions & 1 deletion lua/neocomplete/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ config.defaults = {
alignment = {},
},
docs_view = {
max_height = 7,
max_height = 8,
max_width = 80,
border = "rounded",
scrollbar = "",
},
Expand Down
6 changes: 6 additions & 0 deletions lua/neocomplete/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ neocomplete.api = {
jump_to_entry = function(index)
neocomplete.core.menu.index = index
end,
doc_is_open = function()
return neocomplete.core and neocomplete.core.menu and neocomplete.core.menu:docs_visible()
end,
scroll_docs = function(delta)
neocomplete.core.menu:scroll_docs(delta)
end,
}

--- Sets up neocomplete
Expand Down
36 changes: 7 additions & 29 deletions lua/neocomplete/menu/draw.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,16 @@ return function(self)
local width, entry_texts = format_utils.get_width(self.entries)
local aligned_table = format_utils.get_align_tables(self.entries)
local column = 0
vim.api.nvim_buf_clear_namespace(self.buf, self.ns, 0, -1)
vim.api.nvim_buf_clear_namespace(self.scrollbar_buf, self.ns, 0, -1)
vim.api.nvim_buf_clear_namespace(self.menu_window.buf, self.ns, 0, -1)
local spaces = {}
for _ = 1, #self.entries do
table.insert(spaces, (" "):rep(width))
end
vim.api.nvim_buf_set_lines(self.buf, 0, -1, false, spaces)
vim.api.nvim_buf_set_lines(self.menu_window.buf, 0, -1, false, spaces)
if self.index and self.index > 0 then
for i = 0, #self.entries do
if i == self.index then
vim.api.nvim_buf_set_extmark(self.buf, self.ns, i - 1, 0, {
vim.api.nvim_buf_set_extmark(self.menu_window.buf, self.ns, i - 1, 0, {
virt_text = { { string.rep(" ", width), "@neocomplete.selected" } },
virt_text_pos = "overlay",
})
Expand All @@ -66,7 +65,7 @@ return function(self)
end
local cur_line_text = table.concat(line_text, "")
table.insert(texts, cur_line_text)
vim.api.nvim_buf_set_extmark(self.buf, self.ns, line - 1, column, {
vim.api.nvim_buf_set_extmark(self.menu_window.buf, self.ns, line - 1, column, {
virt_text = aligned_chunks,
virt_text_pos = "overlay",
hl_mode = "combine",
Expand All @@ -78,44 +77,23 @@ return function(self)
local length = utils.longest(texts)
add_extmarks(aligned_sec, function(chunk)
return { string.rep(" ", length - #chunk[1]) .. chunk[1], chunk[2] }
end, self.buf, self.ns, column)
end, self.menu_window.buf, self.ns, column)
column = column + length
elseif alignment[i] == "center" then
local texts = get_texts(aligned_sec)
local length = utils.longest(texts)
add_extmarks(aligned_sec, function(chunk)
return { string.rep(" ", math.floor((length - #chunk[1]) / 2)) .. chunk[1], chunk[2] }
end, self.buf, self.ns, column)
end, self.menu_window.buf, self.ns, column)
column = column + length
end
end
for line, entry in ipairs(self.entries) do
for _, idx in ipairs(entry.matches or {}) do
vim.api.nvim_buf_add_highlight(self.buf, self.ns, "@neocomplete.match", line - 1, idx - 1, idx)
vim.api.nvim_buf_add_highlight(self.menu_window.buf, self.ns, "@neocomplete.match", line - 1, idx - 1, idx)
end
end

if not self.window.scrollbar_is_open then
return
end

local top_visible = vim.fn.line("w0", self.window.winnr)
local bottom_visible = vim.fn.line("w$", self.window.winnr)
local visible_entries = bottom_visible - top_visible + 1
if visible_entries >= #self.entries then
return
end
local scrollbar_height =
math.max(math.min(math.floor(visible_entries * (visible_entries / #self.entries) + 0.5), visible_entries), 1)
vim.api.nvim_buf_set_lines(self.scrollbar_buf, 0, -1, false, vim.split(string.rep(" ", visible_entries + 1), ""))
local scrollbar_offset = math.max(math.floor(visible_entries * (top_visible / #self.entries)), 1)
for i = scrollbar_offset, scrollbar_offset + scrollbar_height do
vim.api.nvim_buf_set_extmark(self.scrollbar_buf, self.ns, i - 1, 0, {
virt_text = { { self.config.ui.menu.scrollbar, "PmenuSbar" } },
virt_text_pos = "overlay",
})
end

local line = vim.api.nvim_get_current_line()
local cursor = vim.api.nvim_win_get_cursor(0)
local cursor_col = cursor[2]
Expand Down
119 changes: 107 additions & 12 deletions lua/neocomplete/menu/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,130 @@
---@diagnostic disable-next-line: missing-fields
local Menu = {}

local format_utils = require("neocomplete.utils.format")

function Menu.new()
---@type neocomplete.menu
local self = setmetatable({}, { __index = Menu })
self.entries = nil
self.ns = vim.api.nvim_create_namespace("neocomplete")
self.config = require("neocomplete.config").options
self.buf = vim.api.nvim_create_buf(false, true)
self.index = 0
---@diagnostic disable-next-line: missing-fields
self.scrollbar_buf = vim.api.nvim_create_buf(false, true)
self.window = require("neocomplete.menu.window").new(self.buf, self.scrollbar_buf)
self.menu_window = require("neocomplete.utils.window").new()
self.docs_window = require("neocomplete.utils.window").new()
return self
end

Menu.draw = require("neocomplete.menu.draw")

function Menu:readjust_win(offset)
self.window:readjust(self.entries, offset)
self.index = 0
local width, _ = format_utils.get_width(self.entries)
if not self.entries or #self.entries < 1 then
self.menu_window:close()
return
end
self.menu_window:readjust(#self.entries, width, offset)
self:draw()
self.menu_window:draw_scrollbar()
end

function Menu.close(self)
self.window:close()
self.menu_window:close()
self.docs_window:close()
require("neocomplete.ghost_text").hide()
end

---@param menu neocomplete.menu
local function draw_docs(menu, entry, config)
if not entry then
return
end

local function open_docs_window(doc_entry, x_offset)
if not doc_entry.completion_item.documentation then
return
end
local documentation = doc_entry.completion_item.documentation
local format = "markdown"
local contents
if type(documentation) == "table" and documentation.kind == "plaintext" then
format = "plaintext"
contents = vim.split(documentation.value or "", "\n", { trimempty = true })
else
contents = vim.lsp.util.convert_input_to_markdown_lines(documentation --[[@as string]])
end

local TODO = 100000
local width = math.min(vim.o.columns - x_offset, config.max_width)
local height = math.min(TODO, config.max_height)

local do_stylize = format == "markdown" and vim.g.syntax_on ~= nil

if do_stylize then
contents = vim.lsp.util._normalize_markdown(contents, { width = width })
vim.bo[menu.docs_window.buf].filetype = "markdown"
vim.treesitter.start(menu.docs_window.buf)
vim.api.nvim_buf_set_lines(menu.docs_window.buf, 0, -1, false, contents)
else
-- Clean up input: trim empty lines
contents = vim.split(table.concat(contents, "\n"), "\n", { trimempty = true })

if format then
vim.bo[menu.docs_window.buf].syntax = format
end
vim.api.nvim_buf_set_lines(menu.docs_window.buf, 0, -1, true, contents)
end

menu.docs_window:open_cursor_relative(width, height, -x_offset)
menu.docs_window:draw_scrollbar()

vim.api.nvim_set_option_value("scrolloff", 0, { win = menu.docs_window.winnr })
end

if entry.source.source.resolve_item then
entry.source.source:resolve_item(entry.completion_item, function(resolved_item)
entry.completion_item = resolved_item
open_docs_window(
entry,
menu.menu_window.opened_at.col
+ vim.api.nvim_win_get_width(menu.menu_window.winnr)
- (vim.api.nvim_win_get_cursor(0)[2] - 1)
+ 1
)
end)
else
open_docs_window(
entry,
menu.menu_window.opened_at.col
+ vim.api.nvim_win_get_width(menu.menu_window.winnr)
- (vim.api.nvim_win_get_cursor(0)[2] - 1)
+ 1
)
end
end

function Menu:docs_visible()
return self.docs_window:is_open()
end

function Menu:scroll_docs(delta)
if not self:docs_visible() then
return
end
self.docs_window:scroll(delta)
end

function Menu:select_next(count)
count = count or 1
self.index = self.index + count
if self.index > #self.entries then
self.index = self.index - #self.entries - 1
end
self.window:set_scroll(self.index, 1)
self.menu_window:set_scroll(self.index, 1)
draw_docs(self, self:get_active_entry(), self.config.ui.docs_view)
self:draw()
self.menu_window:draw_scrollbar()
end

function Menu:select_prev(count)
Expand All @@ -44,8 +134,10 @@ function Menu:select_prev(count)
if self.index < 0 then
self.index = #self.entries + self.index + 1
end
self.window:set_scroll(self.index, -1)
self.menu_window:set_scroll(self.index, -1)
draw_docs(self, self:get_active_entry(), self.config.ui.docs_view)
self:draw()
self.menu_window:draw_scrollbar()
end

function Menu:open(entries, offset)
Expand All @@ -57,9 +149,11 @@ function Menu:open(entries, offset)
return
end
self.index = 0
self.window:open_win(entries, offset)
local width, _ = format_utils.get_width(self.entries)
self.menu_window:open_cursor_relative(width, #self.entries, offset)
self:draw()
self.window:set_scroll(self.index, -1)
self.menu_window:draw_scrollbar()
self.menu_window:set_scroll(self.index, -1)
end

function Menu:get_active_entry()
Expand All @@ -83,11 +177,12 @@ function Menu:confirm()
return
end
self:complete(entry)
self.window:close()
self.menu_window:close()
self.docs_window:close()
end

function Menu:is_open()
return self.window:is_open()
return self.menu_window:is_open()
end

return Menu
2 changes: 2 additions & 0 deletions lua/neocomplete/types/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
---@class neocomplete.config.ui.docs
--- Maximum height of the documentation view
---@field max_height integer
--- Maximum width of the documentation view
---@field max_width integer
--- The border of the documentation view
---@field border string|string[]|string[][]
--- Character used for the scrollbar
Expand Down
8 changes: 7 additions & 1 deletion lua/neocomplete/types/menu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,14 @@
---@field complete fun(self: neocomplete.menu, entry: neocomplete.entry): nil
--- Readjust size of completino window
---@field readjust_win fun(self: neocomplete.menu, offset: integer): nil
--- Checks if docs are open
---@field docs_visible fun(self: neocomplete.menu): boolean
--- Scroll in the docs window
---@field scroll_docs fun(self: neocomplete.menu, delta: integer): nil
--- Wrapper for utilities for the window of the menu
---@field window neocomplete.menu_window
---@field menu_window neocomplete.window
--- Wrapper for utilities for the window of the docs
---@field docs_window neocomplete.window
--- Entries of the menu
---@field entries neocomplete.entry[]
--- Namespace used for the menu
Expand Down
27 changes: 0 additions & 27 deletions lua/neocomplete/types/menu_window.lua

This file was deleted.

Loading

0 comments on commit 9d4fd1d

Please sign in to comment.