Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

neovim/lua/std/light_up.lua

Raw
--- Highlights given words in a buffer.
--- Word matching is case sensitive.
--- @param bufnr number Number of buffer to highlight. If 0, current buffer is used.
--- @param words table Word to highlight group name mapping. Every occurrence with keys in this table, will be
--- highlighted with its mapped value, which is expected to be a highlight group name.
local function buffer( bufnr, words )
	vim.validate( 'bufnr', bufnr, 'number' )
	vim.validate( 'words', words, 'table' )

	local namespace = vim.api.nvim_create_namespace( 'light_up_ns' )
	vim.api.nvim_buf_clear_namespace( bufnr, namespace, 0, -1 )

	local handler = function ( event, buffer_handle, tick, first_line, last_line_changed, last_line_updated, bytes )
		assert( event == 'lines', 'this handler is for `on_lines` notification' )

		local last = math.max( last_line_updated, last_line_changed )
		local lines
		if last < 0 then
			lines = vim.api.nvim_buf_get_lines( bufnr, first_line, -1, true )
		else
			lines = vim.api.nvim_buf_get_lines( bufnr, first_line, last, true )
		end
		for index, line in ipairs( lines ) do
			local current_line = first_line + index - 1
			for word, highlight_group in pairs( words ) do
				local s = 1
				while s <= #line do
					local word_start = line:find( word, s, true )
					if not word_start then break end
					local before_char = line:sub( word_start - 1, word_start - 1 )
					local after_char = line:sub( word_start + #word, word_start + #word )
					local before_ok = #before_char == 0 or before_char:match( '[%s%.]' )
					local after_ok = #after_char == 0 or after_char:match( '[%s%.]' )
					if before_ok and after_ok then
						local start_col = word_start - 1
						local end_col = word_start + #word - 1
						vim.api.nvim_buf_set_extmark( bufnr, namespace, current_line, start_col, {
							end_col = end_col,
							hl_group = highlight_group,
						} )
					end
					s = word_start + 1
				end
			end
		end
	end

	local ok = vim.api.nvim_buf_attach( bufnr, false, { on_lines = handler } )
	if not ok then error( 'unable to attach to buffer ' .. bufnr ) end

	handler( 'lines', bufnr, nil, 0, -1, -1, nil )

	return namespace
end

--- @return table groups A map of all highlight group names, mapping to themselves.
local function get_vim_highlight_groups()
	local groups = {}
	for name in pairs( vim.api.nvim_get_hl( 0, {} ) ) do
		groups[name] = name
	end
	return groups
end

return {
	buffer = buffer,
	get_vim_highlight_groups = get_vim_highlight_groups,
}