Regenerate nvim config
This commit is contained in:
@ -0,0 +1,321 @@
|
||||
local M = {}
|
||||
|
||||
local timers = {}
|
||||
local references = {}
|
||||
local paused_bufs = {}
|
||||
|
||||
-- returns r1 < r2 based on start of range
|
||||
local function before_by_start(r1, r2)
|
||||
if r1['start'].line < r2['start'].line then return true end
|
||||
if r2['start'].line < r1['start'].line then return false end
|
||||
if r1['start'].character < r2['start'].character then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
-- returns r1 < r2 base on start and if they are disjoint
|
||||
local function before_disjoint(r1, r2)
|
||||
if r1['end'].line < r2['start'].line then return true end
|
||||
if r2['start'].line < r1['end'].line then return false end
|
||||
if r1['end'].character < r2['start'].character then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
-- check for cursor row in [start,end]
|
||||
-- check for cursor col in [start,end]
|
||||
-- While the end is technically exclusive based on the highlighting, we treat it as inclusive to match the server.
|
||||
local function point_in_range(point, range)
|
||||
if point.row == range['start']['line'] and point.col < range['start']['character'] then
|
||||
return false
|
||||
end
|
||||
if point.row == range['end']['line'] and point.col > range['end']['character'] then
|
||||
return false
|
||||
end
|
||||
return point.row >= range['start']['line'] and point.row <= range['end']['line']
|
||||
end
|
||||
|
||||
local function cursor_in_references(bufnr)
|
||||
if not references[bufnr] then
|
||||
return false
|
||||
end
|
||||
if vim.api.nvim_win_get_buf(0) ~= bufnr then
|
||||
return false
|
||||
end
|
||||
local crow, ccol = unpack(vim.api.nvim_win_get_cursor(0))
|
||||
crow = crow - 1 -- reference ranges are (0,0)-indexed for (row,col)
|
||||
for _, reference in pairs(references[bufnr]) do
|
||||
local range = reference.range
|
||||
if point_in_range({ row = crow, col = ccol }, range) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function handle_document_highlight(result, bufnr, client_id)
|
||||
if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then return end
|
||||
local btimer = timers[bufnr]
|
||||
if btimer then
|
||||
vim.loop.timer_stop(btimer)
|
||||
-- vim.loop.close(btimer)
|
||||
end
|
||||
if type(result) ~= 'table' then
|
||||
vim.lsp.util.buf_clear_references(bufnr)
|
||||
return
|
||||
end
|
||||
timers[bufnr] = vim.defer_fn(function()
|
||||
if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then return end
|
||||
vim.lsp.util.buf_clear_references(bufnr)
|
||||
if cursor_in_references(bufnr) then
|
||||
local client = vim.lsp.get_client_by_id(client_id)
|
||||
if client then
|
||||
vim.lsp.util.buf_highlight_references(bufnr, result, client.offset_encoding)
|
||||
end
|
||||
end
|
||||
end, vim.g.Illuminate_delay or 17)
|
||||
table.sort(result, function(a, b)
|
||||
return before_by_start(a.range, b.range)
|
||||
end)
|
||||
references[bufnr] = result
|
||||
end
|
||||
|
||||
local function valid(bufnr, range)
|
||||
return range
|
||||
and range.start.line < vim.api.nvim_buf_line_count(bufnr)
|
||||
and range.start.character < #vim.fn.getline(range.start.line + 1)
|
||||
end
|
||||
|
||||
local function augroup(bufnr, autocmds)
|
||||
vim.cmd('augroup vim_illuminate_lsp' .. bufnr)
|
||||
vim.cmd('autocmd!')
|
||||
if autocmds then
|
||||
vim.b.illuminate_lsp_enabled = true
|
||||
autocmds()
|
||||
else
|
||||
vim.b.illuminate_lsp_enabled = false
|
||||
end
|
||||
vim.cmd('augroup END')
|
||||
end
|
||||
|
||||
local function autocmd(bufnr)
|
||||
vim.cmd(string.format('autocmd CursorMoved,CursorMovedI <buffer=%d> lua require"illuminate".on_cursor_moved(%d)',
|
||||
bufnr, bufnr))
|
||||
end
|
||||
|
||||
local function move_cursor(row, col)
|
||||
if not paused_bufs[vim.api.nvim_get_current_buf()] then
|
||||
augroup(vim.api.nvim_get_current_buf(), function()
|
||||
vim.api.nvim_win_set_cursor(0, { row, col })
|
||||
autocmd(vim.api.nvim_get_current_buf())
|
||||
end)
|
||||
else
|
||||
vim.api.nvim_win_set_cursor(0, { row, col })
|
||||
end
|
||||
end
|
||||
|
||||
function M.on_attach(client)
|
||||
M.stop_buf()
|
||||
if client and not client.supports_method('textDocument/documentHighlight') then
|
||||
return
|
||||
end
|
||||
pcall(vim.api.nvim_command, 'IlluminationDisable!')
|
||||
augroup(vim.api.nvim_get_current_buf(), function()
|
||||
autocmd(vim.api.nvim_get_current_buf())
|
||||
end)
|
||||
vim.lsp.handlers['textDocument/documentHighlight'] = function(...)
|
||||
if vim.fn.has('nvim-0.5.1') == 1 then
|
||||
handle_document_highlight(select(2, ...), select(3, ...).bufnr, select(3, ...).client_id)
|
||||
else
|
||||
handle_document_highlight(select(3, ...), select(5, ...), nil)
|
||||
end
|
||||
end
|
||||
vim.lsp.buf.document_highlight()
|
||||
end
|
||||
|
||||
function M.on_cursor_moved(bufnr)
|
||||
if not cursor_in_references(bufnr) then
|
||||
vim.lsp.util.buf_clear_references(bufnr)
|
||||
end
|
||||
|
||||
-- Best-effort check if any client support textDocument/documentHighlight
|
||||
local supported = nil
|
||||
-- For nvim 0.10+
|
||||
if vim.lsp.get_clients then
|
||||
supported = false
|
||||
for _, client in ipairs(vim.lsp.get_clients({bufnr = bufnr})) do
|
||||
if client and client.supports_method('textDocument/documentHighlight') then
|
||||
supported = true
|
||||
end
|
||||
end
|
||||
-- For older versions
|
||||
elseif vim.lsp.for_each_buffer_client then
|
||||
supported = false
|
||||
vim.lsp.for_each_buffer_client(bufnr, function(client)
|
||||
if client.supports_method('textDocument/documentHighlight') then
|
||||
supported = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if supported == nil or supported then
|
||||
vim.lsp.buf.document_highlight()
|
||||
else
|
||||
augroup(vim.api.nvim_get_current_buf(), function()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function M.get_document_highlights(bufnr)
|
||||
return references[bufnr]
|
||||
end
|
||||
|
||||
function M.next_reference(opt)
|
||||
opt = vim.tbl_extend('force', { reverse = false, wrap = false, range_ordering = 'start', silent = false }, opt or {})
|
||||
|
||||
local before
|
||||
if opt.range_ordering == 'start' then
|
||||
before = before_by_start
|
||||
else
|
||||
before = before_disjoint
|
||||
end
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local refs = M.get_document_highlights(bufnr)
|
||||
if not refs or #refs == 0 then return nil end
|
||||
|
||||
local next = nil
|
||||
local nexti = nil
|
||||
local crow, ccol = unpack(vim.api.nvim_win_get_cursor(0))
|
||||
local crange = { start = { line = crow - 1, character = ccol } }
|
||||
|
||||
for i, ref in ipairs(refs) do
|
||||
local range = ref.range
|
||||
if valid(bufnr, range) then
|
||||
if opt.reverse then
|
||||
if before(range, crange) and (not next or before(next, range)) then
|
||||
next = range
|
||||
nexti = i
|
||||
end
|
||||
else
|
||||
if before(crange, range) and (not next or before(range, next)) then
|
||||
next = range
|
||||
nexti = i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not next and opt.wrap then
|
||||
nexti = opt.reverse and #refs or 1
|
||||
next = refs[nexti].range
|
||||
end
|
||||
if next then
|
||||
move_cursor(next.start.line + 1, next.start.character)
|
||||
if not opt.silent then
|
||||
print('[' .. nexti .. '/' .. #refs .. ']')
|
||||
end
|
||||
end
|
||||
return next
|
||||
end
|
||||
|
||||
function M.toggle_pause()
|
||||
if paused_bufs[vim.api.nvim_get_current_buf()] then
|
||||
paused_bufs[vim.api.nvim_get_current_buf()] = false
|
||||
augroup(vim.api.nvim_get_current_buf(), function()
|
||||
autocmd(vim.api.nvim_get_current_buf())
|
||||
end)
|
||||
M.on_cursor_moved(vim.api.nvim_get_current_buf())
|
||||
else
|
||||
paused_bufs[vim.api.nvim_get_current_buf()] = true
|
||||
augroup(vim.api.nvim_get_current_buf(), nil)
|
||||
end
|
||||
end
|
||||
|
||||
function M.configure(config)
|
||||
require('illuminate.config').set(config)
|
||||
end
|
||||
|
||||
function M.pause()
|
||||
require('illuminate.engine').pause()
|
||||
end
|
||||
|
||||
function M.resume()
|
||||
require('illuminate.engine').resume()
|
||||
end
|
||||
|
||||
function M.toggle()
|
||||
require('illuminate.engine').toggle()
|
||||
end
|
||||
|
||||
function M.toggle_buf()
|
||||
require('illuminate.engine').toggle_buf()
|
||||
end
|
||||
|
||||
function M.pause_buf()
|
||||
require('illuminate.engine').pause_buf()
|
||||
end
|
||||
|
||||
function M.stop_buf()
|
||||
require('illuminate.engine').stop_buf()
|
||||
end
|
||||
|
||||
function M.resume_buf()
|
||||
require('illuminate.engine').resume_buf()
|
||||
end
|
||||
|
||||
function M.freeze_buf()
|
||||
require('illuminate.engine').freeze_buf()
|
||||
end
|
||||
|
||||
function M.unfreeze_buf()
|
||||
require('illuminate.engine').unfreeze_buf()
|
||||
end
|
||||
|
||||
function M.toggle_freeze_buf()
|
||||
require('illuminate.engine').toggle_freeze_buf()
|
||||
end
|
||||
|
||||
function M.invisible_buf()
|
||||
require('illuminate.engine').invisible_buf()
|
||||
end
|
||||
|
||||
function M.visible_buf()
|
||||
require('illuminate.engine').visible_buf()
|
||||
end
|
||||
|
||||
function M.toggle_visibility_buf()
|
||||
require('illuminate.engine').toggle_visibility_buf()
|
||||
end
|
||||
|
||||
function M.goto_next_reference(wrap)
|
||||
if wrap == nil then
|
||||
wrap = vim.o.wrapscan
|
||||
end
|
||||
require('illuminate.goto').goto_next_reference(wrap)
|
||||
end
|
||||
|
||||
function M.goto_prev_reference(wrap)
|
||||
if wrap == nil then
|
||||
wrap = vim.o.wrapscan
|
||||
end
|
||||
require('illuminate.goto').goto_prev_reference(wrap)
|
||||
end
|
||||
|
||||
function M.textobj_select()
|
||||
require('illuminate.textobj').select()
|
||||
end
|
||||
|
||||
function M.debug()
|
||||
require('illuminate.engine').debug()
|
||||
end
|
||||
|
||||
function M.is_paused()
|
||||
return require('illuminate.engine').is_paused()
|
||||
end
|
||||
|
||||
function M.set_highlight_defaults()
|
||||
vim.cmd [[
|
||||
hi def IlluminatedWordText guifg=none guibg=none gui=underline
|
||||
hi def IlluminatedWordRead guifg=none guibg=none gui=underline
|
||||
hi def IlluminatedWordWrite guifg=none guibg=none gui=underline
|
||||
]]
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,137 @@
|
||||
local M = {}
|
||||
|
||||
local config = {
|
||||
providers = {
|
||||
'lsp',
|
||||
'treesitter',
|
||||
'regex',
|
||||
},
|
||||
delay = 100,
|
||||
filetype_overrides = {},
|
||||
filetypes_denylist = {
|
||||
'dirbuf',
|
||||
'dirvish',
|
||||
'fugitive',
|
||||
},
|
||||
filetypes_allowlist = {},
|
||||
modes_denylist = {},
|
||||
modes_allowlist = {},
|
||||
providers_regex_syntax_denylist = {},
|
||||
providers_regex_syntax_allowlist = {},
|
||||
under_cursor = true,
|
||||
max_file_lines = nil,
|
||||
large_file_cutoff = nil,
|
||||
large_file_config = nil,
|
||||
min_count_to_highlight = 1,
|
||||
should_enable = nil,
|
||||
case_insensitive_regex = false,
|
||||
}
|
||||
|
||||
function M.set(config_overrides)
|
||||
config = vim.tbl_extend('force', config, config_overrides or {})
|
||||
end
|
||||
|
||||
function M.get_raw()
|
||||
return config
|
||||
end
|
||||
|
||||
function M.get()
|
||||
return (
|
||||
M.large_file_cutoff() == nil
|
||||
or vim.fn.line('$') <= M.large_file_cutoff()
|
||||
or M.large_file_overrides() == nil
|
||||
)
|
||||
and config
|
||||
or M.large_file_overrides()
|
||||
end
|
||||
|
||||
function M.filetype_override(bufnr)
|
||||
local ft = vim.api.nvim_buf_get_option(bufnr, 'filetype')
|
||||
return M.get()['filetype_overrides'] and M.get()['filetype_overrides'][ft] or {}
|
||||
end
|
||||
|
||||
function M.providers(bufnr)
|
||||
return M.filetype_override(bufnr)['providers'] or M.get()['providers']
|
||||
end
|
||||
|
||||
function M.filetypes_denylist()
|
||||
return M.get()['filetypes_denylist'] or {}
|
||||
end
|
||||
|
||||
function M.filetypes_allowlist()
|
||||
return M.get()['filetypes_allowlist'] or {}
|
||||
end
|
||||
|
||||
function M.modes_denylist(bufnr)
|
||||
return M.filetype_override(bufnr)['modes_denylist'] or M.get()['modes_denylist'] or {}
|
||||
end
|
||||
|
||||
function M.modes_allowlist(bufnr)
|
||||
return M.filetype_override(bufnr)['modes_allowlist'] or M.get()['modes_allowlist'] or {}
|
||||
end
|
||||
|
||||
function M.provider_regex_syntax_denylist(bufnr)
|
||||
return M.filetype_override(bufnr)['providers_regex_syntax_denylist']
|
||||
or M.get()['providers_regex_syntax_denylist']
|
||||
or {}
|
||||
end
|
||||
|
||||
function M.provider_regex_syntax_allowlist(bufnr)
|
||||
return M.filetype_override(bufnr)['providers_regex_syntax_allowlist']
|
||||
or M.get()['providers_regex_syntax_allowlist']
|
||||
or {}
|
||||
end
|
||||
|
||||
function M.under_cursor(bufnr)
|
||||
if M.filetype_override(bufnr)['under_cursor'] ~= nil then
|
||||
return M.filetype_override(bufnr)['under_cursor'] ~= nil
|
||||
end
|
||||
return M.get()['under_cursor']
|
||||
end
|
||||
|
||||
function M.delay(bufnr)
|
||||
local delay = M.filetype_override(bufnr)['delay'] or M.get()['delay'] or 17
|
||||
if string.sub(vim.api.nvim_get_mode().mode, 1, 1) == 'i' then
|
||||
delay = delay + 100
|
||||
end
|
||||
if delay < 17 then
|
||||
return 17
|
||||
end
|
||||
return delay
|
||||
end
|
||||
|
||||
function M.max_file_lines()
|
||||
return M.get()['max_file_lines']
|
||||
end
|
||||
|
||||
function M.large_file_cutoff()
|
||||
return config['large_file_cutoff']
|
||||
end
|
||||
|
||||
function M.large_file_overrides()
|
||||
if config['large_file_overrides'] ~= nil then
|
||||
if config['large_file_overrides']['under_cursor'] == nil then
|
||||
config['large_file_overrides']['under_cursor'] = true
|
||||
end
|
||||
return config['large_file_overrides']
|
||||
end
|
||||
return {
|
||||
filetypes_allowlist = { '_none' }
|
||||
}
|
||||
end
|
||||
|
||||
function M.min_count_to_highlight()
|
||||
return M.get()['min_count_to_highlight'] or 1
|
||||
end
|
||||
|
||||
function M.should_enable()
|
||||
return M.get()['should_enable'] or function(_)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function M.case_insensitive_regex()
|
||||
return M.get()['case_insensitive_regex']
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,267 @@
|
||||
local hl = require('illuminate.highlight')
|
||||
local ref = require('illuminate.reference')
|
||||
local config = require('illuminate.config')
|
||||
local util = require('illuminate.util')
|
||||
|
||||
local M = {}
|
||||
|
||||
local AUGROUP = 'vim_illuminate_v2_augroup'
|
||||
local timers = {}
|
||||
local paused_bufs = {}
|
||||
local stopped_bufs = {}
|
||||
local is_paused = false
|
||||
local written = {}
|
||||
local error_timestamps = {}
|
||||
local frozen_bufs = {}
|
||||
local invisible_bufs = {}
|
||||
local started = false
|
||||
|
||||
local function buf_should_illuminate(bufnr)
|
||||
if is_paused or paused_bufs[bufnr] or stopped_bufs[bufnr] then
|
||||
return false
|
||||
end
|
||||
|
||||
return config.should_enable()(bufnr)
|
||||
and (config.max_file_lines() == nil or vim.fn.line('$') <= config.max_file_lines())
|
||||
and util.is_allowed(
|
||||
config.modes_allowlist(bufnr),
|
||||
config.modes_denylist(bufnr),
|
||||
vim.api.nvim_get_mode().mode
|
||||
) and util.is_allowed(
|
||||
config.filetypes_allowlist(),
|
||||
config.filetypes_denylist(),
|
||||
vim.api.nvim_buf_get_option(bufnr, 'filetype')
|
||||
)
|
||||
end
|
||||
|
||||
local function stop_timer(timer)
|
||||
if vim.loop.is_active(timer) then
|
||||
vim.loop.timer_stop(timer)
|
||||
vim.loop.close(timer)
|
||||
end
|
||||
end
|
||||
|
||||
function M.start()
|
||||
started = true
|
||||
vim.api.nvim_create_augroup(AUGROUP, { clear = true })
|
||||
vim.api.nvim_create_autocmd({ 'VimEnter', 'CursorMoved', 'CursorMovedI', 'ModeChanged', 'TextChanged' }, {
|
||||
group = AUGROUP,
|
||||
callback = function()
|
||||
M.refresh_references()
|
||||
end,
|
||||
})
|
||||
-- If vim.lsp.buf.format is called, this will call vim.api.nvim_buf_set_text which messes up extmarks.
|
||||
-- By using this `written` variable, we can ensure refresh_references doesn't terminate early based on
|
||||
-- ref.buf_cursor_in_references being incorrect (we have references but they're not actually showing
|
||||
-- as illuminated). vim.lsp.buf.format will trigger CursorMoved so we don't need to do it here.
|
||||
vim.api.nvim_create_autocmd({ 'BufWritePost' }, {
|
||||
group = AUGROUP,
|
||||
callback = function()
|
||||
written[vim.api.nvim_get_current_buf()] = true
|
||||
end,
|
||||
})
|
||||
vim.api.nvim_create_autocmd({ 'VimLeave' }, {
|
||||
group = AUGROUP,
|
||||
callback = function()
|
||||
for _, timer in pairs(timers) do
|
||||
stop_timer(timer)
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function M.stop()
|
||||
started = false
|
||||
vim.api.nvim_create_augroup(AUGROUP, { clear = true })
|
||||
end
|
||||
|
||||
--- Get the highlighted references for the item under the cursor for
|
||||
--- @bufnr and clears any old reference highlights
|
||||
---
|
||||
--- @bufnr (number)
|
||||
function M.refresh_references(bufnr, winid)
|
||||
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||
winid = winid or vim.api.nvim_get_current_win()
|
||||
|
||||
if frozen_bufs[bufnr] then
|
||||
return
|
||||
end
|
||||
|
||||
if not buf_should_illuminate(bufnr) then
|
||||
hl.buf_clear_references(bufnr)
|
||||
ref.buf_set_references(bufnr, {})
|
||||
return
|
||||
end
|
||||
|
||||
-- We might want to optimize here by returning early if cursor is in references.
|
||||
-- The downside is that LSP servers can sometimes return a different list of references
|
||||
-- as you move around an existing reference (like return statements).
|
||||
if written[bufnr] or not ref.buf_cursor_in_references(bufnr, util.get_cursor_pos(winid)) then
|
||||
hl.buf_clear_references(bufnr)
|
||||
ref.buf_set_references(bufnr, {})
|
||||
elseif config.large_file_cutoff() ~= nil and vim.fn.line('$') > config.large_file_cutoff() then
|
||||
return
|
||||
end
|
||||
written[bufnr] = nil
|
||||
|
||||
if timers[bufnr] then
|
||||
stop_timer(timers[bufnr])
|
||||
end
|
||||
|
||||
local provider = M.get_provider(bufnr)
|
||||
if not provider then return end
|
||||
pcall(provider['initiate_request'], bufnr, winid)
|
||||
|
||||
local changedtick = vim.api.nvim_buf_get_changedtick(bufnr)
|
||||
|
||||
local timer = vim.loop.new_timer()
|
||||
timers[bufnr] = timer
|
||||
timer:start(config.delay(bufnr), 17, vim.schedule_wrap(function()
|
||||
local ok, err = pcall(function()
|
||||
if not bufnr or not vim.api.nvim_buf_is_loaded(bufnr) then
|
||||
stop_timer(timer)
|
||||
return
|
||||
end
|
||||
|
||||
hl.buf_clear_references(bufnr)
|
||||
ref.buf_set_references(bufnr, {})
|
||||
|
||||
if vim.api.nvim_buf_get_changedtick(bufnr) ~= changedtick
|
||||
or vim.api.nvim_get_current_win() ~= winid
|
||||
or bufnr ~= vim.api.nvim_win_get_buf(0) then
|
||||
stop_timer(timer)
|
||||
return
|
||||
end
|
||||
|
||||
provider = M.get_provider(bufnr)
|
||||
if not provider then
|
||||
stop_timer(timer)
|
||||
return
|
||||
end
|
||||
|
||||
local references = provider.get_references(bufnr, util.get_cursor_pos(winid))
|
||||
if references ~= nil then
|
||||
ref.buf_set_references(bufnr, references)
|
||||
if ref.buf_cursor_in_references(bufnr, util.get_cursor_pos(winid)) then
|
||||
if not invisible_bufs[bufnr] == true then
|
||||
hl.buf_highlight_references(bufnr, ref.buf_get_references(bufnr))
|
||||
end
|
||||
else
|
||||
ref.buf_set_references(bufnr, {})
|
||||
end
|
||||
stop_timer(timer)
|
||||
end
|
||||
end)
|
||||
|
||||
if not ok then
|
||||
local time = vim.loop.hrtime()
|
||||
if #error_timestamps == 5 then
|
||||
vim.notify(
|
||||
'vim-illuminate: An internal error has occured: ' .. vim.inspect(ok) .. vim.inspect(err),
|
||||
vim.log.levels.ERROR,
|
||||
{}
|
||||
)
|
||||
M.stop()
|
||||
stop_timer(timer)
|
||||
elseif #error_timestamps == 0 or time - error_timestamps[#error_timestamps] < 500000000 then
|
||||
table.insert(error_timestamps, time)
|
||||
else
|
||||
error_timestamps = { time }
|
||||
end
|
||||
end
|
||||
end))
|
||||
end
|
||||
|
||||
function M.get_provider(bufnr)
|
||||
for _, provider in ipairs(config.providers(bufnr) or {}) do
|
||||
local ok, providerModule = pcall(require, string.format('illuminate.providers.%s', provider))
|
||||
if ok and providerModule.is_ready(bufnr) then
|
||||
return providerModule, provider
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function M.pause()
|
||||
is_paused = true
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.resume()
|
||||
is_paused = false
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.toggle()
|
||||
is_paused = not is_paused
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.toggle_buf(bufnr)
|
||||
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||
if paused_bufs[bufnr] then
|
||||
paused_bufs[bufnr] = nil
|
||||
else
|
||||
paused_bufs[bufnr] = true
|
||||
end
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.pause_buf(bufnr)
|
||||
paused_bufs[bufnr or vim.api.nvim_get_current_buf()] = true
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.resume_buf(bufnr)
|
||||
paused_bufs[bufnr or vim.api.nvim_get_current_buf()] = nil
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.stop_buf(bufnr)
|
||||
stopped_bufs[bufnr or vim.api.nvim_get_current_buf()] = true
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.freeze_buf(bufnr)
|
||||
frozen_bufs[bufnr or vim.api.nvim_get_current_buf()] = true
|
||||
end
|
||||
|
||||
function M.unfreeze_buf(bufnr)
|
||||
frozen_bufs[bufnr or vim.api.nvim_get_current_buf()] = nil
|
||||
end
|
||||
|
||||
function M.toggle_freeze_buf(bufnr)
|
||||
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||
frozen_bufs[bufnr] = not frozen_bufs[bufnr]
|
||||
end
|
||||
|
||||
function M.invisible_buf(bufnr)
|
||||
invisible_bufs[bufnr or vim.api.nvim_get_current_buf()] = true
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.visible_buf(bufnr)
|
||||
invisible_bufs[bufnr or vim.api.nvim_get_current_buf()] = nil
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.toggle_visibility_buf(bufnr)
|
||||
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||
invisible_bufs[bufnr] = not invisible_bufs[bufnr]
|
||||
M.refresh_references()
|
||||
end
|
||||
|
||||
function M.debug()
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
print('buf_should_illuminate', bufnr, buf_should_illuminate(bufnr))
|
||||
print('config', vim.inspect(config.get_raw()))
|
||||
print('started', started)
|
||||
print('provider', M.get_provider(bufnr))
|
||||
print('`termguicolors`', vim.opt.termguicolors:get())
|
||||
end
|
||||
|
||||
function M.is_paused()
|
||||
return is_paused
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,63 @@
|
||||
local util = require('illuminate.util')
|
||||
local ref = require('illuminate.reference')
|
||||
local engine = require('illuminate.engine')
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.goto_next_reference(wrap)
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local winid = vim.api.nvim_get_current_win()
|
||||
local cursor_pos = util.get_cursor_pos(winid)
|
||||
|
||||
if #ref.buf_get_references(bufnr) == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local i = ref.bisect_left(ref.buf_get_references(bufnr), cursor_pos)
|
||||
i = i + 1
|
||||
if i > #ref.buf_get_references(bufnr) then
|
||||
if wrap then
|
||||
i = 1
|
||||
else
|
||||
vim.api.nvim_err_writeln("E384: vim-illuminate: goto_next_reference hit BOTTOM of the references")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local pos, _ = unpack(ref.buf_get_references(bufnr)[i])
|
||||
local new_cursor_pos = { pos[1] + 1, pos[2] }
|
||||
vim.cmd('normal! m`')
|
||||
engine.freeze_buf(bufnr)
|
||||
vim.api.nvim_win_set_cursor(winid, new_cursor_pos)
|
||||
engine.unfreeze_buf(bufnr)
|
||||
end
|
||||
|
||||
function M.goto_prev_reference(wrap)
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local winid = vim.api.nvim_get_current_win()
|
||||
local cursor_pos = util.get_cursor_pos(winid)
|
||||
|
||||
if #ref.buf_get_references(bufnr) == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local i = ref.bisect_left(ref.buf_get_references(bufnr), cursor_pos)
|
||||
i = i - 1
|
||||
if i == 0 then
|
||||
if wrap then
|
||||
i = #ref.buf_get_references(bufnr)
|
||||
else
|
||||
vim.api.nvim_err_writeln("E384: vim-illuminate: goto_prev_reference hit TOP of the references")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local pos, _ = unpack(ref.buf_get_references(bufnr)[i])
|
||||
local new_cursor_pos = { pos[1] + 1, pos[2] }
|
||||
vim.cmd('normal! m`')
|
||||
engine.freeze_buf(bufnr)
|
||||
vim.api.nvim_win_set_cursor(winid, new_cursor_pos)
|
||||
engine.unfreeze_buf(bufnr)
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,59 @@
|
||||
local util = require('illuminate.util')
|
||||
local config = require('illuminate.config')
|
||||
local ref = require('illuminate.reference')
|
||||
|
||||
local M = {}
|
||||
|
||||
local HL_NAMESPACE = vim.api.nvim_create_namespace('illuminate.highlight')
|
||||
|
||||
local function kind_to_hl_group(kind)
|
||||
return kind == vim.lsp.protocol.DocumentHighlightKind.Text and 'IlluminatedWordText'
|
||||
or kind == vim.lsp.protocol.DocumentHighlightKind.Read and 'IlluminatedWordRead'
|
||||
or kind == vim.lsp.protocol.DocumentHighlightKind.Write and 'IlluminatedWordWrite'
|
||||
or 'IlluminatedWordText'
|
||||
end
|
||||
|
||||
function M.buf_highlight_references(bufnr, references)
|
||||
if config.min_count_to_highlight() > #references then
|
||||
return
|
||||
end
|
||||
|
||||
local cursor_pos = util.get_cursor_pos()
|
||||
for _, reference in ipairs(references) do
|
||||
if config.under_cursor(bufnr) or not ref.is_pos_in_ref(cursor_pos, reference) then
|
||||
M.range(
|
||||
bufnr,
|
||||
reference[1],
|
||||
reference[2],
|
||||
reference[3]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.range(bufnr, start, finish, kind)
|
||||
local region = vim.region(bufnr, start, finish, 'v', false)
|
||||
for linenr, cols in pairs(region) do
|
||||
if linenr == -1 then
|
||||
linenr = 0
|
||||
end
|
||||
local end_row
|
||||
if cols[2] == -1 then
|
||||
end_row = linenr + 1
|
||||
cols[2] = 0
|
||||
end
|
||||
vim.api.nvim_buf_set_extmark(bufnr, HL_NAMESPACE, linenr, cols[1], {
|
||||
hl_group = kind_to_hl_group(kind),
|
||||
end_row = end_row,
|
||||
end_col = cols[2],
|
||||
priority = 199,
|
||||
strict = false,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function M.buf_clear_references(bufnr)
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, HL_NAMESPACE, 0, -1)
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,130 @@
|
||||
local M = {}
|
||||
|
||||
local bufs = {}
|
||||
|
||||
local function _str_byteindex_enc(line, col, encoding)
|
||||
if not encoding then
|
||||
encoding = 'utf-16'
|
||||
end
|
||||
|
||||
if encoding == 'utf-8' then
|
||||
if col then
|
||||
return col
|
||||
else
|
||||
return #line
|
||||
end
|
||||
elseif encoding == 'utf-16' then
|
||||
return vim.str_byteindex(line, col, true)
|
||||
elseif encoding == 'utf-32' then
|
||||
return vim.str_byteindex(line, col)
|
||||
else
|
||||
return col
|
||||
end
|
||||
end
|
||||
|
||||
local function get_line_byte_from_position(bufnr, line, col, offset_encoding)
|
||||
if col == 0 then
|
||||
return col
|
||||
end
|
||||
|
||||
local lines = vim.api.nvim_buf_get_lines(bufnr, line, line + 1, false)
|
||||
if not lines or #lines == 0 then
|
||||
return col
|
||||
end
|
||||
local ok, result = pcall(_str_byteindex_enc, lines[1], col, offset_encoding)
|
||||
if ok then
|
||||
return result
|
||||
end
|
||||
return math.min(#(lines[1]), col)
|
||||
end
|
||||
|
||||
function M.get_references(bufnr)
|
||||
if not bufs[bufnr] or not bufs[bufnr][3] then
|
||||
return nil
|
||||
end
|
||||
|
||||
return bufs[bufnr][3]
|
||||
end
|
||||
|
||||
function M.is_ready(bufnr)
|
||||
local supported = false
|
||||
-- For nvim 0.10+
|
||||
if vim.lsp.get_clients then
|
||||
supported = false
|
||||
for _, client in ipairs(vim.lsp.get_clients({bufnr = bufnr})) do
|
||||
if client and client.supports_method('textDocument/documentHighlight') then
|
||||
supported = true
|
||||
end
|
||||
end
|
||||
-- For older versions
|
||||
elseif vim.lsp.for_each_buffer_client then
|
||||
supported = false
|
||||
vim.lsp.for_each_buffer_client(bufnr, function(client)
|
||||
if client and client.supports_method('textDocument/documentHighlight') then
|
||||
supported = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
return supported
|
||||
end
|
||||
|
||||
function M.initiate_request(bufnr, winid)
|
||||
local id = 1
|
||||
if bufs[bufnr] then
|
||||
local prev_id, cancel_fn, references = unpack(bufs[bufnr])
|
||||
if references == nil then
|
||||
pcall(cancel_fn)
|
||||
end
|
||||
id = prev_id + 1
|
||||
end
|
||||
|
||||
local cancel_fn = vim.lsp.buf_request_all(
|
||||
bufnr,
|
||||
'textDocument/documentHighlight',
|
||||
vim.lsp.util.make_position_params(winid),
|
||||
function(client_results)
|
||||
if bufs[bufnr][1] ~= id then
|
||||
return
|
||||
end
|
||||
if not vim.api.nvim_buf_is_valid(bufnr) then
|
||||
bufs[bufnr][3] = {}
|
||||
return
|
||||
end
|
||||
|
||||
local references = {}
|
||||
for client_id, results in pairs(client_results) do
|
||||
local client = vim.lsp.get_client_by_id(client_id)
|
||||
if client and results['result'] then
|
||||
for _, res in ipairs(results['result']) do
|
||||
local start_col = get_line_byte_from_position(
|
||||
bufnr,
|
||||
res['range']['start']['line'],
|
||||
res['range']['start']['character'],
|
||||
res['offset_encoding']
|
||||
)
|
||||
local end_col = get_line_byte_from_position(
|
||||
bufnr,
|
||||
res['range']['end']['line'],
|
||||
res['range']['end']['character'],
|
||||
res['offset_encoding']
|
||||
)
|
||||
table.insert(references, {
|
||||
{ res['range']['start']['line'], start_col },
|
||||
{ res['range']['end']['line'], end_col },
|
||||
res['kind'],
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
bufs[bufnr][3] = references
|
||||
end
|
||||
)
|
||||
|
||||
bufs[bufnr] = {
|
||||
id,
|
||||
cancel_fn,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,74 @@
|
||||
local config = require('illuminate.config')
|
||||
local util = require('illuminate.util')
|
||||
|
||||
local M = {}
|
||||
|
||||
local START_WORD_REGEX = vim.regex([[^\k*]])
|
||||
local END_WORD_REGEX = vim.regex([[\k*$]])
|
||||
|
||||
-- foo
|
||||
-- foo
|
||||
-- Foo
|
||||
-- fOo
|
||||
local function get_cur_word(bufnr, cursor)
|
||||
local line = vim.api.nvim_buf_get_lines(bufnr, cursor[1], cursor[1] + 1, false)[1]
|
||||
local left_part = string.sub(line, 0, cursor[2] + 1)
|
||||
local right_part = string.sub(line, cursor[2] + 1)
|
||||
local start_idx, _ = END_WORD_REGEX:match_str(left_part)
|
||||
local _, end_idx = START_WORD_REGEX:match_str(right_part)
|
||||
local word = string.format('%s%s', string.sub(left_part, start_idx + 1), string.sub(right_part, 2, end_idx))
|
||||
local modifiers = [[\V]]
|
||||
if config.case_insensitive_regex() then
|
||||
modifiers = modifiers .. [[\c]]
|
||||
end
|
||||
local ok, escaped = pcall(vim.fn.escape, word, [[/\]])
|
||||
if ok then
|
||||
return modifiers .. [[\<]] .. escaped .. [[\>]]
|
||||
end
|
||||
end
|
||||
|
||||
function M.get_references(bufnr, cursor)
|
||||
local refs = {}
|
||||
local ok, re = pcall(vim.regex, get_cur_word(bufnr, cursor))
|
||||
if not ok then
|
||||
return refs
|
||||
end
|
||||
|
||||
local line_count = vim.api.nvim_buf_line_count(bufnr)
|
||||
for i = 0, line_count - 1 do
|
||||
local start_byte, end_byte = 0, 0
|
||||
while true do
|
||||
local start_offset, end_offset = re:match_line(bufnr, i, end_byte)
|
||||
if not start_offset then break end
|
||||
|
||||
start_byte = end_byte + start_offset
|
||||
end_byte = end_byte + end_offset
|
||||
table.insert(refs, {
|
||||
{ i, start_byte },
|
||||
{ i, end_byte },
|
||||
vim.lsp.protocol.DocumentHighlightKind.Text,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return refs
|
||||
end
|
||||
|
||||
function M.is_ready(bufnr)
|
||||
local name = vim.fn.synIDattr(
|
||||
vim.fn.synIDtrans(
|
||||
vim.fn.synID(vim.fn.line('.'), vim.fn.col('.'), 1)
|
||||
),
|
||||
'name'
|
||||
)
|
||||
if util.is_allowed(
|
||||
config.provider_regex_syntax_allowlist(bufnr),
|
||||
config.provider_regex_syntax_denylist(bufnr),
|
||||
name
|
||||
) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,51 @@
|
||||
local ts_utils = require('nvim-treesitter.ts_utils')
|
||||
local locals = require('nvim-treesitter.locals')
|
||||
|
||||
local M = {}
|
||||
|
||||
local buf_attached = {}
|
||||
|
||||
function M.get_references(bufnr)
|
||||
local node_at_point = ts_utils.get_node_at_cursor()
|
||||
if not node_at_point then
|
||||
return
|
||||
end
|
||||
|
||||
local refs = {}
|
||||
|
||||
local def_node, scope = locals.find_definition(node_at_point, bufnr)
|
||||
if def_node ~= node_at_point then
|
||||
local range = { def_node:range() }
|
||||
table.insert(refs, {
|
||||
{ range[1], range[2] },
|
||||
{ range[3], range[4] },
|
||||
vim.lsp.protocol.DocumentHighlightKind.Write,
|
||||
})
|
||||
end
|
||||
|
||||
local usages = locals.find_usages(def_node, scope, bufnr)
|
||||
for _, node in ipairs(usages) do
|
||||
local range = { node:range() }
|
||||
table.insert(refs, {
|
||||
{ range[1], range[2] },
|
||||
{ range[3], range[4] },
|
||||
vim.lsp.protocol.DocumentHighlightKind.Read,
|
||||
})
|
||||
end
|
||||
|
||||
return refs
|
||||
end
|
||||
|
||||
function M.is_ready(bufnr)
|
||||
return buf_attached[bufnr] and vim.api.nvim_buf_get_option(bufnr, 'filetype') ~= 'yaml'
|
||||
end
|
||||
|
||||
function M.attach(bufnr)
|
||||
buf_attached[bufnr] = true
|
||||
end
|
||||
|
||||
function M.detach(bufnr)
|
||||
buf_attached[bufnr] = nil
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,91 @@
|
||||
local M = {}
|
||||
|
||||
-- @table pos
|
||||
-- @field 1 (number) line (0-indexed)
|
||||
-- @field 2 (number) col (0-indexed)
|
||||
--
|
||||
-- @table ref
|
||||
-- @field 1 (table) start pos
|
||||
-- @field 2 (table) end pos
|
||||
|
||||
local buf_references = {}
|
||||
|
||||
local function get_references(bufnr)
|
||||
return buf_references[bufnr] or {}
|
||||
end
|
||||
|
||||
local function pos_before(pos1, pos2)
|
||||
if pos1[1] < pos2[1] then return true end
|
||||
if pos1[1] > pos2[1] then return false end
|
||||
if pos1[2] < pos2[2] then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
local function pos_equal(pos1, pos2)
|
||||
return pos1[1] == pos2[1] and pos1[2] == pos2[2]
|
||||
end
|
||||
|
||||
local function ref_before(ref1, ref2)
|
||||
return pos_before(ref1[1], ref2[1]) or pos_equal(ref1[1], ref2[1]) and pos_before(ref1[2], ref2[2])
|
||||
end
|
||||
|
||||
local function buf_sort_references(bufnr)
|
||||
local should_sort = false
|
||||
for i, ref in ipairs(get_references(bufnr)) do
|
||||
if i > 1 then
|
||||
if not ref_before(get_references(bufnr)[i - 1], ref) then
|
||||
should_sort = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if should_sort then
|
||||
table.sort(get_references(bufnr), ref_before)
|
||||
end
|
||||
end
|
||||
|
||||
function M.is_pos_in_ref(pos, ref)
|
||||
return (pos_before(ref[1], pos) or pos_equal(ref[1], pos)) and (pos_before(pos, ref[2]) or pos_equal(pos, ref[2]))
|
||||
end
|
||||
|
||||
function M.bisect_left(references, pos)
|
||||
local l, r = 1, #references + 1
|
||||
while l < r do
|
||||
local m = l + math.floor((r - l) / 2)
|
||||
if pos_before(references[m][2], pos) then
|
||||
l = m + 1
|
||||
else
|
||||
r = m
|
||||
end
|
||||
end
|
||||
return l
|
||||
end
|
||||
|
||||
function M.buf_get_references(bufnr)
|
||||
return get_references(bufnr)
|
||||
end
|
||||
|
||||
function M.buf_set_references(bufnr, references)
|
||||
buf_references[bufnr] = references
|
||||
buf_sort_references(bufnr)
|
||||
end
|
||||
|
||||
function M.buf_cursor_in_references(bufnr, cursor_pos)
|
||||
if not get_references(bufnr) then
|
||||
return false
|
||||
end
|
||||
|
||||
local i = M.bisect_left(get_references(bufnr), cursor_pos)
|
||||
|
||||
if i > #get_references(bufnr) then
|
||||
return false
|
||||
end
|
||||
if not M.is_pos_in_ref(cursor_pos, get_references(bufnr)[i]) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,42 @@
|
||||
local util = require('illuminate.util')
|
||||
local ref = require('illuminate.reference')
|
||||
|
||||
local M = {}
|
||||
|
||||
local visual_modes = {
|
||||
['v'] = true,
|
||||
['vs'] = true,
|
||||
['V'] = true,
|
||||
['Vs'] = true,
|
||||
['CTRL-V'] = true,
|
||||
['CTRL-Vs'] = true,
|
||||
['s'] = true,
|
||||
['S'] = true,
|
||||
['CTRL-S'] = true,
|
||||
}
|
||||
|
||||
function M.select()
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local winid = vim.api.nvim_get_current_win()
|
||||
local cursor_pos = util.get_cursor_pos(winid)
|
||||
|
||||
if #ref.buf_get_references(bufnr) == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local i = ref.bisect_left(ref.buf_get_references(bufnr), cursor_pos)
|
||||
if i > #ref.buf_get_references(bufnr) then
|
||||
return
|
||||
end
|
||||
|
||||
local reference = ref.buf_get_references(bufnr)[i]
|
||||
vim.api.nvim_win_set_cursor(winid, { reference[1][1] + 1, reference[1][2] })
|
||||
if not visual_modes[vim.api.nvim_get_mode().mode] then
|
||||
vim.cmd('normal! v')
|
||||
else
|
||||
vim.cmd('normal! o')
|
||||
end
|
||||
vim.api.nvim_win_set_cursor(winid, { reference[2][1] + 1, reference[2][2] - 1 })
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,51 @@
|
||||
local M = {}
|
||||
|
||||
function M.get_cursor_pos(winid)
|
||||
winid = winid or vim.api.nvim_get_current_win()
|
||||
local cursor = vim.api.nvim_win_get_cursor(winid)
|
||||
cursor[1] = cursor[1] - 1 -- we always want line to be 0-indexed
|
||||
return cursor
|
||||
end
|
||||
|
||||
function M.list_to_set(list)
|
||||
if list == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
local set = {}
|
||||
for _, v in pairs(list) do
|
||||
set[v] = true
|
||||
end
|
||||
return set
|
||||
end
|
||||
|
||||
function M.is_allowed(allow_list, deny_list, thing)
|
||||
if #allow_list == 0 and #deny_list == 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
if #deny_list > 0 then
|
||||
return not vim.tbl_contains(deny_list, thing)
|
||||
end
|
||||
|
||||
return vim.tbl_contains(allow_list, thing)
|
||||
end
|
||||
|
||||
function M.tbl_get(tbl, expected_type, ...)
|
||||
local cur = tbl
|
||||
for _, key in ipairs({ ... }) do
|
||||
if type(cur) ~= 'table' or cur[key] == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
cur = cur[key]
|
||||
end
|
||||
|
||||
return type(cur) == expected_type and cur or nil
|
||||
end
|
||||
|
||||
function M.has_keymap(mode, lhs)
|
||||
return vim.fn.mapcheck(lhs, mode) ~= ''
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user