diff --git a/ftplugin/markdown.lua b/ftplugin/markdown.lua index 8d9aed0..05a2846 100644 --- a/ftplugin/markdown.lua +++ b/ftplugin/markdown.lua @@ -75,17 +75,33 @@ vim.api.nvim_create_autocmd({ "BufWinEnter" }, { markview.state.buf_states[buffer] = true; - local parsed_content = markview.parser.init(buffer, markview.configuration); + local lines = vim.api.nvim_buf_line_count(buffer); markview.renderer.clear(buffer); - markview.renderer.render(buffer, parsed_content, markview.configuration) + + 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); 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 - markview.keymaps.init(buffer, window, parsed_content, markview.configuration); + markview.keymaps.init(buffer, window, keymap_content, markview.configuration); end end }); @@ -123,28 +139,45 @@ vim.api.nvim_create_autocmd({ "ModeChanged", "TextChanged" }, { ::noCallbacks:: + -- Mode is a valid mode if markview.configuration.modes and vim.list_contains(markview.configuration.modes, mode) then - local parsed_content = markview.parser.init(buffer, markview.configuration); - local parse_start, parse_stop = utils.get_cursor_range(buffer, windows[1]); + local lines = vim.api.nvim_buf_line_count(buffer); + local parsed_content; markview.renderer.clear(buffer); - local partial_contents = markview.parser.parse_range(event.buf, markview.configuration, parse_start, parse_stop); - local current_range = markview.renderer.get_content_range(partial_contents); + if lines < (markview.configuration.max_length or 1000) then + parsed_content = markview.parser.init(buffer, markview.configuration); - if markview.configuration.hybrid_modes and vim.list_contains(markview.configuration.hybrid_modes, mode) then - markview.renderer.render(buffer, parsed_content, markview.configuration, parse_start, parse_stop); - markview.renderer.clear_content_range(event.buf, partial_contents) - else markview.renderer.render(buffer, parsed_content, markview.configuration); - end + 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)); - -- Or else things won't render on first redraw from the other autocmd - markview.renderer.update_range(buffer, current_range); + parsed_content = markview.parser.parse_range(buffer, markview.configuration, start, stop); + + markview.renderer.render(buffer, parsed_content, markview.configuration) + end for _, window in ipairs(windows) do markview.keymaps.init(buffer, window, 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]) + + -- Mode is not a valid mode. Clear decorations. else -- Call an extra redraw to flush out screen updates markview.renderer.clear(buffer); @@ -186,35 +219,47 @@ vim.api.nvim_create_autocmd(events, { move_timer:stop(); move_timer:start(100, 0, vim.schedule_wrap(function () - if not _G.__markview_render_ranges then - _G.__markview_render_ranges = {}; - end + local lines = vim.api.nvim_buf_line_count(event.buf); + local buffer = event.buf; - if not _G.__markview_render_ranges[event.buf] then - _G.__markview_render_ranges[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 - local windows = utils.find_attached_wins(event.buf); + if parsed_content and #parsed_content > 0 then + local windows = utils.find_attached_wins(event.buf); - local old_start, old_stop = _G.__markview_render_ranges[event.buf][1], _G.__markview_render_ranges[event.buf][2]; - local parse_start, parse_stop = utils.get_cursor_range(event.buf, windows[1]); + for _, window in ipairs(windows) do + markview.keymaps.init(buffer, window, parsed_content, markview.configuration); + end + end - local prev_contents = markview.parser.parse_range(event.buf, markview.configuration, old_start, old_stop); - local partial_contents = markview.parser.parse_range(event.buf, markview.configuration, parse_start, parse_stop); + 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 current_range = markview.renderer.get_content_range(partial_contents); + local under_cursor = markview.parser.parse_range(event.buf, markview.configuration, start, stop); + local clear_range = markview.renderer.get_content_range(under_cursor); - if _G.__markview_render_ranges[event.buf] and vim.deep_equal(_G.__markview_render_ranges[event.buf], current_range) then - markview.renderer.clear_content_range(event.buf, partial_contents) + if not clear_range or not clear_range[1] or not clear_range[2] then return; end - markview.renderer.clear_content_range(event.buf, partial_contents) - markview.renderer.clear_content_range(event.buf, prev_contents); - markview.renderer.clear(event.buf, parse_start, parse_stop); - - markview.renderer.render_in_range(event.buf, prev_contents, markview.configuration); - markview.renderer.update_range(event.buf, current_range); + markview.renderer.clear(event.buf, clear_range[1], clear_range[2]) end)); end }) diff --git a/lua/definitions.lua b/lua/definitions.lua index ee5b70a..d27a29e 100644 --- a/lua/definitions.lua +++ b/lua/definitions.lua @@ -19,6 +19,12 @@ --- List of modes where both raw & preview is shown ---@field hybrid_modes string[]? --- +--- Max number of lines in a file to do full rendering +---@field max_length number? +--- +--- Number of lines to render on partial render mode +---@field render_range number? +--- --- Callbacks for plugin states ---@field callbacks markview.config.callbacks? --- @@ -65,6 +71,12 @@ --- List of modes where both raw & preview is shown ---@field hybrid_modes string[]? --- +--- Max number of lines in a file to do full rendering +---@field max_length number? +--- +--- Number of lines to render on partial render mode +---@field render_range number? +--- --- Options for various plugins states ---@field callbacks markview.config.callbacks --- diff --git a/lua/markview.lua b/lua/markview.lua index bf87bf8..b40d8ff 100644 --- a/lua/markview.lua +++ b/lua/markview.lua @@ -41,8 +41,10 @@ markview.deep_merge = function (behavior, tbl_1, tbl_2) for index, item in ipairs(value) do if not markview.list_contains(tbl_1[key], item) then table.insert(tbl_1[key], item); - else + elseif tbl_1[key][index] and type(tbl_1[key][index]) == "table" and type(item) == "table" then tbl_1[key][index] = markview.deep_merge(behavior, tbl_1[key][index], item); + elseif not markview.list_contains(tbl_1[key], item) then + tbl_1[key][index] = item; end end else @@ -70,31 +72,49 @@ markview.hl_exits = function (hl_list, hl) return false; end +markview.added_hls = {}; + +markview.remove_hls = function () + if vim.tbl_isempty(markview.added_hls) then + return; + end + + for _, hl in ipairs(markview.added_hls) do + if vim.fn.hlexists("Markview" .. hl) == 1 then + vim.api.nvim_set_hl(0, "Markview" .. hl, {}); + end + end +end + markview.add_hls = function (obj) - local added = {}; + markview.added_hls = {}; local use_hl = {}; for _, hl in ipairs(obj) do if hl.output and type(hl.output) == "function" and pcall(hl.output) then local _o = hl.output(); + local _n = {}; for _, item in ipairs(_o) do local exists, index = markview.hl_exits(use_hl, item); if exists == true then table.remove(use_hl, index); + else + table.insert(_n, item.group_name); end end - use_hl = vim.list_extend(use_hl, _o) + use_hl = vim.list_extend(use_hl, _o); + markview.added_hls = vim.list_extend(markview.added_hls, _n); elseif hl.group_name and hl.value then - local contains, index = markview.list_contains(added, hl.group_name); + local contains, index = markview.list_contains(markview.added_hls, hl.group_name); if contains == true and index then use_hl[index] = hl; else table.insert(use_hl, hl) - table.insert(added, hl.group_name); + table.insert(markview.added_hls, hl.group_name); end end end @@ -124,16 +144,16 @@ markview.global_options = {}; ---@type markview.config markview.configuration = { callbacks = { - on_enable = function (buffer, window) + on_enable = function (_, window) vim.wo[window].conceallevel = 2; vim.wo[window].concealcursor = "nc"; end, - on_disable = function (buffer, window) + on_disable = function (_, window) vim.wo[window].conceallevel = 0; vim.wo[window].concealcursor = ""; end, - on_mode_change = function (buffer, window, mode) + on_mode_change = function (_, window, mode) if vim.list_contains(markview.configuration.modes, mode) then vim.wo[window].conceallevel = 2; else @@ -1594,11 +1614,17 @@ end, { }) markview.setup = function (user_config) + if user_config and user_config.highlight_groups then + markview.configuration.highlight_groups = vim.list_extend(markview.configuration.highlight_groups, user_config.highlight_groups); + user_config.highlight_groups = nil; + end + ---@type markview.config -- Merged configuration tables - markview.configuration = markview.deep_merge("force", markview.configuration, user_config or {}); + markview.configuration = vim.tbl_deep_extend("force", markview.configuration, user_config or {}); if vim.islist(markview.configuration.highlight_groups) then + markview.remove_hls(); markview.add_hls(markview.configuration.highlight_groups); end diff --git a/lua/markview/renderer.lua b/lua/markview/renderer.lua index 3914131..6fa0c46 100644 --- a/lua/markview/renderer.lua +++ b/lua/markview/renderer.lua @@ -1725,6 +1725,8 @@ renderer.render = function (buffer, parsed_content, config_table, conceal_start, _G.__markview_render_ranges[buffer] = {}; end + -- vim.print(#parsed_content) + for _, content in ipairs(_G.__markview_views[buffer]) do local type = content.type; local fold_closed = vim.fn.foldclosed(content.row_start + 1);