Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

neovim/lua/std/dbg/init.lua

Raw
--- Debug logging facade. Minimal by design: everything goes to one JSONL file.
--- File: stdpath('state')/bugabinga_config_debug.jsonl
---
--- API:
---   dbg( message, ... )        -- DEBUG level, printf-style ( string.format )
---   dbg.kind( kind, message, ... )
---   dbg.print( message, ... )  -- DEBUG level, explicit method form
---   dbg.get()                  -- is debug mode on
---   dbg.toggle()
---
--- Commands: :DbgModeToggle  :DbgOpenFile  :DbgClear
local user_command = require 'std.user_command'

local DBG_FILE = vim.fn.stdpath 'state' .. '/bugabinga_config_debug.jsonl'

if vim.g.bugabinga_debug_mode == nil then
	vim.g.bugabinga_debug_mode = false
end

local function path()
	return vim.g.bugabinga_debug_file_override or DBG_FILE
end

local function enabled()
	return vim.g.bugabinga_debug_mode
end

-- filename, function name and line of the caller, skipping this module's frames.
local function context()
	local level = 2
	while true do
		local info = debug.getinfo( level, 'Sln' )
		if not info then return 'unknown', '', 0 end
		local source = info.short_src or info.source
		if source and not source:match 'std/dbg' then
			return source, info.name or '', info.currentline or 0
		end
		level = level + 1
	end
end

local function log( kind, message, ... )
	if not enabled() then return end
	local data = { ... }
	local ok, formatted = pcall( string.format, message, ... )
	local source, fn, line = context()
	local event = {
		kind = kind,
		date = os.time(),
		message = ok and formatted or message,
		data = data,
		filename = source,
		fn = fn,
		line = line,
	}
	local file_path = path()
	vim.fn.mkdir( vim.fs.dirname( file_path ), 'p' )
	local handle, err = io.open( file_path, 'a' )
	if not handle then
		error( 'dbg: cannot open ' .. file_path .. ': ' .. tostring( err ) )
	end
	handle:write( vim.json.encode( event ) .. '\n' )
	handle:close()
end

local function toggle()
	vim.g.bugabinga_debug_mode = not enabled()
	vim.notify( 'debug mode: ' .. tostring( enabled() ) )
end

user_command.DbgModeToggle 'Toggle global vim config debug mode.' ( toggle )
user_command.DbgOpenFile 'Open the JSONL debug file in a buffer' ( function ()
	vim.cmd.edit( path() )
end )
user_command.DbgClear 'Clear the JSONL debug file' ( function ()
	local handle = io.open( path(), 'w' )
	if handle then handle:close() end
end )

return setmetatable( {
	kind = log,
	print = function ( message, ... ) log( 'DEBUG', message, ... ) end,
	toggle = toggle,
	get = enabled,
}, {
	__call = function ( _, message, ... ) log( 'DEBUG', message, ... ) end,
	__newindex = function ( ... )
		error( 'Assignments are not supported for std.dbg.\n' .. vim.inspect( ... ), 2 )
	end,
} )