From 2ece9162ab8a26f942ddfdcc085988ce48f8ab14 Mon Sep 17 00:00:00 2001 From: marcobuess <42165023+MarcoBuess@users.noreply.github.com> Date: Sat, 30 Mar 2024 01:25:53 +0100 Subject: [PATCH 1/7] feat: close markmap when watched buffer is closed This was a late one for me. Let me know how you like it, or if you can spot major flaws right away. cheers and happy easter. :) --- lua/markmap/init.lua | 66 ++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/lua/markmap/init.lua b/lua/markmap/init.lua index 3a09ce2..b16c493 100644 --- a/lua/markmap/init.lua +++ b/lua/markmap/init.lua @@ -1,4 +1,6 @@ -- This plugin is a wrapper for markmap-cli +local api = vim.api +local uv = vim.uv or vim.loop local utils = require("markmap.utils") local jobstart = utils.jobstart local jobstop = vim.fn.jobstop @@ -27,48 +29,40 @@ M.setup = function(opts) cmd("MarkmapSave", function() config = vim.g.markmap_config arguments = utils.reset_arguments() - local path = '"' .. vim.fn.expand("%:p") .. '"' -- current buffer path - table.insert(arguments, "--no-open") -- specific to this command - table.insert(arguments, path) - if job ~= nil then jobstop(job) end -- kill jobs + table.insert(arguments, "--no-open") -- specific to this command + table.insert(arguments, vim.fn.expand("%:p")) -- current buffer path + if job ~= nil then jobstop(job) end -- kill jobs job = jobstart(config.markmap_cmd, arguments) end, { desc = "Save the HTML file without opening the mindmap" }) - cmd("MarkmapWatch", function() - config = vim.g.markmap_config - arguments = utils.reset_arguments() - local path = '"' .. vim.fn.expand("%:p") .. '"' -- current buffer path - table.insert(arguments, "--watch") -- spetific to this command - table.insert(arguments, path) - if job ~= nil then jobstop(job) end -- kill jobs - job = jobstart(config.markmap_cmd, arguments) - end, { desc = "Show a mental map of the current file and watch for changes" }) + cmd( + "MarkmapWatch", + function() + config = vim.g.markmap_config + arguments = utils.reset_arguments() + table.insert(arguments, "--watch") -- spetific to this command + table.insert(arguments, vim.fn.expand("%:p")) -- current buffer path + if job ~= nil then jobstop(job) end -- kill jobs + job = jobstart(config.markmap_cmd, arguments) + + -- Register buffer local autocmd to kill job when buffer closes + local kill_on_close = augroup("markmap_kill_on_close", { clear = true }) + autocmd("BufDelete", { + buffer = 0, + desc = "Kill markmap when watched buffer is closed", + group = kill_on_close, + callback = function() + jobstop(job) + api.nvim_clear_autocmds({ group = kill_on_close }) + end, + }) + end, + { desc = "Show a mental map of the current file and watch for changes" } + ) cmd("MarkmapWatchStop", function() - if job ~= nil then jobstop(job) end -- kill jobs + if job ~= nil then jobstop(job) end -- kill jobs end, { desc = "Manually stops markmap watch" }) - - -- Autocmds ----------------------------------------------------------------- - -- Kill jobs after a grace period - local last_execution = vim.uv.now() -- timer for grace period - autocmd("CursorHold", { - desc = "Kill all markmap jobs after a grace period", - group = augroup("markmap_kill_after_grace_period", { clear = true }), - callback = function() - -- If grace_periodd is disabled, remove the autocmd and return - if config.grace_period == 0 then - vim.cmd "autocmd! markmap_kill_after_grace_period" - return - end - - -- Otherwise, use grace_period - local current_time = vim.uv.now() - if current_time - last_execution >= config.grace_period then -- if grace period exceeded - if job ~= nil then jobstop(job) end -- pkill jobs - last_execution = current_time -- update time - end - end, - }) end return M From a4b80af9f72518d86c90dc9df2586952d5b46b5e Mon Sep 17 00:00:00 2001 From: marcobuess <42165023+MarcoBuess@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:12:53 +0200 Subject: [PATCH 2/7] fix(stylua): removed unknown configuration option removed `remove_trailing_seperators` option, which would prevent stylua from formatting --- .stylua.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/.stylua.toml b/.stylua.toml index f6b869b..7662e6a 100644 --- a/.stylua.toml +++ b/.stylua.toml @@ -5,4 +5,3 @@ indent_type = "Spaces" indent_width = 2 line_endings = "Unix" quote_style = "AutoPreferDouble" -remove_trailing_separators = false From 478053d58666bc2a8901fbfbe0dcb4b4e530f6f0 Mon Sep 17 00:00:00 2001 From: marcobuess <42165023+MarcoBuess@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:06:42 +0200 Subject: [PATCH 3/7] style(config): stylua changed quotes --- lua/markmap/config.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lua/markmap/config.lua b/lua/markmap/config.lua index 05d403a..c14b78d 100644 --- a/lua/markmap/config.lua +++ b/lua/markmap/config.lua @@ -1,8 +1,9 @@ -- Config options to keep init clean. local M = {} -local is_windows = vim.uv.os_uname().sysname == "Windows_NT" -local is_android = vim.fn.isdirectory('/data') == 1 +local uv = vim.uv or vim.loop +local is_windows = uv.os_uname().sysname == "Windows_NT" +local is_android = vim.fn.isdirectory("/data") == 1 ---Parse user options, or set the defaults ---@param opts table A table with options to set. From 01a0cbbe39a2b916dd286d7d677dcef9d1f9595f Mon Sep 17 00:00:00 2001 From: marcobuess <42165023+MarcoBuess@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:08:35 +0200 Subject: [PATCH 4/7] feat(utils): extended jobstart with opts To handle that windows can't have multiple instances of markmapcli running I added a passthrough, so that I can handle appropreatly when markmapcli errors. I deregister autocmds and take the buffer from the watch list. --- lua/markmap/utils.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lua/markmap/utils.lua b/lua/markmap/utils.lua index a720bbe..a23c82a 100644 --- a/lua/markmap/utils.lua +++ b/lua/markmap/utils.lua @@ -12,12 +12,13 @@ local is_windows = vim.uv.os_uname().sysname == "Windows_NT" --- the executables must be added to path in at windows level. ---@param cmd string command to run. ---@param arguments table arguments to pass to the cmd. +---@param opts table vim.fn.jobstart options ---@return number job pid of the job, so we can stop it later. -M.jobstart = function(cmd, arguments) +M.jobstart = function(cmd, arguments, opts) if is_windows then - return vim.fn.jobstart({ cmd, unpack(arguments) }) + return vim.fn.jobstart({ cmd, unpack(arguments) }, opts) else - return vim.fn.jobstart(cmd .. " " .. table.concat(arguments, " ")) + return vim.fn.jobstart(cmd .. " " .. table.concat(arguments, " "), opts) end end @@ -28,7 +29,7 @@ M.reset_arguments = function() local config = vim.g.markmap_config local arguments = {} - if config.html_output ~= "" then -- if html_output is "", don't pass the parameter + if config.html_output ~= "" then -- if html_output is "", don't pass the parameter table.insert(arguments, "-o") table.insert(arguments, '"' .. config.html_output .. '"') end From 4013ab3b1355bd617ff888c2f37897dbcdcd1ff7 Mon Sep 17 00:00:00 2001 From: marcobuess <42165023+MarcoBuess@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:09:57 +0200 Subject: [PATCH 5/7] feat(init): added tracking of watched buffers --- lua/markmap/init.lua | 64 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/lua/markmap/init.lua b/lua/markmap/init.lua index b16c493..1d61be4 100644 --- a/lua/markmap/init.lua +++ b/lua/markmap/init.lua @@ -15,6 +15,7 @@ M.setup = function(opts) local config = vim.g.markmap_config local job = nil local arguments = {} + local lookup_table = {} -- Setup commands ----------------------------------------------------------- cmd("MarkmapOpen", function() @@ -38,30 +39,65 @@ M.setup = function(opts) cmd( "MarkmapWatch", function() + local watch_buffer = vim.api.nvim_get_current_buf() config = vim.g.markmap_config arguments = utils.reset_arguments() table.insert(arguments, "--watch") -- spetific to this command table.insert(arguments, vim.fn.expand("%:p")) -- current buffer path - if job ~= nil then jobstop(job) end -- kill jobs - job = jobstart(config.markmap_cmd, arguments) - -- Register buffer local autocmd to kill job when buffer closes - local kill_on_close = augroup("markmap_kill_on_close", { clear = true }) - autocmd("BufDelete", { - buffer = 0, - desc = "Kill markmap when watched buffer is closed", - group = kill_on_close, - callback = function() - jobstop(job) - api.nvim_clear_autocmds({ group = kill_on_close }) - end, - }) + if lookup_table[watch_buffer] then + vim.notify("You're already watching this buffer.", vim.log.levels.WARN) + else + local kill_on_close = + augroup("markmap_kill_on_close", { clear = false }) + + job = jobstart(config.markmap_cmd, arguments, { + stderr_buffered = true, -- needed so on_stderr is only called once + on_stderr = function(_, data) + local message = table.concat(data, "\n") + message = message:gsub("\r", "") + vim.notify(message, vim.log.levels.ERROR) + + lookup_table[watch_buffer] = nil + api.nvim_clear_autocmds({ + group = kill_on_close, + buffer = watch_buffer, + }) + end, + }) + + lookup_table[watch_buffer] = job + + -- Register buffer local autocmd to kill job when buffer closes + autocmd("BufDelete", { + desc = "Kill markmap when watched buffer is closed", + buffer = watch_buffer, + group = kill_on_close, + callback = function() + jobstop(job) + lookup_table[watch_buffer] = nil + api.nvim_clear_autocmds({ + group = kill_on_close, + buffer = watch_buffer, + }) + end, + }) + end end, { desc = "Show a mental map of the current file and watch for changes" } ) cmd("MarkmapWatchStop", function() - if job ~= nil then jobstop(job) end -- kill jobs + local watch_buffer = vim.api.nvim_get_current_buf() + local job = lookup_table[watch_buffer] + if job then + jobstop(job) + lookup_table[watch_buffer] = nil + api.nvim_clear_autocmds({ + group = kill_on_close, + buffer = watch_buffer, + }) + end end, { desc = "Manually stops markmap watch" }) end From d7af548e8e978ddcc310be1ab2c6f56529c2ae2b Mon Sep 17 00:00:00 2001 From: marcobuess <42165023+MarcoBuess@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:22:05 +0200 Subject: [PATCH 6/7] chore(init): removed unused variable uv --- lua/markmap/init.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/markmap/init.lua b/lua/markmap/init.lua index 1d61be4..eced275 100644 --- a/lua/markmap/init.lua +++ b/lua/markmap/init.lua @@ -1,6 +1,5 @@ -- This plugin is a wrapper for markmap-cli local api = vim.api -local uv = vim.uv or vim.loop local utils = require("markmap.utils") local jobstart = utils.jobstart local jobstop = vim.fn.jobstop From 1ca57edfd29c001685b2ff6e0ed819308bb96c7d Mon Sep 17 00:00:00 2001 From: marcobuess <42165023+MarcoBuess@users.noreply.github.com> Date: Thu, 4 Apr 2024 10:34:40 +0200 Subject: [PATCH 7/7] fix(utils): Vim:E475 after adding opts to jobstart wrapper Looks like I've broken open and save after adding opts. This should adress this. For some reason vim.fn.jobstart() can't handle an empty table as opts. Maybe someone has a better solution that this, but this works for now. --- lua/markmap/utils.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/markmap/utils.lua b/lua/markmap/utils.lua index a23c82a..07bf64b 100644 --- a/lua/markmap/utils.lua +++ b/lua/markmap/utils.lua @@ -16,9 +16,9 @@ local is_windows = vim.uv.os_uname().sysname == "Windows_NT" ---@return number job pid of the job, so we can stop it later. M.jobstart = function(cmd, arguments, opts) if is_windows then - return vim.fn.jobstart({ cmd, unpack(arguments) }, opts) + return opts and vim.fn.jobstart({ cmd, unpack(arguments) }, opts) or vim.fn.jobstart({ cmd, unpack(arguments) }) else - return vim.fn.jobstart(cmd .. " " .. table.concat(arguments, " "), opts) + return opts and vim.fn.jobstart(cmd .. " " .. table.concat(arguments, " "), opts) or vim.fn.jobstart(cmd .. " " .. table.concat(arguments, " ")) end end