add a ui (wip)
This commit is contained in:
30
lua/dep.lua
30
lua/dep.lua
@ -5,6 +5,7 @@ local packager = require("dep.package")
|
||||
local modules = require("dep.modules")
|
||||
local bench = require("dep.bench")
|
||||
local lazy = require("dep.lazy")
|
||||
local ui = require("dep.ui")
|
||||
|
||||
-- all functions for convenience
|
||||
local M = {}
|
||||
@ -143,25 +144,6 @@ return function(opts)
|
||||
end
|
||||
|
||||
-- add some user commands
|
||||
vim.api.nvim_create_user_command("DepLog", function()
|
||||
vim.cmd('vsp '..logger.path)
|
||||
vim.opt_local.readonly = true
|
||||
|
||||
-- make the log auto update while it's open
|
||||
local w = h.uv.new_fs_event()
|
||||
local function watch_file(fname)
|
||||
local fullpath = vim.api.nvim_call_function(
|
||||
'fnamemodify', { fname, ':p' })
|
||||
w:start(fullpath, {}, vim.schedule_wrap(function(...)
|
||||
vim.cmd('checktime')
|
||||
w:stop()
|
||||
watch_file(fname)
|
||||
end))
|
||||
end
|
||||
|
||||
watch_file(logger.path)
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("DepSync", function()
|
||||
synctree(packager.get_packages())
|
||||
end, {})
|
||||
@ -177,5 +159,15 @@ return function(opts)
|
||||
fs:clean(packager)
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("DepUi", function()
|
||||
ui.open(packager)
|
||||
ui.set_page("P")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("DepLog", function()
|
||||
ui.open(packager)
|
||||
ui.set_page("L")
|
||||
end, {})
|
||||
|
||||
logger:cleanup()
|
||||
end
|
||||
|
@ -79,8 +79,8 @@ function logger:log(level, message, ...)
|
||||
|
||||
-- write to the pipe if it's open
|
||||
if logger.pipe then
|
||||
logger.pipe:write(string.format("[%s] %s:%s: %s\n", os.date("%T"),
|
||||
source.short_src:gsub('.*%/', ''), source.currentline, message))
|
||||
logger.pipe:write(string.format("[%s] %s:%s:(%s) %s\n", os.date("%T"),
|
||||
source.short_src:gsub('.*%/', ''), source.currentline, level, message))
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
46
lua/dep/ui/format.lua
Normal file
46
lua/dep/ui/format.lua
Normal file
@ -0,0 +1,46 @@
|
||||
local logger = require("dep.log")
|
||||
|
||||
local format = {}
|
||||
|
||||
--- format a boolean to a chunk with highlights
|
||||
---@param b boolean
|
||||
---@return chunk chunk
|
||||
function format.bool(b)
|
||||
return { vim.inspect(b), b and "DiffAdd" or "DiffDelete" }
|
||||
end
|
||||
|
||||
--- format a number to a chunk with highlights
|
||||
---@param n number
|
||||
---@return chunk chunk
|
||||
function format.number(n)
|
||||
return { vim.inspect(n), "Number" }
|
||||
end
|
||||
|
||||
--- format a log line with highlights
|
||||
---@param log_line string log line
|
||||
---@return chunk[] chunks
|
||||
function format.log_line(log_line)
|
||||
local log_time = string.sub( log_line, string.find(log_line, "%[") + 1,
|
||||
string.find(log_line, "%]") - 1)
|
||||
local colon = string.find(log_line, ":", 11)
|
||||
local log_path = string.sub(log_line, string.find(log_line, "%]") + 2,
|
||||
colon - 1)
|
||||
local log_path_ln = string.sub(log_line, colon + 1,
|
||||
string.find(log_line, ":", colon + 1) - 1)
|
||||
local level = string.sub(log_line, string.find(log_line, "%(") + 1,
|
||||
string.find(log_line, "%)") - 1)
|
||||
local rest = string.sub(log_line, string.find(log_line, "%)") + 2)
|
||||
|
||||
return {
|
||||
{ "[", "" },
|
||||
{ log_time, "Boolean" },
|
||||
{ "] ", "" },
|
||||
{ log_path, "String" },
|
||||
{ ":", "" },
|
||||
{ log_path_ln, "Number" },
|
||||
{ ": ", "" },
|
||||
{ rest, logger.stage_colors[level] or "" }
|
||||
}
|
||||
end
|
||||
|
||||
return format
|
198
lua/dep/ui/init.lua
Normal file
198
lua/dep/ui/init.lua
Normal file
@ -0,0 +1,198 @@
|
||||
local h = require("dep.helpers")
|
||||
local page = require("dep.ui.page")
|
||||
local logger = require("dep.log")
|
||||
local format = require("dep.ui.format")
|
||||
|
||||
---@class ui
|
||||
---@field bufnr number
|
||||
---@field winnr number
|
||||
---@field header_bufnr number
|
||||
---@field header_winnr number
|
||||
---@field pages page[]
|
||||
local ui = {}
|
||||
|
||||
-- the active page being displayed
|
||||
local active_page
|
||||
|
||||
-- all the pages
|
||||
local pages = {}
|
||||
|
||||
-- the header ext mark
|
||||
local header_ext_id
|
||||
|
||||
local function page_packages(packager)
|
||||
local p = page:new("Packages", "P")
|
||||
for _, pkg in pairs(packager.get_packages()) do
|
||||
p:new_line({
|
||||
{ pkg.id, "@conditional" },
|
||||
{ " loaded: ", "" },
|
||||
format.bool(pkg.loaded),
|
||||
{ " lazy: ", "" },
|
||||
format.bool(pkg.lazy)
|
||||
})
|
||||
end
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
local function page_log()
|
||||
local p = page:new("Log", "L")
|
||||
local f = io.open(logger.path, "r")
|
||||
if not f then
|
||||
return
|
||||
end
|
||||
|
||||
-- put the cursor at the bottom of the page after drawing
|
||||
p.post_draw = function()
|
||||
vim.api.nvim_win_set_cursor(ui.winnr, { #p.content, 0 })
|
||||
end
|
||||
|
||||
-- read in the contents of the file, and keep watching for updates
|
||||
local function update_contents()
|
||||
repeat
|
||||
local line = f:read("*l")
|
||||
|
||||
-- if the line isn't empty we shouldn't draw it
|
||||
if line then
|
||||
p:new_line(format.log_line(line))
|
||||
end
|
||||
until not line
|
||||
end
|
||||
|
||||
update_contents()
|
||||
|
||||
local fullpath = vim.api.nvim_call_function(
|
||||
"fnamemodify", { logger.path, ":p" })
|
||||
h.uv.new_fs_event():start(fullpath, {}, vim.schedule_wrap(function()
|
||||
update_contents()
|
||||
|
||||
-- if the log is currently being displayed then make sure to draw it when
|
||||
-- it updates
|
||||
if active_page == p then
|
||||
p:draw(ui.bufnr)
|
||||
end
|
||||
end))
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
--- set the current page
|
||||
---@param p string|page page to set
|
||||
function ui.set_page(p)
|
||||
if type(p) == "string" then
|
||||
for _, v in ipairs(pages) do
|
||||
if p == v.kb then
|
||||
v:draw(ui.bufnr)
|
||||
active_page = v
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif type(p) == "table" then
|
||||
p:draw(ui.bufnr)
|
||||
active_page = p
|
||||
end
|
||||
|
||||
-- color the header text
|
||||
local txt = vim.api.nvim_buf_get_text(ui.header_bufnr, 0, 0, -1, -1, {})[1]
|
||||
local start_range = (string.find(txt, active_page.name)) - 2
|
||||
local end_range = #active_page.name + start_range + 2
|
||||
|
||||
if header_ext_id then
|
||||
vim.api.nvim_buf_del_extmark(ui.header_bufnr, active_page.hlns, header_ext_id)
|
||||
end
|
||||
header_ext_id = vim.api.nvim_buf_set_extmark(ui.header_bufnr,
|
||||
active_page.hlns, 0, start_range, {
|
||||
hl_mode = "replace",
|
||||
hl_group = "CurSearch",
|
||||
end_col = end_range,
|
||||
})
|
||||
end
|
||||
|
||||
--- setup all the pages
|
||||
---@param packager package the packager
|
||||
local function setup_pages(packager)
|
||||
local header_text = ""
|
||||
|
||||
table.insert(pages, page_packages(packager))
|
||||
table.insert(pages, page_log())
|
||||
|
||||
for _, v in ipairs(pages) do
|
||||
header_text = header_text.." "..v.name.." "
|
||||
|
||||
vim.keymap.set("n", v.kb, function()
|
||||
ui.set_page(v)
|
||||
end, { buffer = ui.bufnr })
|
||||
end
|
||||
|
||||
-- set the header text
|
||||
vim.api.nvim_buf_set_lines(ui.header_bufnr, 0, -1, false, { header_text })
|
||||
|
||||
-- add keymaps
|
||||
vim.keymap.set("n", "q", function()
|
||||
vim.api.nvim_win_close(ui.winnr, false)
|
||||
ui.winnr = nil
|
||||
end, { buffer = ui.bufnr })
|
||||
end
|
||||
|
||||
--- setup the ui
|
||||
---@param packager package
|
||||
function ui.open(packager)
|
||||
if not ui.bufnr then
|
||||
ui.bufnr = vim.api.nvim_create_buf(false, true)
|
||||
end
|
||||
if not ui.header_bufnr then
|
||||
ui.header_bufnr = vim.api.nvim_create_buf(false, true)
|
||||
end
|
||||
|
||||
local header_height = 1
|
||||
local width = math.floor(vim.o.columns * 0.8)
|
||||
local height = math.floor(vim.o.lines * 0.8) - header_height
|
||||
|
||||
if not ui.winnr then
|
||||
ui.winnr = vim.api.nvim_open_win(ui.bufnr, true, {
|
||||
relative = "editor",
|
||||
row = (vim.o.lines - height) / 2,
|
||||
col = (vim.o.columns - width) / 2,
|
||||
width = width,
|
||||
height = height,
|
||||
border = "solid",
|
||||
zindex = 998,
|
||||
})
|
||||
end
|
||||
|
||||
if not ui.header_winnr then
|
||||
ui.header_winnr = vim.api.nvim_open_win(ui.header_bufnr, false, {
|
||||
relative = "editor",
|
||||
row = ((vim.o.lines - height) / 2) - (header_height * 2),
|
||||
col = (vim.o.columns - width) / 2,
|
||||
width = width,
|
||||
height = header_height,
|
||||
border = "solid",
|
||||
zindex = 999,
|
||||
focusable = false
|
||||
})
|
||||
end
|
||||
|
||||
vim.api.nvim_win_set_buf(ui.winnr, ui.bufnr)
|
||||
vim.api.nvim_win_set_buf(ui.header_winnr, ui.header_bufnr)
|
||||
|
||||
-- make sure the header closes when the body does and vice versa
|
||||
local function cb()
|
||||
vim.api.nvim_win_close(ui.header_winnr, false)
|
||||
ui.header_winnr = nil
|
||||
vim.api.nvim_win_close(ui.winnr, false)
|
||||
ui.winnr = nil
|
||||
end
|
||||
vim.api.nvim_create_autocmd("WinClosed", {
|
||||
pattern = ui.winnr.."",
|
||||
callback = cb
|
||||
})
|
||||
vim.api.nvim_create_autocmd("WinClosed", {
|
||||
pattern = ui.header_winnr.."",
|
||||
callback = cb
|
||||
})
|
||||
|
||||
setup_pages(packager)
|
||||
end
|
||||
|
||||
return ui
|
84
lua/dep/ui/page.lua
Normal file
84
lua/dep/ui/page.lua
Normal file
@ -0,0 +1,84 @@
|
||||
---@class chunk: table
|
||||
---@field [1] string text to be displayed
|
||||
---@field [2] string neovim highlight group to use
|
||||
|
||||
---@class page
|
||||
---@field name string name of the ui page
|
||||
---@field kb string keybind of the page
|
||||
---@field content chunk[]|chunk[][] all the chunks
|
||||
---@field hlns number highlight namespace
|
||||
---@field pre_draw function things to do prior to drawing to the buffer
|
||||
---@field post_draw function things to do post drawing to the buffer
|
||||
local page = {}
|
||||
|
||||
--- create a new page
|
||||
---@param name string the name of the page
|
||||
---@param kb string keybind to change to the page
|
||||
---@return page page
|
||||
function page:new(name, kb)
|
||||
local o = {}
|
||||
self.__index = self
|
||||
setmetatable(o, self)
|
||||
|
||||
o.hlns = vim.api.nvim_create_namespace("DepUi")
|
||||
o.name = name
|
||||
o.kb = kb
|
||||
o.content = {}
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
--- add a new line to the page
|
||||
---@param line chunk|chunk[] new line
|
||||
function page:new_line(line)
|
||||
table.insert(self.content, line)
|
||||
end
|
||||
|
||||
--- draw the page to the given buffer
|
||||
---@param bufnr number buffer number
|
||||
function page:draw(bufnr)
|
||||
-- try to run pre_draw steps
|
||||
if self.pre_draw then
|
||||
self.pre_draw()
|
||||
end
|
||||
|
||||
-- ready all information for rendering
|
||||
for i, chunk in ipairs(self.content) do
|
||||
local linenr = i - 1
|
||||
local text = ""
|
||||
local hls = {}
|
||||
|
||||
if type(chunk[1]) == "table" then
|
||||
local j = 0
|
||||
for _, ch in ipairs(chunk) do
|
||||
text = text..ch[1]
|
||||
table.insert(hls, { ch[2], j, j + #ch[1] })
|
||||
j = j + #ch[1]
|
||||
end
|
||||
elseif type(chunk[1]) == "string" then
|
||||
text = chunk[1]
|
||||
table.insert(hls, { chunk[2], 0, #text })
|
||||
end
|
||||
|
||||
-- draw the text to the buffer
|
||||
vim.api.nvim_buf_set_lines(bufnr, linenr, -1, false, { text })
|
||||
|
||||
-- highlight the buffer
|
||||
for _, hl in ipairs(hls) do
|
||||
vim.api.nvim_buf_set_extmark(bufnr, self.hlns, linenr, hl[2], {
|
||||
hl_mode = "replace",
|
||||
hl_group = hl[1],
|
||||
end_col = hl[3],
|
||||
end_row = linenr
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- try to run post_draw steps
|
||||
if self.post_draw then
|
||||
self.post_draw()
|
||||
end
|
||||
end
|
||||
|
||||
return page
|
Reference in New Issue
Block a user