mirror of
https://github.com/zyedidia/micro.git
synced 2025-06-18 23:05:40 -04:00
145 lines
3.2 KiB
Lua
145 lines
3.2 KiB
Lua
VERSION = "1.0.0"
|
|
|
|
local micro = import("micro")
|
|
local config = import("micro/config")
|
|
local buffer = import("micro/buffer")
|
|
local overlay = import("micro/overlay")
|
|
|
|
|
|
-- Immediate-mode event handling
|
|
|
|
local overlay_handle = nil
|
|
local event_count = 0
|
|
local events = {}
|
|
local tracked_events = {}
|
|
|
|
function track_event(name, block)
|
|
-- Registers a global handler for an event
|
|
-- If "no_block" is passed as the second argument,
|
|
-- the event will not be prevented.
|
|
|
|
local full_name = "pre" .. name
|
|
if block=="no_block" then
|
|
full_name = "on"..name
|
|
end
|
|
|
|
if not tracked_events[full_name] then
|
|
tracked_events[full_name] = true
|
|
|
|
if block~="no_block" then
|
|
_G[full_name] = function()
|
|
if overlay_handle then
|
|
events[name] = true
|
|
event_count = event_count + 1
|
|
end
|
|
end
|
|
else
|
|
_G[full_name] = function()
|
|
if overlay_handle then
|
|
events[name] = true
|
|
event_count = event_count + 1
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function untrack_events()
|
|
-- Removes all global event handlers
|
|
for e, _ in pairs(tracked_events) do
|
|
_G[e] = nil
|
|
end
|
|
tracked_events = {}
|
|
end
|
|
|
|
function reset_events()
|
|
-- Resets tracked events between redraws
|
|
events = {}
|
|
event_count = 0
|
|
end
|
|
|
|
function event(event_name, block)
|
|
-- Returns true if the event has occured.
|
|
track_event(event_name, block)
|
|
return events[event_name] or false
|
|
end
|
|
|
|
function close_overlay()
|
|
-- Closes the overlay and untracks all events.
|
|
untrack_events()
|
|
overlay.DestroyOverlay(overlay_handle)
|
|
overlay_handle = nil
|
|
end
|
|
|
|
function max_len(iter)
|
|
-- Returns the length of the longest string in iterable
|
|
local max = 0
|
|
for _, item in iter do
|
|
max = math.max(max, #item)
|
|
end
|
|
return max
|
|
end
|
|
|
|
function draw_autocomplete_overlay()
|
|
local bp = micro.CurPane()
|
|
local buf = bp.Buf
|
|
|
|
if not buf.HasSuggestions then
|
|
-- If there are no suggestions, we close the overlay.
|
|
close_overlay()
|
|
return
|
|
end
|
|
|
|
-- These events should not close the menu, so we track them, but
|
|
-- we do not block them, because we want autocomplete cycling to work.
|
|
event("CycleAutocomplete", "no_block")
|
|
event("CycleAutocompleteBack", "no_block")
|
|
|
|
-- Positioning adjustment - show the menu below where the cursor
|
|
-- was when autocomplete was initiated by subtracting the length
|
|
-- of the currently applied completion.
|
|
local compl_len = #buf.Completions[buf.CurSuggestion+1] + 1
|
|
|
|
-- Note: The minus dereferences the Loc pointer
|
|
local l = -buf:GetActiveCursor().Loc
|
|
l = overlay.BufPaneScreenLoc(bp, l)
|
|
|
|
local x = l.X-compl_len
|
|
local y = l.Y+1
|
|
|
|
-- Calculate the maximum text width of the options,
|
|
-- add 2 cells of padding
|
|
local w = max_len(buf.Suggestions())+2
|
|
|
|
-- Draw each option, highlight the current option
|
|
local yoff = 0
|
|
local style = overlay.GetColor("cursor-line")
|
|
for i, option in buf.Suggestions() do
|
|
local style = overlay.Style()
|
|
if i == buf.CurSuggestion+1 then
|
|
style = overlay.GetColor("statusline")
|
|
end
|
|
|
|
overlay.DrawText(" "..option, x, y+yoff, w, 1, style)
|
|
yoff = yoff+1
|
|
end
|
|
|
|
reset_events()
|
|
end
|
|
|
|
function init()
|
|
config.AddRuntimeFile("completebox", config.RTHelp, "help/completebox.md")
|
|
end
|
|
|
|
function deinit()
|
|
close_overlay()
|
|
untrack_events()
|
|
end
|
|
|
|
function onAutocomplete()
|
|
if overlay_handle then return end
|
|
reset_events()
|
|
overlay_handle = overlay.CreateOverlay(draw_autocomplete_overlay)
|
|
end
|