From e7e91ad3320c8a3feabba27f5ac79953f99c2632 Mon Sep 17 00:00:00 2001 From: Shawon Date: Mon, 26 Aug 2024 09:15:56 +0600 Subject: [PATCH] feat!: Added the ability to use the plugin in other filetypes - A few minor performance improvememts have been made. - Code blocks now support the default conceals from markdown. - Fixed a bug causing things inside code blocks(e.g. markdown code blocks) to render And various minor improvements! --- README.md | 1 + ftplugin/markdown.lua | 309 ---------------------------------------- lua/definitions.lua | 6 + lua/markview.lua | 1 + lua/markview/parser.lua | 118 ++++++++++++--- plugin/markview.lua | 204 ++++++++++++++++++++++++++ 6 files changed, 312 insertions(+), 327 deletions(-) delete mode 100644 ftplugin/markdown.lua create mode 100644 plugin/markview.lua diff --git a/README.md b/README.md index 9edccc1..2e6dcc1 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Markview.nvim comes with a ton of features such as, - Fully customisable setup! You can customise everything to your needs! - A `hybrid mode` that allows rendering in real-time! It will even unconceal nodes under the cursor. - Dynamic `highlight groups` that allows support for almost any colorscheme! +- Supports other filetypes too(e.g. quarto/.qmd, r markdown/.rmd for now)! You can also add your own one. And a lot more to come! diff --git a/ftplugin/markdown.lua b/ftplugin/markdown.lua deleted file mode 100644 index 545bc1e..0000000 --- a/ftplugin/markdown.lua +++ /dev/null @@ -1,309 +0,0 @@ -local markview = require("markview"); -local utils = require("markview.utils"); - -local ts_available, treesitter_parsers = pcall(require, "nvim-treesitter.parsers"); -local function parser_installed(parser) - return (ts_available and treesitter_parsers.has_parser(parser)) or pcall(vim.treesitter.query.get, parser, "highlights") -end - --- Check for requirements -if vim.fn.has("nvim-0.10") == 0 then - vim.notify("[ markview.nvim ] : This plugin is only available on version 0.10.0 and higher!", vim.log.levels.WARN); - return; -elseif not parser_installed("markdown") then - vim.notify("[ markview.nvim ] : Treesitter parser for 'markdown' wasn't found!", vim.log.levels.WARN); - return; -elseif not parser_installed("markdown_inline") then - vim.notify("[ markview.nvim ] : Treesitter parser for 'markdown_inline' wasn't found!", vim.log.levels.WARN); - return; -elseif not parser_installed("html") then - vim.notify("[ markview.nvim ] : Treesitter parser for 'html' wasn't found! It is required for basic html tag support.", vim.log.levels.WARN); - return; -end - -if vim.islist(markview.configuration.buf_ignore) and vim.list_contains(markview.configuration.buf_ignore, vim.bo.buftype) then - return -end - --- Don't add hls unless absolutely necessary -if not markview.set_hl_complete and vim.islist(markview.configuration.highlight_groups) then - markview.add_hls(markview.configuration.highlight_groups) - markview.set_hl_complete = true; -end - -local markview_augroup = vim.api.nvim_create_augroup("markview_buf_" .. vim.api.nvim_get_current_buf(), { clear = true }); - -vim.api.nvim_create_autocmd({ "BufWinEnter" }, { - buffer = vim.api.nvim_get_current_buf(), - group = markview_augroup, - - callback = function (event) - local buffer = event.buf; - local windows = utils.find_attached_wins(event.buf); - - if not vim.list_contains(markview.attached_buffers, buffer) then - table.insert(markview.attached_buffers, buffer); - markview.attached_windows = vim.list_extend(markview.attached_windows, windows) - end - - if markview.state.enable == false then - -- Call the on_disable callback before exiting - if not markview.configuration.callbacks or not markview.configuration.callbacks.on_disable then - return; - end - - for _, window in ipairs(windows) do - pcall(markview.configuration.callbacks.on_disable, buffer, window); - end - - return; - end - - if markview.state.buf_states[buffer] == false then - -- Call the on_disable callback before exiting - -- Even if only the buffer is disabled - if not markview.configuration.callbacks or not markview.configuration.callbacks.on_disable then - return; - end - - for _, window in ipairs(windows) do - pcall(markview.configuration.callbacks.on_disable, buffer, window); - end - - return; - end - - markview.state.buf_states[buffer] = true; - - local lines = vim.api.nvim_buf_line_count(buffer); - - markview.renderer.clear(buffer); - - if lines < (markview.configuration.max_length or 1000) then - local parsed_content = markview.parser.init(buffer, markview.configuration); - - markview.renderer.render(buffer, parsed_content, markview.configuration) - else - local cursor = vim.api.nvim_win_get_cursor(0); - local start = math.max(0, cursor[1] - (markview.configuration.render_range or 100)); - local stop = math.min(lines, cursor[1] + (markview.configuration.render_range or 100)); - - local parsed_content = markview.parser.parse_range(buffer, markview.configuration, start, stop); - - markview.renderer.render(buffer, parsed_content, markview.configuration) - end - - -- This needs all of the buffer to be parsed - local keymap_content = markview.parser.init(buffer, markview.configuration); - - - markview.keymaps.init(buffer, keymap_content, markview.configuration); - for _, window in ipairs(windows) do - if markview.configuration.callbacks and markview.configuration.callbacks.on_enable then - pcall(markview.configuration.callbacks.on_enable, buffer, window); - end - end - end -}); - -local cached_mode = nil; -local mode_timer = vim.uv.new_timer(); - -local update_events = { "BufEnter", "ModeChanged", "TextChanged" }; - -if vim.list_contains(markview.configuration.modes, "n") or vim.list_contains(markview.configuration.modes, "v") then - table.insert(update_events, "CursorMoved"); -end - -if vim.list_contains(markview.configuration.modes, "i") then - table.insert(update_events, "CursorMovedI"); - table.insert(update_events, "TextChangedI"); -- For smoother experience when writing, potentially can cause bugs -end - -local prev_pos = vim.api.nvim_win_get_cursor(0)[1]; - --- ISSUE: Work in progress -vim.api.nvim_create_autocmd(update_events, { - buffer = vim.api.nvim_get_current_buf(), - group = markview_augroup, - - callback = function (event) - local buffer = event.buf; - local windows = utils.find_attached_wins(event.buf); - - local mode_debounce = 50; - - local mode = vim.api.nvim_get_mode().mode; - - if not vim.list_contains({ "CursorMoved", "CursorMovedI" }, event.event) and cached_mode and cached_mode == mode then - mode_debounce = 0; - end - - mode_timer:stop(); - mode_timer:start(mode_debounce, 0, vim.schedule_wrap(function () - if markview.state.enable == false then - return; - end - - if markview.state.buf_states[buffer] == false then - return; - end - - -- In case something managed to change the mode - mode = vim.api.nvim_get_mode().mode; - - local current_pos = vim.api.nvim_win_get_cursor(0)[1]; - - -- Experimental - -- May introduce bugs - if cached_mode == mode and vim.list_contains({ "CursorMoved", "CursorMovedI" }, event.event) and math.abs(prev_pos - current_pos) < 100 then - prev_pos = current_pos; - return; - end - - -- Only on mode change or if the mode changed due to text changed - if mode ~= cached_mode or event.event == "ModeChanged" then - -- Call the on_mode_change callback before exiting - if not markview.configuration.callbacks or not markview.configuration.callbacks.on_mode_change then - goto noCallbacks; - end - - for _, window in ipairs(windows) do - pcall(markview.configuration.callbacks.on_mode_change, buffer, window, mode); - end - end - - ::noCallbacks:: - - cached_mode = mode; -- Still gotta update the cache - - -- Mode is a valid mode - if markview.configuration.modes and vim.list_contains(markview.configuration.modes, mode) then - local lines = vim.api.nvim_buf_line_count(buffer); - local parsed_content; - - markview.renderer.clear(buffer); - - if lines < (markview.configuration.max_length or 1000) then - parsed_content = markview.parser.init(buffer, markview.configuration); - - markview.renderer.render(buffer, parsed_content, markview.configuration); - else - local cursor = vim.api.nvim_win_get_cursor(0); - local start = math.max(0, cursor[1] - (markview.configuration.render_range or 100)); - local stop = math.min(lines, cursor[1] + (markview.configuration.render_range or 100)); - - parsed_content = markview.parser.parse_range(buffer, markview.configuration, start, stop); - - markview.renderer.render(buffer, parsed_content, markview.configuration) - end - - markview.keymaps.init(buffer, parsed_content, markview.configuration); - - if not markview.configuration.hybrid_modes or not vim.list_contains(markview.configuration.hybrid_modes, mode) then - return; - end - - local cursor = vim.api.nvim_win_get_cursor(0); - local start = math.max(0, cursor[1] - 1); - local stop = math.min(lines, cursor[1]); - - local under_cursor = markview.parser.parse_range(event.buf, markview.configuration, start, stop); - local clear_range = markview.renderer.get_content_range(under_cursor); - - if not clear_range or not clear_range[1] or not clear_range[2] then - return; - end - - markview.renderer.clear(event.buf, clear_range[1], clear_range[2]) - - -- Mode is not a valid mode. Clear decorations. - else - -- Call an extra redraw to flush out screen updates - markview.renderer.clear(buffer); - vim.cmd("redraw!"); - end - end)); - end -}); - -if not markview.configuration.hybrid_modes then - return; -end - -local events = {} -local move_timer = vim.uv.new_timer(); - -if vim.list_contains(markview.configuration.hybrid_modes, "n") or vim.list_contains(markview.configuration.hybrid_modes, "v") then - table.insert(events, "CursorMoved"); -end - -if vim.list_contains(markview.configuration.hybrid_modes, "i") then - table.insert(events, "CursorMovedI"); - table.insert(events, "TextChangedI"); -- For smoother experience when writing, potentially can cause bugs -end - -vim.api.nvim_create_autocmd(events, { - buffer = vim.api.nvim_get_current_buf(), - group = markview_augroup, - - callback = function (event) - if markview.state.enable == false then - move_timer:stop(); - return; - end - - if markview.state.buf_states[event.buf] == false then - move_timer:stop(); - return; - end - - move_timer:stop(); - move_timer:start(100, 0, vim.schedule_wrap(function () - local mode = vim.api.nvim_get_mode().mode; - - if not markview.configuration.hybrid_modes or not vim.list_contains(markview.configuration.hybrid_modes, mode) then - return; - end - - local lines = vim.api.nvim_buf_line_count(event.buf); - local buffer = event.buf; - - local parsed_content; - - markview.renderer.clear(buffer); - - if lines < (markview.configuration.max_length or 1000) then - parsed_content = markview.parser.init(buffer, markview.configuration); - - markview.renderer.render(buffer, parsed_content, markview.configuration) - else - local cursor = vim.api.nvim_win_get_cursor(0); - local start = math.max(0, cursor[1] - (markview.configuration.render_range or 100)); - local stop = math.min(lines, cursor[1] + (markview.configuration.render_range or 100)); - - parsed_content = markview.parser.parse_range(buffer, markview.configuration, start, stop); - - markview.renderer.render(buffer, parsed_content, markview.configuration) - end - - if parsed_content and #parsed_content > 0 then - markview.keymaps.init(buffer, parsed_content, markview.configuration); - end - - local cursor = vim.api.nvim_win_get_cursor(0); - local start = math.max(0, cursor[1] - 1); - local stop = math.min(lines, cursor[1]); - - local under_cursor = markview.parser.parse_range(event.buf, markview.configuration, start, stop); - local clear_range = markview.renderer.get_content_range(under_cursor); - - if not clear_range or not clear_range[1] or not clear_range[2] then - return; - end - - markview.renderer.clear(event.buf, clear_range[1], clear_range[2]) - end)); - end -}) - diff --git a/lua/definitions.lua b/lua/definitions.lua index 6cb3d26..6228968 100644 --- a/lua/definitions.lua +++ b/lua/definitions.lua @@ -10,6 +10,9 @@ --- List of custom highlight groups ---@field highlight_groups table[]? --- +--- List of filetypes where the plugin will be active +---@field filetypes string[] +--- --- List of buffer types to ignore ---@field buf_ignore string[]? --- @@ -62,6 +65,9 @@ --- List of custom highlight groups ---@field highlight_groups table[]? --- +--- List of filetypes where the plugin will be active +---@field filetypes string[] +--- --- List of buffer types to ignore ---@field buf_ignore string[]? --- diff --git a/lua/markview.lua b/lua/markview.lua index 7d0570b..86c6878 100644 --- a/lua/markview.lua +++ b/lua/markview.lua @@ -143,6 +143,7 @@ markview.global_options = {}; ---@type markview.config markview.configuration = { + filetypes = { "markdown", "quarto", "rmd" }, callbacks = { on_enable = function (_, window) vim.wo[window].conceallevel = 2; diff --git a/lua/markview/parser.lua b/lua/markview/parser.lua index ab8a7d8..bd6579c 100644 --- a/lua/markview/parser.lua +++ b/lua/markview/parser.lua @@ -1,7 +1,61 @@ local parser = {}; +local lang = require("markview.languages") -- local renderer = require("markview/renderer"); parser.cached_conf = {}; +parser.avoid_ranges = {}; + +parser.get_md_len = function (text) + local final_string = text; + local len = vim.fn.strdisplaywidth(text); + + for inline_code in final_string:gmatch("`([^`]+)`") do + len = len - 2; + + local escaped = inline_code:gsub("%p", "%%%1"); + final_string = final_string:gsub("`" .. escaped .. "`", inline_code:gsub(".", "|")); + end + + for link, address in final_string:gmatch("!%[([^%]]+)%]%(([^%)]+)%)") do + len = len - vim.fn.strdisplaywidth("![]()" .. address); + + final_string = final_string:gsub("%!%[" .. link .. "%]%(" .. address .. "%)", link); + end + + for link, address in final_string:gmatch("%[([^%]]+)%]%(([^%)]+)%)") do + len = len - vim.fn.strdisplaywidth("[]()" .. address); + + final_string = final_string:gsub("%[" .. link .. "%]%(" .. address .. "%)", link); + end + + for link, address in final_string:gmatch("[^!]%[([^%]]+)%]%[([^%]]+)%]") do + len = len - vim.fn.strdisplaywidth("[" .. "][" .. address .. "]"); + + final_string = final_string:gsub("%[" .. link .. "%]%[" .. address .. "%]", link); + end + + for pattern in final_string:gmatch("%[([^%]]+)%]") do + len = len - 2; + final_string = final_string:gsub( "[" .. pattern .. "]", pattern); + end + + for str_a, internal, str_b in final_string:gmatch("([*_]+)([^*]+)([*_]+)") do + local valid_signs = math.max(vim.fn.strdisplaywidth(str_a), vim.fn.strdisplaywidth(str_b)); + + for s = 1, valid_signs do + local a = str_a:sub(s, s); + local b = str_b:reverse():sub(s, s); + + if a == b then + len = len - 2; + + final_string = final_string:gsub(a .. internal .. b, internal); + end + end + end + + return len, final_string; +end parser.fiter_lines = function (buffer, from, to) local captured_lines = vim.api.nvim_buf_get_lines(buffer, from, to, false); @@ -139,7 +193,10 @@ parser.parsed_content = {}; ---@param buffer number ---@param TStree any parser.md = function (buffer, TStree, from, to) - if not parser.cached_conf or not parser.cached_conf.on_injected or parser.cached_conf.on_injected == false then + if not parser.cached_conf or + not parser.cached_conf.on_injected or + parser.cached_conf.on_injected == false + then local root = TStree:root(); local root_r_start, _, root_r_end, _ = root:range(); local buf_lines = vim.api.nvim_buf_line_count(buffer); @@ -231,10 +288,26 @@ parser.md = function (buffer, TStree, from, to) local block_start = vim.api.nvim_buf_get_lines(buffer, row_start, row_start + 1, false)[1]; + local language_string, additional_info = "", nil; + + if block_start:match("%s*```{{?([^}]*)}}?") then + language_string = block_start:match("%s*```{{?([^}]*)}}?"); + additional_info = block_start:match("%s*```{{?[^}]*}}?%s*(.*)$"); + elseif block_start:match("%s*```(%S*)$") then + language_string = block_start:match("%s*```(%S*)$"); + elseif block_start:match("%s*```(%S*)%s*") then + language_string = block_start:match("%s*```(%S*)%s"); + additional_info = block_start:match("%s*```%S*%s+(.*)$"); + end + for i = 1,(row_end - row_start) - 2 do local this_code = vim.api.nvim_buf_get_lines(buffer, row_start + i, row_start + i + 1, false)[1]; local len = vim.fn.strchars(this_code) or 0; + if vim.list_contains(parser.cached_conf.filetypes or {}, string.lower(lang.get_name(language_string))) then + len = parser.get_md_len(this_code) + end + if len > highest_len then highest_len = len; end @@ -243,17 +316,9 @@ parser.md = function (buffer, TStree, from, to) table.insert(line_lens, len); end - local language_string, additional_info = "", nil; - - if block_start:match("%s*```{{?([^}]*)}}?") then - language_string = block_start:match("%s*```{{?([^}]*)}}?"); - additional_info = block_start:match("%s*```{{?[^}]*}}?%s*(.*)$"); - elseif block_start:match("%s*```(%S*)$") then - language_string = block_start:match("%s*```(%S*)$"); - elseif block_start:match("%s*```(%S*)%s*") then - language_string = block_start:match("%s*```(%S*)%s"); - additional_info = block_start:match("%s*```%S*%s+(.*)$"); - end + -- So that we don't accidentally parse the wrong range + -- Note: We won't parse only the inside of the code block + table.insert(parser.avoid_ranges, { row_start + 1, row_end - 1 }); table.insert(parser.parsed_content, { node = capture_node, @@ -504,6 +569,20 @@ end ---@param buffer number ---@param TStree any parser.md_inline = function (buffer, TStree, from, to) + if not parser.cached_conf or + not parser.cached_conf.on_injected or + parser.cached_conf.on_injected == false + then + local root = TStree:root(); + local root_r_start, _, root_r_end, _ = root:range(); + + for _, range in ipairs(parser.avoid_ranges) do + if root_r_start >= range[1] and root_r_end <= range[2] then + return; + end + end + end + local scanned_queies = vim.treesitter.query.parse("markdown_inline", [[ ((shortcut_link) @callout) @@ -665,14 +744,17 @@ parser.md_inline = function (buffer, TStree, from, to) end parser.html = function (buffer, TStree, from, to) - if not parser.cached_conf or not parser.cached_conf.on_injected or parser.cached_conf.on_injected == false then + if not parser.cached_conf or + not parser.cached_conf.on_injected or + parser.cached_conf.on_injected == false + then local root = TStree:root(); - local root_r_start, _, _, _ = root:range(); - - local start_line = vim.api.nvim_buf_get_lines(buffer, root_r_start - 1, root_r_start, false)[1] or ""; + local root_r_start, _, root_r_end, _ = root:range(); - if start_line:match("```") then - return; + for _, range in ipairs(parser.avoid_ranges) do + if root_r_start >= range[1] and root_r_end <= range[2] then + return; + end end end diff --git a/plugin/markview.lua b/plugin/markview.lua new file mode 100644 index 0000000..103a0ce --- /dev/null +++ b/plugin/markview.lua @@ -0,0 +1,204 @@ +local markview = require("markview"); +local utils = require("markview.utils"); + +local ts_available, treesitter_parsers = pcall(require, "nvim-treesitter.parsers"); +local function parser_installed(parser) + return (ts_available and treesitter_parsers.has_parser(parser)) or pcall(vim.treesitter.query.get, parser, "highlights") +end + +-- Check for requirements +if vim.fn.has("nvim-0.10") == 0 then + vim.notify("[ markview.nvim ] : This plugin is only available on version 0.10.0 and higher!", vim.log.levels.WARN); + return; +elseif not parser_installed("markdown") then + vim.notify("[ markview.nvim ] : Treesitter parser for 'markdown' wasn't found!", vim.log.levels.WARN); + return; +elseif not parser_installed("markdown_inline") then + vim.notify("[ markview.nvim ] : Treesitter parser for 'markdown_inline' wasn't found!", vim.log.levels.WARN); + return; +elseif not parser_installed("html") then + vim.notify("[ markview.nvim ] : Treesitter parser for 'html' wasn't found! It is required for basic html tag support.", vim.log.levels.WARN); + return; +end + +if markview.configuration.highlight_groups then + markview.add_hls(markview.configuration.highlight_groups) +end + +local buf_render = function (buffer) + local lines = vim.api.nvim_buf_line_count(buffer); + local parsed_content; + + local mode = vim.api.nvim_get_mode().mode; + + if lines < (markview.configuration.max_length or 1000) then + -- Buffer isn't too big. Render everything + parsed_content = markview.parser.init(buffer, markview.configuration); + + markview.renderer.render(buffer, parsed_content, markview.configuration) + else + -- Buffer is too big, render only parts of it + local cursor = vim.api.nvim_win_get_cursor(0); + local start = math.max(0, cursor[1] - (markview.configuration.render_range or 100)); + local stop = math.min(lines, cursor[1] + (markview.configuration.render_range or 100)); + + parsed_content = markview.parser.parse_range(buffer, markview.configuration, start, stop); + + markview.renderer.render(buffer, parsed_content, markview.configuration) + end + + markview.keymaps.init(buffer, parsed_content, markview.configuration); + + -- Don't do hybrid mode stuff unless needed + if not markview.configuration.hybrid_modes or not vim.list_contains(markview.configuration.hybrid_modes, mode) then + return; + end + + local win = utils.find_attached_wins(buffer)[1]; + + -- Get the cursor + local cursor = vim.api.nvim_win_get_cursor(win or 0); + + -- Range to start & stop parsing + local start = math.max(0, cursor[1] - 1); + local stop = math.min(lines, cursor[1]); + + -- Get the contents range to clear + local under_cursor = markview.parser.parse_range(buffer, markview.configuration, start, stop); + local clear_range = markview.renderer.get_content_range(under_cursor); + + -- Content range was invalid, nothing to clear + if not clear_range or not clear_range[1] or not clear_range[2] then + return; + end + + markview.renderer.clear(buffer, clear_range[1], clear_range[2]) +end + + + +local redraw_autocmd = function (augroup, buffer) + local update_events = { "BufEnter", "ModeChanged", "TextChanged" }; + + if vim.list_contains(markview.configuration.modes, "n") or vim.list_contains(markview.configuration.modes, "v") then + table.insert(update_events, "CursorMoved"); + end + + if vim.list_contains(markview.configuration.modes, "i") then + table.insert(update_events, "CursorMovedI"); + table.insert(update_events, "TextChangedI"); -- For smoother experience when writing, potentially can cause bugs + end + + -- Mode + local cached_mode = vim.api.nvim_get_mode().mode; + local timer = vim.uv.new_timer(); + + vim.api.nvim_create_autocmd(update_events, { + buffer = buffer, + group = augroup, + callback = function (event) + local windows = utils.find_attached_wins(buffer); + local debounce = 50; + + -- Current mode + local mode = vim.api.nvim_get_mode().mode; + + if event.event == "ModeChanged" and cached_mode == mode then + debounce = 0; + end + + timer:stop(); + timer:start(debounce, 0, vim.schedule_wrap(function () + if markview.state.enable == false or markview.state.buf_states[buffer] == false then + return; + end + + -- Only on mode change or if the mode changed due to text changed + if mode ~= cached_mode or event.event == "ModeChanged" then + -- Call the on_mode_change callback before exiting + if not markview.configuration.callbacks or not markview.configuration.callbacks.on_mode_change then + goto noCallbacks; + end + + for _, window in ipairs(windows) do + pcall(markview.configuration.callbacks.on_mode_change, buffer, window, mode); + end + end + + ::noCallbacks:: + + cached_mode = mode; -- Still gotta update the cache + + if vim.list_contains(markview.configuration.modes, mode) then + markview.renderer.clear(buffer); + buf_render(buffer); + else + markview.renderer.clear(buffer); + vim.cmd("redraw!"); + end + end)); + end + }); +end + +vim.api.nvim_create_autocmd({ "BufWinEnter" }, { + desc = "Attaches markview to the buffers", + callback = function (event) + local buffer = event.buf; + + local ft = vim.bo[buffer].filetype; + local bt = vim.bo[buffer].buftype; + + --- Incorrect file type + if not vim.list_contains(markview.configuration.filetypes or { "markdown" }, ft) then + return; + end + + -- Incorrect buffer type + if vim.islist(markview.configuration.buf_ignore) and vim.list_contains(markview.configuration.buf_ignore, bt) then + return + end + + local windows = utils.find_attached_wins(buffer); + + -- If not attached then attach + if not vim.list_contains(markview.attached_buffers, buffer) then + table.insert(markview.attached_buffers, buffer); + markview.attached_windows = vim.list_extend(markview.attached_windows, windows); + end + + -- Plugin is disabled + if markview.state.enable == false or markview.state.buf_states[buffer] == false then + -- Call the on_disable callback before exiting + if not markview.configuration.callbacks or not markview.configuration.callbacks.on_disable then + return; + end + + for _, window in ipairs(windows) do + pcall(markview.configuration.callbacks.on_disable, buffer, window); + end + + return; + end + + -- Set state to true and call the callback + markview.state.buf_states[buffer] = true; + + for _, window in ipairs(windows) do + if markview.configuration.callbacks and markview.configuration.callbacks.on_enable then + pcall(markview.configuration.callbacks.on_enable, buffer, window); + end + end + + -- Clear the buffer before rendering things + markview.renderer.clear(buffer); + buf_render(buffer); + + -- Augroup for the special autocmds + local markview_augroup = vim.api.nvim_create_augroup("markview_buf_" .. buffer, { clear = true }); + + redraw_autocmd(markview_augroup, buffer); + end +}) + +