|
| 1 | +local util = require('render-markdown.core.util') |
| 2 | + |
| 3 | +---@class render.md.log.Entry |
| 4 | +---@field date string |
| 5 | +---@field level string |
| 6 | +---@field name string |
| 7 | +---@field message string |
| 8 | + |
| 9 | +---@class render.md.Log |
| 10 | +---@field private level render.md.config.LogLevel |
| 11 | +---@field private entries render.md.log.Entry[] |
| 12 | +---@field file string |
| 13 | +local M = {} |
| 14 | + |
| 15 | +---@param level render.md.config.LogLevel |
| 16 | +function M.setup(level) |
| 17 | + M.level = level |
| 18 | + M.entries = {} |
| 19 | + -- Typically resolves to ~/.local/state/nvim/render-markdown.log |
| 20 | + M.file = vim.fn.stdpath('state') .. '/render-markdown.log' |
| 21 | + -- Clear the file contents if it is too big |
| 22 | + if util.file_size_mb(M.file) > 5 then |
| 23 | + assert(io.open(M.file, 'w')):close() |
| 24 | + end |
| 25 | +end |
| 26 | + |
| 27 | +---@param capture string |
| 28 | +---@param info render.md.NodeInfo |
| 29 | +function M.debug_node_info(capture, info) |
| 30 | + M.debug('node info', { |
| 31 | + capture = capture, |
| 32 | + text = info.text, |
| 33 | + rows = { info.start_row, info.end_row }, |
| 34 | + cols = { info.start_col, info.end_col }, |
| 35 | + }) |
| 36 | +end |
| 37 | + |
| 38 | +---Encountered if user provides custom capture |
| 39 | +---@param group string |
| 40 | +---@param capture string |
| 41 | +function M.unhandled_capture(group, capture) |
| 42 | + M.error('unhandled capture', string.format('%s -> %s', group, capture)) |
| 43 | +end |
| 44 | + |
| 45 | +---Encountered if new type is seen for a particular group |
| 46 | +---@param language string |
| 47 | +---@param group string |
| 48 | +---@param value string |
| 49 | +function M.unhandled_type(language, group, value) |
| 50 | + M.error('unhandled type', string.format('%s -> %s -> %s', language, group, value)) |
| 51 | +end |
| 52 | + |
| 53 | +---@param name string |
| 54 | +---@param ... any |
| 55 | +function M.debug(name, ...) |
| 56 | + if vim.tbl_contains({ 'debug' }, M.level) then |
| 57 | + M.add('debug', name, ...) |
| 58 | + end |
| 59 | +end |
| 60 | + |
| 61 | +---@param name string |
| 62 | +---@param ... any |
| 63 | +function M.error(name, ...) |
| 64 | + if vim.tbl_contains({ 'debug', 'error' }, M.level) then |
| 65 | + M.add('error', name, ...) |
| 66 | + end |
| 67 | +end |
| 68 | + |
| 69 | +---@private |
| 70 | +---@param level render.md.config.LogLevel |
| 71 | +---@param name string |
| 72 | +---@param ... any |
| 73 | +function M.add(level, name, ...) |
| 74 | + local messages = {} |
| 75 | + local args = vim.F.pack_len(...) |
| 76 | + for i = 1, args.n do |
| 77 | + local message = type(args[i]) == 'string' and args[i] or vim.inspect(args[i]) |
| 78 | + table.insert(messages, message) |
| 79 | + end |
| 80 | + ---@type render.md.log.Entry |
| 81 | + local entry = { |
| 82 | + date = vim.fn.strftime('%Y-%m-%d %H:%M:%S'), |
| 83 | + level = string.upper(level), |
| 84 | + name = name, |
| 85 | + message = table.concat(messages, ' | '), |
| 86 | + } |
| 87 | + table.insert(M.entries, entry) |
| 88 | + -- Periodically flush logs to disk |
| 89 | + if #M.entries > 1000 then |
| 90 | + M.flush() |
| 91 | + end |
| 92 | +end |
| 93 | + |
| 94 | +function M.flush() |
| 95 | + if #M.entries == 0 then |
| 96 | + return |
| 97 | + end |
| 98 | + local file = assert(io.open(M.file, 'a')) |
| 99 | + for _, entry in ipairs(M.entries) do |
| 100 | + local line = string.format('%s %s [%s] - %s', entry.date, entry.level, entry.name, entry.message) |
| 101 | + file:write(line .. '\n') |
| 102 | + end |
| 103 | + file:close() |
| 104 | + M.entries = {} |
| 105 | +end |
| 106 | + |
| 107 | +return M |
0 commit comments