Update autocomplete with changes needed for latest LSP plugin.

This commit is contained in:
jgmdev 2022-02-03 14:55:01 -04:00
parent af76f544be
commit 6773e85cb8
2 changed files with 130 additions and 46 deletions

View File

@ -19,7 +19,6 @@ config.line_height = 1.2
config.indent_size = 2 config.indent_size = 2
config.tab_type = "soft" config.tab_type = "soft"
config.line_limit = 80 config.line_limit = 80
config.max_symbols = 4000
config.max_project_files = 2000 config.max_project_files = 2000
config.transitions = true config.transitions = true
config.animation_rate = 1.0 config.animation_rate = 1.0
@ -32,11 +31,11 @@ config.max_clicks = 3
config.plugins = {} config.plugins = {}
-- Allow you to set plugin configs even if we haven't seen the plugin before. -- Allow you to set plugin configs even if we haven't seen the plugin before.
setmetatable(config.plugins, { setmetatable(config.plugins, {
__index = function(t, k) __index = function(t, k)
if rawget(t, k) == nil then rawset(t, k, {}) end if rawget(t, k) == nil then rawset(t, k, {}) end
return rawget(t, k) return rawget(t, k)
end end
}) })
-- Disable these plugins by default. -- Disable these plugins by default.

View File

@ -11,12 +11,16 @@ local DocView = require "core.docview"
local Doc = require "core.doc" local Doc = require "core.doc"
config.plugins.autocomplete = common.merge({ config.plugins.autocomplete = common.merge({
-- Amount of characters that need to be written for autocomplete -- Amount of characters that need to be written for autocomplete
min_len = 3, min_len = 3,
-- The max amount of visible items -- The max amount of visible items
max_height = 6, max_height = 6,
-- The max amount of scrollable items -- The max amount of scrollable items
max_suggestions = 100, max_suggestions = 100,
-- Maximum amount of symbols to cache per document
max_symbols = 4000,
-- Font size of the description box
desc_font_size = 12
}, config.plugins.autocomplete) }, config.plugins.autocomplete)
local autocomplete = {} local autocomplete = {}
@ -33,7 +37,7 @@ local triggered_manually = false
local mt = { __tostring = function(t) return t.text end } local mt = { __tostring = function(t) return t.text end }
function autocomplete.add(t, triggered_manually) function autocomplete.add(t, manually_triggered)
local items = {} local items = {}
for text, info in pairs(t.items) do for text, info in pairs(t.items) do
if type(info) == "table" then if type(info) == "table" then
@ -43,9 +47,10 @@ function autocomplete.add(t, triggered_manually)
{ {
text = text, text = text,
info = info.info, info = info.info,
desc = info.desc, -- Description shown on item selected desc = info.desc, -- Description shown on item selected
cb = info.cb, -- A callback called once when item is selected onhover = info.onhover, -- A callback called once when item is hovered
data = info.data -- Optional data that can be used on cb onselect = info.onselect, -- A callback called when item is selected
data = info.data -- Optional data that can be used on cb
}, },
mt mt
) )
@ -56,7 +61,7 @@ function autocomplete.add(t, triggered_manually)
end end
end end
if not triggered_manually then if not manually_triggered then
autocomplete.map[t.name] = { files = t.files or ".*", items = items } autocomplete.map[t.name] = { files = t.files or ".*", items = items }
else else
autocomplete.map_manually[t.name] = { files = t.files or ".*", items = items } autocomplete.map_manually[t.name] = { files = t.files or ".*", items = items }
@ -66,7 +71,7 @@ end
-- --
-- Thread that scans open document symbols and cache them -- Thread that scans open document symbols and cache them
-- --
local max_symbols = config.max_symbols local max_symbols = config.plugins.autocomplete.max_symbols
core.add_thread(function() core.add_thread(function()
local cache = setmetatable({}, { __mode = "k" }) local cache = setmetatable({}, { __mode = "k" })
@ -85,7 +90,9 @@ core.add_thread(function()
doc.disable_symbols = true doc.disable_symbols = true
core.status_view:show_message("!", style.accent, core.status_view:show_message("!", style.accent,
"Too many symbols in document "..doc.filename.. "Too many symbols in document "..doc.filename..
": stopping auto-complete for this document according to config.max_symbols.") ": stopping auto-complete for this document according to "..
"config.plugins.autocomplete.max_symbols."
)
collectgarbage('collect') collectgarbage('collect')
return {} return {}
end end
@ -159,16 +166,6 @@ local function reset_suggestions()
end end
end end
local function in_table(value, table_array)
for i, element in pairs(table_array) do
if element == value then
return true
end
end
return false
end
local function update_suggestions() local function update_suggestions()
local doc = core.active_view.doc local doc = core.active_view.doc
local filename = doc and doc.filename or "" local filename = doc and doc.filename or ""
@ -199,6 +196,7 @@ local function update_suggestions()
j = j + 1 j = j + 1
end end
end end
suggestions_idx = 1
end end
local function get_partial_symbol() local function get_partial_symbol()
@ -249,6 +247,11 @@ local function get_suggestions_rect(av)
max_width = 150 max_width = 150
end end
-- if portion not visiable to right, reposition to DocView right margin
if (x - av.position.x) + max_width > av.size.x then
x = (av.size.x + av.position.x) - max_width - (style.padding.x * 2)
end
return return
x - style.padding.x, x - style.padding.x,
y - style.padding.y, y - style.padding.y,
@ -256,20 +259,99 @@ local function get_suggestions_rect(av)
max_items * (th + style.padding.y) + style.padding.y max_items * (th + style.padding.y) + style.padding.y
end end
local function wrap_line(line, max_chars)
if #line > max_chars then
local lines = {}
local line_len = #line
local new_line = ""
local prev_char = ""
local position = 0
local indent = line:match("^%s+")
for char in line:gmatch(".") do
position = position + 1
if #new_line < max_chars then
new_line = new_line .. char
prev_char = char
if position >= line_len then
table.insert(lines, new_line)
end
else
if
not prev_char:match("%s")
and
not string.sub(line, position+1, 1):match("%s")
and
position < line_len
then
new_line = new_line .. "-"
end
table.insert(lines, new_line)
if indent then
new_line = indent .. char
else
new_line = char
end
end
end
return lines
end
return line
end
local previous_scale = SCALE
local desc_font = style.code_font:copy(
config.plugins.autocomplete.desc_font_size * SCALE
)
local function draw_description_box(text, av, sx, sy, sw, sh) local function draw_description_box(text, av, sx, sy, sw, sh)
if previous_scale ~= SCALE then
desc_font = style.code_font:copy(
config.plugins.autocomplete.desc_font_size * SCALE
)
previous_scale = SCALE
end
local font = desc_font
local lh = font:get_height()
local y = sy + style.padding.y
local x = sx + sw + style.padding.x / 4
local width = 0 local width = 0
local char_width = font:get_width(" ")
local draw_left = false;
local max_chars = 0
if sx - av.position.x < av.size.x - (sx - av.position.x) - sw then
max_chars = (((av.size.x+av.position.x) - x) / char_width) - 5
else
draw_left = true;
max_chars = (
(sx - av.position.x - (style.padding.x / 4) - style.scrollbar_size)
/ char_width
) - 5
end
local lines = {} local lines = {}
for line in string.gmatch(text.."\n", "(.-)\n") do for line in string.gmatch(text.."\n", "(.-)\n") do
width = math.max(width, style.font:get_width(line)) local wrapper_lines = wrap_line(line, max_chars)
table.insert(lines, line) if type(wrapper_lines) == "table" then
for _, wrapped_line in pairs(wrapper_lines) do
width = math.max(width, font:get_width(wrapped_line))
table.insert(lines, wrapped_line)
end
else
width = math.max(width, font:get_width(line))
table.insert(lines, line)
end
end end
local height = #lines * style.font:get_height() if draw_left then
x = sx - (style.padding.x / 4) - width - (style.padding.x * 2)
end
local height = #lines * font:get_height()
-- draw background rect -- draw background rect
renderer.draw_rect( renderer.draw_rect(
sx + sw + style.padding.x / 4, x,
sy, sy,
width + style.padding.x * 2, width + style.padding.x * 2,
height + style.padding.y * 2, height + style.padding.y * 2,
@ -277,13 +359,10 @@ local function draw_description_box(text, av, sx, sy, sw, sh)
) )
-- draw text -- draw text
local lh = style.font:get_height()
local y = sy + style.padding.y
local x = sx + sw + style.padding.x / 4
for _, line in pairs(lines) do for _, line in pairs(lines) do
common.draw_text( common.draw_text(
style.font, style.text, line, "left", x + style.padding.x, y, width, lh font, style.text, line, "left",
x + style.padding.x, y, width, lh
) )
y = y + lh y = y + lh
end end
@ -320,10 +399,9 @@ local function draw_suggestions_box(av)
end end
y = y + lh y = y + lh
if suggestions_idx == i then if suggestions_idx == i then
if s.cb then if s.onhover then
s.cb(suggestions_idx, s) s.onhover(suggestions_idx, s)
s.cb = nil s.onhover = nil
s.data = nil
end end
if s.desc and #s.desc > 0 then if s.desc and #s.desc > 0 then
draw_description_box(s.desc, av, rx, ry, rw, rh) draw_description_box(s.desc, av, rx, ry, rw, rh)
@ -487,10 +565,17 @@ command.add(predicate, {
["autocomplete:complete"] = function() ["autocomplete:complete"] = function()
local doc = core.active_view.doc local doc = core.active_view.doc
local line, col = doc:get_selection() local line, col = doc:get_selection()
local text = suggestions[suggestions_idx].text local item = suggestions[suggestions_idx]
doc:insert(line, col, text) local text = item.text
doc:remove(line, col, line, col - #partial) local inserted = false
doc:set_selection(line, col + #text - #partial) if item.onselect then
inserted = item.onselect(suggestions_idx, item)
end
if not inserted then
doc:insert(line, col, text)
doc:remove(line, col, line, col - #partial)
doc:set_selection(line, col + #text - #partial)
end
reset_suggestions() reset_suggestions()
end, end,