Skip to content

Commit

Permalink
perf: perform syntax highlighting async
Browse files Browse the repository at this point in the history
  • Loading branch information
stevearc committed Jul 31, 2024
1 parent e03d5d6 commit 56237b4
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 22 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 4 additions & 7 deletions doc/quicker.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"`
Expand Down
11 changes: 5 additions & 6 deletions lua/quicker/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
57 changes: 53 additions & 4 deletions lua/quicker/display.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lua/quicker/highlight.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
local config = require("quicker.config")
local M = {}

---@class quicker.TSHighlight
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit 56237b4

Please sign in to comment.