|
|
@@ -1,113 +1,206 @@
|
|
|
+-- local function parse_stderr(data)
|
|
|
+-- local message = table.concat(data, "\n")
|
|
|
+-- local level = "info"
|
|
|
+--
|
|
|
+-- -- Check each line for error or warning
|
|
|
+-- for line in message:gmatch("[^\r\n]+") do
|
|
|
+-- local lower_line = line:lower()
|
|
|
+-- if lower_line:match("^%s*error:") then
|
|
|
+-- level = "error"
|
|
|
+-- break
|
|
|
+-- elseif lower_line:match("^%s*warning:") then
|
|
|
+-- level = "warn"
|
|
|
+-- -- Don't break here, in case an error appears later
|
|
|
+-- end
|
|
|
+-- end
|
|
|
+--
|
|
|
+-- return message, level
|
|
|
+-- end
|
|
|
|
|
|
+local function parse_stderr(data, filter_level)
|
|
|
+ local messages = {}
|
|
|
+ local current_message = {}
|
|
|
+ local current_level = "info"
|
|
|
|
|
|
-local function parse_stderr(data)
|
|
|
- local message = table.concat(data, "\n")
|
|
|
- local level = "info"
|
|
|
-
|
|
|
- -- Check each line for error or warning
|
|
|
- for line in message:gmatch("[^\r\n]+") do
|
|
|
- local lower_line = line:lower()
|
|
|
- if lower_line:match("^%s*error:") then
|
|
|
- level = "error"
|
|
|
- break
|
|
|
- elseif lower_line:match("^%s*warning:") then
|
|
|
- level = "warn"
|
|
|
- -- Don't break here, in case an error appears later
|
|
|
- end
|
|
|
- end
|
|
|
-
|
|
|
- return message, level
|
|
|
-end
|
|
|
+ -- Split data into blocks
|
|
|
+ for _, line in ipairs(data) do
|
|
|
+ if line:match("^%s*$") then
|
|
|
+ -- Empty line, end of block
|
|
|
+ if #current_message > 0 then
|
|
|
+ table.insert(messages, { message = table.concat(current_message, "\n"), level = current_level })
|
|
|
+ current_message = {}
|
|
|
+ current_level = "info"
|
|
|
+ end
|
|
|
+ else
|
|
|
+ -- Check for error/warning/info at the beginning of the block
|
|
|
+ local lower_line = line:lower()
|
|
|
+ if lower_line:match("^%s*error:") then
|
|
|
+ current_level = "error"
|
|
|
+ elseif lower_line:match("^%s*warning:") then
|
|
|
+ current_level = "warn"
|
|
|
+ elseif lower_line:match("^%s*info:") then
|
|
|
+ current_level = "info"
|
|
|
+ end
|
|
|
+ table.insert(current_message, line)
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ -- Add last block if exists
|
|
|
+ if #current_message > 0 then
|
|
|
+ table.insert(messages, { message = table.concat(current_message, "\n"), level = current_level })
|
|
|
+ end
|
|
|
|
|
|
+ -- Filter messages based on filter_level
|
|
|
+ local filtered_messages = {}
|
|
|
+ for _, msg in ipairs(messages) do
|
|
|
+ if not filter_level or msg.level == filter_level then
|
|
|
+ table.insert(filtered_messages, msg)
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ return filtered_messages
|
|
|
+end
|
|
|
|
|
|
local function typst_build_and_open_sioyek()
|
|
|
- local bufname = vim.fn.expand('%:p')
|
|
|
- local pdf_path = vim.fn.fnamemodify(bufname, ':r') .. '.pdf'
|
|
|
- local cmd = string.format('typst compile "%s"', bufname)
|
|
|
-
|
|
|
- vim.fn.jobstart(cmd, {
|
|
|
- on_exit = function(_, exit_code)
|
|
|
- if exit_code == 0 then
|
|
|
- vim.notify("Typst build completed successfully", vim.log.levels.INFO, {
|
|
|
- title = "Typst Build",
|
|
|
- timeout = 3000,
|
|
|
- })
|
|
|
-
|
|
|
- -- Now open or reload Sioyek
|
|
|
- local sioyek_running = vim.fn.system('pgrep sioyek'):match('%d+')
|
|
|
-
|
|
|
- if sioyek_running then
|
|
|
- vim.fn.system('sioyek --execute-command reload_no_flicker')
|
|
|
- vim.notify("Sioyek reloaded", vim.log.levels.INFO, {
|
|
|
- title = "Sioyek",
|
|
|
- timeout = 2000,
|
|
|
- })
|
|
|
- else
|
|
|
- vim.fn.jobstart('sioyek "' .. pdf_path .. '"', {
|
|
|
- on_exit = function(_, sioyek_exit_code)
|
|
|
- if sioyek_exit_code == 0 then
|
|
|
- vim.notify("Sioyek opened", vim.log.levels.INFO, {
|
|
|
- title = "Sioyek",
|
|
|
- timeout = 2000,
|
|
|
- })
|
|
|
- else
|
|
|
- vim.notify("Failed to open Sioyek", vim.log.levels.ERROR, {
|
|
|
- title = "Sioyek",
|
|
|
- timeout = 3000,
|
|
|
- })
|
|
|
- end
|
|
|
- end
|
|
|
- })
|
|
|
- end
|
|
|
- else
|
|
|
- vim.notify("Typst build failed", vim.log.levels.ERROR, {
|
|
|
- title = "Typst Build",
|
|
|
- timeout = 5000,
|
|
|
- })
|
|
|
- end
|
|
|
- end,
|
|
|
- stderr_buffered = true,
|
|
|
- on_stderr = function(_, data)
|
|
|
- if data and #data > 0 then
|
|
|
- local message, level = parse_stderr(data)
|
|
|
- vim.notify(message, vim.log.levels[level:upper()], {
|
|
|
- title = "Typst Build",
|
|
|
- timeout = 5000,
|
|
|
- })
|
|
|
- end
|
|
|
- end,
|
|
|
- })
|
|
|
+ local bufname = vim.fn.expand("%:p")
|
|
|
+ local pdf_path = vim.fn.fnamemodify(bufname, ":r") .. ".pdf"
|
|
|
+ local cmd = string.format('typst compile "%s"', bufname)
|
|
|
+
|
|
|
+ vim.fn.jobstart(cmd, {
|
|
|
+ on_exit = function(_, exit_code)
|
|
|
+ if exit_code == 0 then
|
|
|
+ vim.notify("Typst build completed successfully", vim.log.levels.INFO, {
|
|
|
+ title = "Typst Build",
|
|
|
+ timeout = 3000,
|
|
|
+ })
|
|
|
+
|
|
|
+ -- Now open or reload Sioyek
|
|
|
+ local sioyek_running = vim.fn.system("pgrep sioyek"):match("%d+")
|
|
|
+
|
|
|
+ if sioyek_running then
|
|
|
+ vim.fn.system("sioyek --execute-command reload_no_flicker")
|
|
|
+ vim.notify("Sioyek reloaded", vim.log.levels.INFO, {
|
|
|
+ title = "Sioyek",
|
|
|
+ timeout = 2000,
|
|
|
+ })
|
|
|
+ else
|
|
|
+ vim.fn.jobstart('sioyek "' .. pdf_path .. '"', {
|
|
|
+ on_exit = function(_, sioyek_exit_code)
|
|
|
+ if sioyek_exit_code == 0 then
|
|
|
+ vim.notify("Sioyek opened", vim.log.levels.INFO, {
|
|
|
+ title = "Sioyek",
|
|
|
+ timeout = 2000,
|
|
|
+ })
|
|
|
+ else
|
|
|
+ vim.notify("Failed to open Sioyek", vim.log.levels.ERROR, {
|
|
|
+ title = "Sioyek",
|
|
|
+ timeout = 3000,
|
|
|
+ })
|
|
|
+ end
|
|
|
+ end,
|
|
|
+ })
|
|
|
+ end
|
|
|
+ else
|
|
|
+ vim.notify("Typst build failed", vim.log.levels.ERROR, {
|
|
|
+ title = "Typst Build",
|
|
|
+ timeout = 5000,
|
|
|
+ })
|
|
|
+ end
|
|
|
+ end,
|
|
|
+ stderr_buffered = true,
|
|
|
+ on_stderr = function(_, data)
|
|
|
+ if data and #data > 0 then
|
|
|
+ local messages = parse_stderr(data)
|
|
|
+ local error_count = 0
|
|
|
+ local warning_count = 0
|
|
|
+ local info_count = 0
|
|
|
+
|
|
|
+ for _, msg in ipairs(messages) do
|
|
|
+ if msg.level == "error" then
|
|
|
+ error_count = error_count + 1
|
|
|
+ elseif msg.level == "warn" then
|
|
|
+ warning_count = warning_count + 1
|
|
|
+ elseif msg.level == "info" then
|
|
|
+ info_count = info_count + 1
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ local notify = require("notify")
|
|
|
+ local original_opts = vim.deepcopy(notify.options)
|
|
|
+ notify.setup({
|
|
|
+ stages = "static",
|
|
|
+ -- Add any other temporary options here
|
|
|
+ })
|
|
|
+
|
|
|
+ for _, msg in ipairs(messages) do
|
|
|
+ if msg.level ~= "error" then
|
|
|
+ -- Route warnings and info to notify without displaying
|
|
|
+ vim.notify(msg.message, vim.log.levels[msg.level:upper()], {
|
|
|
+ title = "Typst Build " .. msg.level,
|
|
|
+ timeout = 0,
|
|
|
+ silent = true,
|
|
|
+ log = true,
|
|
|
+ })
|
|
|
+ end
|
|
|
+ end
|
|
|
+ notify.setup(original_opts)
|
|
|
+
|
|
|
+ for _, msg in ipairs(messages) do
|
|
|
+ if msg.level == "error" then
|
|
|
+ vim.notify(msg.message, vim.log.levels.ERROR, {
|
|
|
+ title = "Typst Build Error",
|
|
|
+ timeout = 5000,
|
|
|
+ })
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ if warning_count > 0 then
|
|
|
+ vim.notify(string.format("%d warning(s)", warning_count), vim.log.levels.WARN, {
|
|
|
+ title = "Typst Build Summary",
|
|
|
+ timeout = 3000,
|
|
|
+ })
|
|
|
+ end
|
|
|
+
|
|
|
+ if info_count > 0 then
|
|
|
+ vim.notify(string.format("%d info message(s)", info_count), vim.log.levels.INFO, {
|
|
|
+ title = "Typst Build Summary",
|
|
|
+ timeout = 2000,
|
|
|
+ })
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end,
|
|
|
+ })
|
|
|
end
|
|
|
|
|
|
-vim.api.nvim_create_user_command('TypstBuild', typst_build_and_open_sioyek, {})
|
|
|
+vim.api.nvim_create_user_command("TypstBuild", typst_build_and_open_sioyek, {})
|
|
|
|
|
|
-- Create an autocommand group
|
|
|
-local typst_group = vim.api.nvim_create_augroup('TypstBuildGroup', { clear = true })
|
|
|
+local typst_group = vim.api.nvim_create_augroup("TypstBuildGroup", { clear = true })
|
|
|
|
|
|
-- Create a command to toggle the autocommand
|
|
|
local typst_auto_build_enabled = false
|
|
|
|
|
|
-- Function to create the autocommand
|
|
|
local function create_typst_autocmd()
|
|
|
- vim.api.nvim_create_autocmd('BufWritePost', {
|
|
|
- group = typst_group,
|
|
|
- pattern = '*.typ',
|
|
|
- callback = function()
|
|
|
- vim.cmd('TypstBuild')
|
|
|
- end,
|
|
|
- })
|
|
|
+ vim.api.nvim_create_autocmd("BufWritePost", {
|
|
|
+ group = typst_group,
|
|
|
+ pattern = "*.typ",
|
|
|
+ callback = function()
|
|
|
+ vim.cmd("TypstBuild")
|
|
|
+ end,
|
|
|
+ })
|
|
|
end
|
|
|
|
|
|
-- Create a command to toggle the autocommand
|
|
|
-vim.api.nvim_create_user_command('TypstAutoBuild', function()
|
|
|
- typst_auto_build_enabled = not typst_auto_build_enabled
|
|
|
- if typst_auto_build_enabled then
|
|
|
- create_typst_autocmd()
|
|
|
- vim.notify('Typst auto-build enabled', vim.log.levels.INFO)
|
|
|
- else
|
|
|
- vim.api.nvim_clear_autocmds({ group = typst_group })
|
|
|
- vim.notify('Typst auto-build disabled', vim.log.levels.INFO)
|
|
|
- end
|
|
|
+vim.api.nvim_create_user_command("TypstAutoBuild", function()
|
|
|
+ typst_auto_build_enabled = not typst_auto_build_enabled
|
|
|
+ if typst_auto_build_enabled then
|
|
|
+ create_typst_autocmd()
|
|
|
+ vim.notify("Typst auto-build enabled", vim.log.levels.INFO)
|
|
|
+ else
|
|
|
+ vim.api.nvim_clear_autocmds({ group = typst_group })
|
|
|
+ vim.notify("Typst auto-build disabled", vim.log.levels.INFO)
|
|
|
+ end
|
|
|
end, {})
|
|
|
|
|
|
return {
|