Skip to content

Instantly share code, notes, and snippets.

@lopesivan
Created December 2, 2024 18:11
Show Gist options
  • Save lopesivan/ff4598e289cb691980813829d3deb0c8 to your computer and use it in GitHub Desktop.
Save lopesivan/ff4598e289cb691980813829d3deb0c8 to your computer and use it in GitHub Desktop.
vim.opt_local.foldexpr = "v:lua.vim.lsp.foldexpr()" e vim.opt_local.foldtext = require "config.foldtext"
--- @module Foldtext
--- Based on https://www.reddit.com/r/neovim/comments/16sqyjz/finally_we_can_have_highlighted_folds/
--- Updated with vim.treesitter._fold.foldtext()
-- Função para processar uma linha e extrair os destaques usando Treesitter
local function parse_line(linenr)
-- Obtém o buffer atual do Neovim
local bufnr = vim.api.nvim_get_current_buf()
-- Obtém a linha do buffer correspondente ao número da linha
local line = vim.api.nvim_buf_get_lines(bufnr, linenr - 1, linenr, false)[1]
-- Retorna nil se a linha não existir
if not line then
return nil
end
-- Tenta obter o parser do Treesitter para o buffer atual
local ok, parser = pcall(vim.treesitter.get_parser, bufnr)
-- Retorna nil se o parser não estiver disponível
if not ok then
return nil
end
-- Obtém a query de destaques da linguagem do parser
local query = vim.treesitter.query.get(parser:lang(), "highlights")
-- Retorna nil se não houver query de destaques configurada
if not query then
return nil
end
-- Realiza o parsing da linha com o Treesitter
local tree = parser:parse({ linenr - 1, linenr })[1]
-- Inicializa o resultado que armazenará os trechos destacados
local result = {}
-- Variável para rastrear a posição atual na linha
local line_pos = 0
-- Itera sobre as capturas do Treesitter na linha especificada
for id, node, metadata in query:iter_captures(tree:root(), 0, linenr - 1, linenr) do
-- Obtém o nome da captura atual
local name = query.captures[id]
-- Obtém as posições inicial e final do nó capturado
local start_row, start_col, end_row, end_col = node:range()
-- Define a prioridade do destaque, usando uma prioridade padrão se nenhuma for especificada
local priority = tonumber(metadata.priority or vim.highlight.priorities.treesitter)
-- Processa apenas capturas que estão inteiramente na linha atual
if start_row == linenr - 1 and end_row == linenr - 1 then
-- Verifica se há caracteres entre a posição atual e o início da captura
if start_col > line_pos then
-- Adiciona o trecho ignorado pelo Treesitter ao resultado
table.insert(result, {
line:sub(line_pos + 1, start_col), -- Texto sem destaque
{ { "Folded", priority } }, -- Aplica destaque padrão "Folded"
range = { line_pos, start_col }, -- Define a faixa de caracteres
})
end
-- Atualiza a posição atual para o final da captura
line_pos = end_col
-- Extrai o texto capturado
local text = line:sub(start_col + 1, end_col)
-- Adiciona o texto capturado com o destaque correspondente ao resultado
table.insert(result, {
text, -- Texto capturado
{ { "@" .. name, priority } }, -- Destaque baseado no nome da captura
range = { start_col, end_col }, -- Define a faixa de caracteres
})
end
end
-- Variável para iterar sobre os resultados processados
local i = 1
while i <= #result do
-- Encontra capturas que estão dentro do intervalo da captura atual
local j = i + 1
while j <= #result and result[j].range[1] >= result[i].range[1] and result[j].range[2] <= result[i].range[2] do
-- Adiciona os destaques da captura pai às capturas filhas
for k, v in ipairs(result[i][2]) do
if not vim.tbl_contains(result[j][2], v) then
table.insert(result[j][2], k, v)
end
end
j = j + 1
end
-- Remove a captura pai se ela foi dividida em capturas filhas
if j > i + 1 then
table.remove(result, i)
else
-- Ordena os destaques por prioridade
if #result[i][2] > 1 then
table.sort(result[i][2], function(a, b)
return a[2] < b[2]
end)
end
-- Simplifica a estrutura de destaque para conter apenas os nomes
result[i][2] = vim.tbl_map(function(tbl)
return tbl[1]
end, result[i][2])
result[i] = { result[i][1], result[i][2] }
-- Avança para a próxima captura
i = i + 1
end
end
-- Retorna o resultado processado
return result
end
-- Função principal que monta o texto dobrado com destaques
function HighlightedFoldtext()
-- Processa a linha inicial do fold
local result = parse_line(vim.v.foldstart)
-- Retorna o texto padrão do fold se não houver destaques
if not result then
return vim.fn.foldtext()
end
-- Adiciona ícones e informações de linhas dobradas ao resultado
local folded = {
{ "  ", "FoldedIcon" }, -- Ícone inicial
{ "+" .. vim.v.foldend - vim.v.foldstart .. " lines", "FoldedText" }, -- Contador de linhas
{ "  ", "FoldedIcon" }, -- Ícone final
}
-- Insere os elementos adicionais no resultado
for _, item in ipairs(folded) do
table.insert(result, item)
end
-- Processa a linha final do fold para capturar destaques adicionais
local result2 = parse_line(vim.v.foldend)
if result2 then
local first = result2[1]
if first then -- Verifica se o primeiro item não é nulo
result2[1] = { vim.trim(first[1]), first[2] }
for _, item in ipairs(result2) do
table.insert(result, item)
end
end
end
-- Retorna o resultado final com os destaques
return result
end
-- Função para configurar os destaques personalizados de fold
local function set_fold_hl()
-- Obtém as cores do destaque atual
local cl = vim.api.nvim_get_hl(0, { name = "CursorLineNr" })
-- Define a cor do ícone dobrado
vim.api.nvim_set_hl(0, "FoldedIcon", { fg = cl.bg })
-- Define a cor e o estilo do texto dobrado
vim.api.nvim_set_hl(0, "FoldedText", { bg = cl.bg, fg = cl.fg, italic = true })
end
-- Aplica as configurações de destaque
set_fold_hl()
-- Atualiza as configurações de destaque quando o esquema de cores é alterado
vim.api.nvim_create_autocmd("ColorScheme", {
callback = set_fold_hl,
})
-- Retorna a função que será usada como `foldtext`
return 'luaeval("HighlightedFoldtext")()'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment