diff --git a/lua/markview/init.lua b/lua/markview/init.lua index ea7d2f3..d592a24 100644 --- a/lua/markview/init.lua +++ b/lua/markview/init.lua @@ -91,6 +91,21 @@ function M.open(bufnr) callback = debounced_push, }) + local debounced_scroll = util.debounce(function() + if not vim.api.nvim_buf_is_valid(bufnr) then + return + end + local cursor = vim.api.nvim_win_get_cursor(0) + local total = vim.api.nvim_buf_line_count(bufnr) + srv.scroll_to(cursor[1], total) + end, 50) + + vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { + group = augroup, + buffer = bufnr, + callback = debounced_scroll, + }) + vim.api.nvim_create_autocmd("BufDelete", { group = augroup, buffer = bufnr, diff --git a/lua/markview/server.lua b/lua/markview/server.lua index ec501c9..d69b4fc 100644 --- a/lua/markview/server.lua +++ b/lua/markview/server.lua @@ -41,7 +41,7 @@ end ---@param port number ---@param config table ---@param base_dir string|nil Directory of the Markdown file (for serving relative images) ----@return { push: fun(markdown: string), stop: fun() } +---@return { push: fun(markdown: string), scroll_to: fun(cursor_line: number, total_lines: number), stop: fun() } function M.start(bufnr, port, config, base_dir) local clients = {} -- SSE client handles local current_html = "" @@ -226,6 +226,25 @@ function M.start(bufnr, port, config, base_dir) clients = alive end + local function scroll_to(cursor_line, total_lines) + local ratio = cursor_line / math.max(total_lines, 1) + local payload = "event: scroll\ndata: " .. string.format("%.6f", ratio) .. "\n\n" + local alive = {} + for _, c in ipairs(clients) do + if not c:is_closing() then + c:write(payload, function(write_err) + if write_err then + if not c:is_closing() then + c:close() + end + end + end) + table.insert(alive, c) + end + end + clients = alive + end + local function stop() -- Close all SSE clients for _, c in ipairs(clients) do @@ -239,7 +258,7 @@ function M.start(bufnr, port, config, base_dir) end end - return { push = push, stop = stop } + return { push = push, scroll_to = scroll_to, stop = stop } end return M diff --git a/lua/markview/template.lua b/lua/markview/template.lua index 05b1366..aeca32e 100644 --- a/lua/markview/template.lua +++ b/lua/markview/template.lua @@ -248,6 +248,13 @@ local function build_js(theme) evtSource.onerror = function() { // Reconnect is handled automatically by EventSource }; + evtSource.addEventListener('scroll', function(e) { + var ratio = parseFloat(e.data); + var maxScroll = document.documentElement.scrollHeight - window.innerHeight; + if (maxScroll > 0) { + window.scrollTo({ top: ratio * maxScroll, behavior: 'smooth' }); + } + }); window.addEventListener('load', afterRender); })();