diff --git a/README.md b/README.md index 8e5430d..4082377 100644 --- a/README.md +++ b/README.md @@ -205,10 +205,9 @@ require("quicker").setup({ -- Keep the cursor to the right of the filename and lnum columns constrain_cursor = true, highlight = { - -- Use treesitter highlights. Can be true, false, or "fast" - -- "fast" - only use highlights from buffers that are already parsed + -- Use treesitter highlighting treesitter = true, - -- Use LSP semantic token highlights + -- Use LSP semantic token highlighting lsp = true, }, -- Options for customizing the display of the quickfix list diff --git a/doc/quicker.txt b/doc/quicker.txt index a9e3047..cb287af 100644 --- a/doc/quicker.txt +++ b/doc/quicker.txt @@ -38,10 +38,9 @@ OPTIONS *quicker-option -- Keep the cursor to the right of the filename and lnum columns constrain_cursor = true, highlight = { - -- Use treesitter highlights. Can be true, false, or "fast" - -- "fast" - only use highlights from buffers that are already parsed + -- Use treesitter highlighting treesitter = true, - -- Use LSP semantic token highlights + -- Use LSP semantic token highlighting lsp = true, }, -- Options for customizing the display of the quickfix list @@ -99,10 +98,8 @@ setup({opts}) *quicker.setu options in `opts` {highlight} `nil|quicker.SetupHighlightConfig` Configure syntax highlighting - {treesitter} `nil|boolean|"fast"` Enable treesitter syntax - highlighting. "fast" will only use highlights from - buffers that are already parsed - {lsp} `nil|boolean` Use LSP semantic token highlights + {treesitter} `nil|boolean` Enable treesitter syntax highlighting + {lsp} `nil|boolean` Use LSP semantic token highlighting {edit} `nil|quicker.SetupEditConfig` {enabled} `nil|boolean` {autosave} `nil|boolean|"unmodified"` diff --git a/lua/quicker/config.lua b/lua/quicker/config.lua index 3b0885a..81e4c24 100644 --- a/lua/quicker/config.lua +++ b/lua/quicker/config.lua @@ -26,10 +26,9 @@ local default_config = { -- Keep the cursor to the right of the filename and lnum columns constrain_cursor = true, highlight = { - -- Use treesitter highlights. Can be true, false, or "fast" - -- "fast" - only use highlights from buffers that are already parsed + -- Use treesitter highlighting treesitter = true, - -- Use LSP semantic token highlights + -- Use LSP semantic token highlighting lsp = true, }, -- Options for customizing the display of the quickfix list @@ -157,12 +156,12 @@ end ---@field soft_end? string ---@class (exact) quicker.HighlightConfig ----@field treesitter boolean|"fast" +---@field treesitter boolean ---@field lsp boolean ---@class (exact) quicker.SetupHighlightConfig ----@field treesitter? boolean|"fast" Enable treesitter syntax highlighting. "fast" will only use highlights from buffers that are already parsed ----@field lsp? boolean Use LSP semantic token highlights +---@field treesitter? boolean Enable treesitter syntax highlighting +---@field lsp? boolean Use LSP semantic token highlighting ---@class (exact) quicker.EditConfig ---@field enabled boolean diff --git a/lua/quicker/display.lua b/lua/quicker/display.lua index e732edf..2a43969 100644 --- a/lua/quicker/display.lua +++ b/lua/quicker/display.lua @@ -105,8 +105,48 @@ local function calc_whitespace_prefix(items) return prefixes end +-- Highlighting can be slow because it requires loading buffers and parsing them with treesitter, so +-- we pipeline it and break it up with defers to keep the editor responsive. +local add_qf_highlights +local _pending_highlights = {} +local _running = false +local function do_next_highlight() + if _running then + return + end + _running = true + local next_info = table.remove(_pending_highlights, 1) + if next_info then + local ok, err = xpcall(add_qf_highlights, debug.traceback, next_info) + if not ok then + error(err) + end + end + if #_pending_highlights > 0 then + vim.defer_fn(function() + _running = false + do_next_highlight() + end, 20) + else + _running = false + end +end ---@param info QuickFixTextFuncInfo -local function add_qf_highlights(info) +local function schedule_highlights(info) + for _, i in ipairs(_pending_highlights) do + -- If we're already processing a highlight for this quickfix, just expand the range + if i.id == info.id and i.winid == info.winid and i.quickfix == info.quickfix then + i.start_idx = math.min(i.start_idx, info.start_idx) + i.end_idx = math.max(i.end_idx, info.end_idx) + return + end + end + table.insert(_pending_highlights, info) + vim.schedule(do_next_highlight) +end + +---@param info QuickFixTextFuncInfo +add_qf_highlights = function(info) local b = config.display.borders local qf_list if info.quickfix == 1 then @@ -131,14 +171,15 @@ local function add_qf_highlights(info) vim.api.nvim_buf_clear_namespace(qf_list.qfbufnr, err_ns, 0, -1) local prefixes = vim.b[qf_list.qfbufnr].qf_prefixes or {} + local start = vim.uv.hrtime() / 1e6 for i = info.start_idx, info.end_idx do ---@type QuickFixItem local item = qf_list.items[i] - if item.bufnr ~= 0 then + local line = lines[i] + if item.bufnr ~= 0 and line then if not vim.api.nvim_buf_is_loaded(item.bufnr) then vim.fn.bufload(item.bufnr) end - local line = lines[i] local src_line = vim.api.nvim_buf_get_lines(item.bufnr, item.lnum - 1, item.lnum, false)[1] -- If the lines differ only in leading whitespace, we should add highlights anyway and adjust @@ -196,6 +237,14 @@ local function add_qf_highlights(info) elseif user_data.header == "soft" then vim.api.nvim_buf_add_highlight(qf_list.qfbufnr, ns, "QuickFixHeaderSoft", i - 1, 0, -1) end + + -- If we've been processing for too long, defer to preserve editor responsiveness + local delta = vim.uv.hrtime() / 1e6 - start + if delta > 50 then + info.start_idx = i + 1 + schedule_highlights(info) + return + end end end @@ -313,7 +362,7 @@ function M.quickfixtextfunc(info) -- If we just rendered the last item, add highlights if info.end_idx == #items then - vim.schedule_wrap(add_qf_highlights)(info) + schedule_highlights(info) -- If we have appended some items to the quickfix, we need to update qf_items (just the appended ones) if qf_list.qfbufnr > 0 then diff --git a/lua/quicker/highlight.lua b/lua/quicker/highlight.lua index 42a01a2..23317f0 100644 --- a/lua/quicker/highlight.lua +++ b/lua/quicker/highlight.lua @@ -1,4 +1,3 @@ -local config = require("quicker.config") local M = {} ---@class quicker.TSHighlight @@ -38,7 +37,7 @@ function M.buf_get_ts_highlights(bufnr, lnum) end local row = lnum - 1 - if config.highlight.treesitter ~= "fast" and not parser:is_valid() then + if not parser:is_valid() then parser:parse(true) end