Implement functions for togging rainbow per buffer

This commit is contained in:
HiPhish 2023-08-24 22:27:55 +02:00
parent 698a439662
commit adfb780b35
6 changed files with 256 additions and 97 deletions

View file

@ -23,4 +23,22 @@ function! rainbow_delimiters#hlgroup_at(i)
return luaeval("require('rainbow-delimiters').hlgroup_at(_A)", a:i)
endfunction
" Disable highlighting for the given buffer. Buffer number zero means current
" buffer.
function! rainbow_delimiters#disable(bufnr)
call luaeval("require('rainbow-delimiters').disable(_A)", a:bufnr)
endfunction
" Enable highlighting for the given buffer. Buffer number zero means current
" buffer.
function! rainbow_delimiters#enable(bufnr)
call luaeval("require('rainbow-delimiters').enable(_A)", a:bufnr)
endfunction
" Toggle highlighting for the given buffer. Buffer number zero means current
" buffer.
function! rainbow_delimiters#toggle(bufnr)
call luaeval("require('rainbow-delimiters').toggle(_A)", a:bufnr)
endfunction
" vim:tw=79:ts=4:sw=4:noet:

View file

@ -366,6 +366,36 @@ There is a utility library provided for people writing their own strategies.
It is available as a table under the Lua module `'rainbow-delimiters'`.
*rb-delimiters.enable*
*rb_delimiters#enable*
'rainbow-delimiters'.enable({bufnr})
Re-enable rainbow delimiters for the buffer {bufnr} (or the current buffer
if {bufnr} is `0`) after it has been disabled.
rainbow_delimiters#enable({bufnr})
Vim script binding for the above function.
*rb-delimiters.disable*
*rb_delimiters#disable*
'rainbow-delimiters'.disable({bufnr})
Disable rainbow delimiters for the buffer {bufnr} (or the current buffer
if {bufnr} is `0`).
rainbow_delimiters#disable({bufnr})
Vim script binding for the above function.
*rb-delimiters.toggle*
*rb_delimiters#toggle*
'rainbow-delimiters'.toggle({bufnr})
Toggle rainbow delimiters for the buffer {bufnr} (or the current buffer
if {bufnr} is `0`).
rainbow_delimiters#toggle({bufnr})
Vim script binding for the above function.
*rb-delimiters.hlgroup_at*
*rainbow-delimiters#hlgroup_at*
'rainbow-delimiters'.hlgroup_at({nesting_level})

View file

@ -17,6 +17,33 @@
local lib = require 'rainbow-delimiters.lib'
---Disable rainbow delimiters for a given buffer.
---@param bufnr number Buffer number, zero for current buffer.
local function disable(bufnr)
bufnr = bufnr > 0 and bufnr or vim.api.nvim_get_current_buf()
lib.detach(bufnr)
lib.buffers[bufnr] = false
end
---Enable rainbow delimiters for a given buffer.
---@param bufnr number Buffer number, zero for current buffer.
local function enable(bufnr)
bufnr = bufnr > 0 and bufnr or vim.api.nvim_get_current_buf()
lib.buffers[bufnr] = nil
lib.attach(bufnr)
end
local function toggle(bufnr)
bufnr = bufnr > 0 and bufnr or vim.api.nvim_get_current_buf()
if lib.buffers[bufnr] then
print 'turn off'
disable(bufnr)
else
print 'turn on'
enable(bufnr)
end
end
---Public API for use in writing strategies or other custom code.
local M = {
hlgroup_at = lib.hlgroup_at,
@ -25,7 +52,10 @@ local M = {
['global'] = require 'rainbow-delimiters.strategy.global',
['local'] = require 'rainbow-delimiters.strategy.local',
['noop'] = require 'rainbow-delimiters.strategy.no-op',
}
},
enable = enable,
disable = disable,
toggle = toggle,
}

View file

@ -16,6 +16,7 @@
--]]
local get_query = vim.treesitter.query.get
local get_parser= vim.treesitter.get_parser
local log = require 'rainbow-delimiters.log'
local config = require 'rainbow-delimiters.config'
@ -120,6 +121,100 @@ function M.clear_namespace(bufnr, lang, line_start, line_end)
end
end
---Start rainbow highlighting for the given buffer
function M.attach(bufnr)
-- Rainbow delimiters was explicitly disabled for this buffer
if M.buffers[bufnr] == false then return end
local lang = vim.treesitter.language.get_lang(vim.bo[bufnr].ft)
if not lang then
log.trace('Cannot attach to buffer %d, no parser for %s', bufnr, lang)
return
end
log.trace('Attaching to buffer %d with language %s.', bufnr, lang)
if M.buffers[bufnr] then
if M.buffers[bufnr].lang == lang then return end
-- The file type of the buffer has change, so we need to detach first
-- before we re-attach
M.detach(bufnr)
end
local parser
do
local success
success, parser = pcall(get_parser, bufnr, lang)
if not success then return end
end
local strategy
do
strategy = config.strategy[lang]
if type(strategy) == 'function' then
strategy = strategy()
end
end
if not strategy or strategy == vim.NIL then return end
-- Intentionally abort; the user has explicitly disabled rainbow delimiters
-- for this buffer, usually by setting a strategy- or query function which
-- returned nil.
if not strategy then
log.warn('No strategy defined for %s', lang)
end
parser:register_cbs {
on_detach = function(bnr)
if not M.buffers[bnr] then return end
M.detach(bufnr)
end,
on_child_removed = function(child)
M.clear_namespace(bufnr, child:lang())
end,
}
local settings = {
strategy = strategy,
parser = parser,
lang = lang
}
M.buffers[bufnr] = settings
-- For now we silently discard errors, but in the future we should log
-- them.
local success, error = pcall(strategy.on_attach, bufnr, settings)
if not success then
log.error('Error attaching strategy to buffer %d: %s', bufnr, error)
M.buffers[bufnr] = nil
end
end
---Start rainbow highlighting for the given buffer
function M.detach(bufnr)
log.trace('Detaching from buffer %d.', bufnr)
if not M.buffers[bufnr] then
return
end
local strategy = M.buffers[bufnr].strategy
local parser = M.buffers[bufnr].parser
-- Clear all the namespaces for each language
parser:for_each_child(function(_, lang)
M.clear_namespace(bufnr, lang)
end, true)
-- Finally release all resources the parser is holding on to
parser:destroy()
-- For now we silently discard errors, but in the future we should log
-- them.
local success, error = pcall(strategy.on_detach, bufnr)
if not success then
log.error('Error detaching strategy from buffer %d: %s', bufnr, error)
end
M.buffers[bufnr] = nil
end
return M
-- vim:tw=79:ts=4:sw=4:noet:

View file

@ -21,7 +21,6 @@ local api = vim.api
local set_hl = api.nvim_set_hl
local create_augroup = api.nvim_create_augroup
local create_autocmd = api.nvim_create_autocmd
local get_parser = vim.treesitter.get_parser
local get_lang = vim.treesitter.language.get_lang
local config = require 'rainbow-delimiters.config'
local log = require 'rainbow-delimiters.log'
@ -44,99 +43,6 @@ end
define_hlgroups()
--- [ CALLBACK FUNCTIONS ]-----------------------------------------------------
local attach, detach
function attach(bufnr)
local lang = vim.treesitter.language.get_lang(vim.bo[bufnr].ft)
if not lang then
log.trace('Cannot attach to buffer %d, no parser for %s', bufnr, lang)
return
end
log.trace('Attaching to buffer %d with language %s.', bufnr, lang)
if lib.buffers[bufnr] then
if lib.buffers[bufnr].lang == lang then return end
-- The file type of the buffer has change, so we need to detach first
-- before we re-attach
detach(bufnr)
end
local parser
do
local success
success, parser = pcall(get_parser, bufnr, lang)
if not success then return end
end
local strategy
do
strategy = config.strategy[lang]
if type(strategy) == 'function' then
strategy = strategy()
end
end
if not strategy or strategy == vim.NIL then return end
-- Intentionally abort; the user has explicitly disabled rainbow delimiters
-- for this buffer, usually by setting a strategy- or query function which
-- returned nil.
if not strategy then
log.warn('No strategy defined for %s', lang)
end
parser:register_cbs {
on_detach = function(bnr)
if not lib.buffers[bnr] then return end
detach(bufnr)
end,
on_child_removed = function(child)
lib.clear_namespace(bufnr, child:lang())
end,
}
local settings = {
strategy = strategy,
parser = parser,
lang = lang
}
lib.buffers[bufnr] = settings
-- For now we silently discard errors, but in the future we should log
-- them.
local success, error = pcall(strategy.on_attach, bufnr, settings)
if not success then
log.error('Error attaching strategy to buffer %d: %s', bufnr, error)
lib.buffers[bufnr] = nil
end
end
function detach(bufnr)
log.trace('Detaching from buffer %d.', bufnr)
if not lib.buffers[bufnr] then
return
end
local strategy = lib.buffers[bufnr].strategy
local parser = lib.buffers[bufnr].parser
-- Clear all the namespaces for each language
parser:for_each_child(function(_, lang)
lib.clear_namespace(bufnr, lang)
end, true)
-- Finally release all resources the parser is holding on to
parser:destroy()
-- For now we silently discard errors, but in the future we should log
-- them.
local success, error = pcall(strategy.on_detach, bufnr)
if not success then
log.error('Error detaching strategy from buffer %d: %s', bufnr, error)
end
lib.buffers[bufnr] = nil
end
--- [ SET UP AUTOCOMMANDS ]----------------------------------------------------
local hl_augroup = create_augroup('TSRainbowHighlight', {})
local rb_augroup = create_augroup('TSRainbowDelimits', {})
@ -154,14 +60,14 @@ create_autocmd('FileType', {
local lang = get_lang(args.match)
if not config.enabled_for(lang) then return end
attach(args.buf)
lib.attach(args.buf)
end,
})
create_autocmd('BufUnload', {
desc = 'Detach from the current buffer',
group = rb_augroup,
callback = function(args) detach(args.buf) end
callback = function(args) lib.detach(args.buf) end
})
vim.g.loaded_rainbow = true

View file

@ -0,0 +1,80 @@
# We can use functions to turn rainbow delimiters off and on again.
Execute lua (Set up the plugin):
the_strategy = require('rainbow-delimiters.strategy.global')
vim.g.rainbow_delimiters = {strategy = {[''] = the_strategy}}
Given lua (A Lua buffer):
print((((('Hello, world!')))))
Execute (Leave things as they are):
redraw! " Without this there will be no extmarks at all
Then (Rainbow delimiters are active):
let extmarks = luaeval('vim.inspect_pos(0, 0, 5)').extmarks
\->map('v:val["ns_id"]')
\->filter({_, nsid -> nsid == luaeval('require("rainbow-delimiters.lib").nsids.lua')})
AssertNotEqual [], extmarks
Execute (Turn rainbow delimiters off):
call rainbow_delimiters#disable(0)
redraw! " Without this there will be no extmarks at all
Then (Rainbow delimiters are inactive):
let extmarks = luaeval('vim.inspect_pos(0, 0, 5)').extmarks
\->map('v:val["ns_id"]')
\->filter({_, nsid -> nsid == luaeval('require("rainbow-delimiters.lib").nsids.lua')})
AssertEqual [], extmarks
Execute (Turn rainbow delimiters off a second time):
call rainbow_delimiters#disable(0)
redraw! " Without this there will be no extmarks at all
Then (Disabling is idempotent):
let extmarks = luaeval('vim.inspect_pos(0, 0, 5)').extmarks
\->map('v:val["ns_id"]')
\->filter({_, nsid -> nsid == luaeval('require("rainbow-delimiters.lib").nsids.lua')})
AssertEqual [], extmarks
Execute (Turn rainbow delimiters back on):
call rainbow_delimiters#enable(0)
redraw! " Without this there will be no extmarks at all
Then (Rainbow delimiters are active):
let extmarks = luaeval('vim.inspect_pos(0, 0, 5)').extmarks
\->map('v:val["ns_id"]')
\->filter({_, nsid -> nsid == luaeval('require("rainbow-delimiters.lib").nsids.lua')})
AssertNotEqual [], extmarks
Execute (Turn rainbow delimiters on a second time):
call rainbow_delimiters#enable(0)
redraw! " Without this there will be no extmarks at all
Then (Enabling is idempotent):
let extmarks = luaeval('vim.inspect_pos(0, 0, 5)').extmarks
\->map('v:val["ns_id"]')
\->filter({_, nsid -> nsid == luaeval('require("rainbow-delimiters.lib").nsids.lua')})
AssertNotEqual [], extmarks
Execute (Toggle rainbow delimiters off):
call rainbow_delimiters#toggle(0)
redraw! " Without this there will be no extmarks at all
Then (Rainbow delimiters are inactive):
let extmarks = luaeval('vim.inspect_pos(0, 0, 5)').extmarks
\->map('v:val["ns_id"]')
\->filter({_, nsid -> nsid == luaeval('require("rainbow-delimiters.lib").nsids.lua')})
AssertEqual [], extmarks
Execute (Toggle rainbow delimiters back on):
call rainbow_delimiters#toggle(0)
redraw! " Without this there will be no extmarks at all
Then (Rainbow delimiters are active):
let extmarks = luaeval('vim.inspect_pos(0, 0, 5)').extmarks
\->map('v:val["ns_id"]')
\->filter({_, nsid -> nsid == luaeval('require("rainbow-delimiters.lib").nsids.lua')})
AssertNotEqual [], extmarks
# vim:tw=79:ts=2:sw=2:et: