repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/std/dbg/file.lua
Rawlocal encode = require 'std.dbg.encode'
local decode = require 'std.dbg.encode'
local DBG_FILE = vim.fn.stdpath 'state' .. '/bugabinga_config_debug.jsonl'
---Returns the path to the debug log file.
---@return string
local function get_path()
return vim.g.bugabinga_debug_file_override or DBG_FILE
end
---Returns the filename, function name, and line number of the caller.
---Skips all frames inside std/dbg/* modules.
---@return string filename
---@return string function_name
---@return integer line_number
local function get_context()
local level = 2
while true do
local info = debug.getinfo(level, 'Sln')
if not info then break end
local src = info.short_src or info.source
if src and not src:match 'std/dbg' and not src:match '@std/dbg' then
return src, info.name or '', info.currentline or 0
end
level = level + 1
end
return 'unknown', '', 0
end
---Appends a debug event as a JSON line to the debug file.
---@param event table debug event
---@param path string? override path
local function write(event, path)
local file_path = path or DBG_FILE
local dir = vim.fs.dirname(file_path)
if dir and dir ~= '' then
vim.fn.mkdir(dir, 'p')
end
local file, errmsg = io.open(file_path, 'a')
if not file then
error('Unable to open debug log file `' .. file_path .. '`: ' .. tostring(errmsg))
end
local json_line = encode.encode(event)
file:write(json_line .. '\n')
file:flush()
file:close()
end
---Closes the open file descriptor. No-op with io.open.
local function close_fd()
end
---Clears the debug log file by truncating it.
local function clear_log()
local dir = vim.fs.dirname(DBG_FILE)
if dir and dir ~= '' then
vim.fn.mkdir(dir, 'p')
end
local file, errmsg = io.open(DBG_FILE, 'w')
if file then
file:close()
end
end
---Reads all debug events from a JSONL file.
---@param path string? override path (defaults to DBG_FILE)
---@return table[] list of decoded events
local function read_all(path)
local file_path = path or DBG_FILE
local file = io.open(file_path, 'r')
if not file then
return {}
end
local events = {}
for line in file:lines() do
if line and line ~= '' then
local ok, event = pcall(decode.decode, line)
if ok and event then
table.insert(events, event)
end
end
end
file:close()
return events
end
---Reads only new events from the JSONL file, skipping the first `last_count` lines.
---Use for incremental updates when tailing a growing file.
---@param last_count number skip this many lines before reading new ones
---@param path string? override path (defaults to DBG_FILE)
---@return table[] new_events list of newly decoded events
---@return number new_total total count of events in file after reading
local function read_new(last_count, path)
local file_path = path or DBG_FILE
local file = io.open(file_path, 'r')
if not file then
return {}, 0
end
local new_events = {}
local current_count = 0
for line in file:lines() do
if line and line ~= '' then
current_count = current_count + 1
if current_count > last_count then
local ok, event = pcall(decode.decode, line)
if ok and event then
table.insert(new_events, event)
end
end
end
end
file:close()
return new_events, current_count
end
return {
get_path = get_path,
get_context = get_context,
write = write,
read_all = read_all,
read_new = read_new,
close_fd = close_fd,
clear_log = clear_log,
}