Update generated neovim config
This commit is contained in:
@ -78,15 +78,16 @@ function Buffer:attach()
|
||||
end
|
||||
|
||||
---lower is less than or equal to lnum
|
||||
---@param lines table<number, any|boolean>
|
||||
---@param lnum number
|
||||
---@param endLnum number
|
||||
---@return table[]
|
||||
function Buffer:buildMissingHunk(lnum, endLnum)
|
||||
function Buffer:buildMissingHunk(lines, lnum, endLnum)
|
||||
local hunks = {}
|
||||
local s, e
|
||||
local cnt = 0
|
||||
for i = lnum, endLnum do
|
||||
if not self._lines[i] then
|
||||
if not lines[i] then
|
||||
cnt = cnt + 1
|
||||
if not s then
|
||||
s = i
|
||||
@ -107,7 +108,7 @@ function Buffer:buildMissingHunk(lnum, endLnum)
|
||||
if fhLnum == lnum then
|
||||
local i = lnum - 1
|
||||
while i > 0 do
|
||||
if self._lines[i] then
|
||||
if lines[i] then
|
||||
break
|
||||
end
|
||||
i = i - 1
|
||||
@ -230,7 +231,7 @@ function Buffer:lines(lnum, endLnum)
|
||||
if endLnum < 0 then
|
||||
endLnum = lineCount + endLnum + 1
|
||||
end
|
||||
for _, hunk in ipairs(self:buildMissingHunk(lnum, endLnum)) do
|
||||
for _, hunk in ipairs(self:buildMissingHunk(self._lines, lnum, endLnum)) do
|
||||
local hs, he = hunk[1], hunk[2]
|
||||
local lines = api.nvim_buf_get_lines(self.bufnr, hs - 1, he, true)
|
||||
for i = hs, he do
|
||||
|
||||
@ -1,37 +1,92 @@
|
||||
local uv = vim.loop
|
||||
|
||||
local foldingrange = require('ufo.model.foldingrange')
|
||||
local event = require('ufo.lib.event')
|
||||
local disposable = require('ufo.lib.disposable')
|
||||
local bufmanager = require('ufo.bufmanager')
|
||||
|
||||
---@class UfoIndentProvider
|
||||
---@field buffers table
|
||||
---@field bufNum number
|
||||
---@field disposables UfoDisposable[]
|
||||
local Indent = {}
|
||||
|
||||
---@class UfoIndentBuffer
|
||||
---@field buf UfoBuffer
|
||||
---@field hrtime number
|
||||
---@field version number
|
||||
---@field levels number[]
|
||||
---@field tabstop number
|
||||
---@field shiftWidth number
|
||||
local IndentBuffer = {}
|
||||
IndentBuffer.__index = IndentBuffer
|
||||
|
||||
---
|
||||
---@param buf UfoBuffer
|
||||
---@return UfoIndentBuffer
|
||||
function IndentBuffer:new(buf)
|
||||
local o = self == IndentBuffer and setmetatable({}, self) or self
|
||||
o.buf = buf
|
||||
o.hrtime = uv.hrtime()
|
||||
o.version = 0
|
||||
o.levels = {}
|
||||
return o
|
||||
end
|
||||
|
||||
function IndentBuffer:getMissHunks(lnum, endLnum)
|
||||
return self.buf:buildMissingHunk(self.levels, lnum, endLnum)
|
||||
end
|
||||
|
||||
function IndentBuffer:handleFoldedLinesChanged(first, last, lastUpdated)
|
||||
self.levels = self.buf:handleLinesChanged(self.levels, first, last, lastUpdated)
|
||||
end
|
||||
|
||||
function Indent.getFolds(bufnr)
|
||||
local buf = bufmanager:get(bufnr)
|
||||
if not buf then
|
||||
local self = Indent
|
||||
local ib = self:getBuffer(bufnr) or self:addBuffer(bufnr)
|
||||
if not ib then
|
||||
return
|
||||
end
|
||||
local lines = buf:lines(1, -1)
|
||||
local ts = vim.bo[bufnr].ts
|
||||
local sw = vim.bo[bufnr].sw
|
||||
sw = sw == 0 and ts or sw
|
||||
local levels = {}
|
||||
for _, line in ipairs(lines) do
|
||||
local level = -1
|
||||
local n = 0
|
||||
for col = 1, #line do
|
||||
-- compare byte is slightly faster than a char in the string
|
||||
local b = line:byte(col, col)
|
||||
if b == 0x20 then
|
||||
-- ' '
|
||||
n = n + 1
|
||||
elseif b == 0x09 then
|
||||
-- '\t'
|
||||
n = n + (ts - (n % ts))
|
||||
else
|
||||
level = math.ceil(n / sw)
|
||||
break
|
||||
end
|
||||
end
|
||||
table.insert(levels, level)
|
||||
local buf = ib.buf
|
||||
local ts, sw = vim.bo[bufnr].ts, vim.bo[bufnr].sw
|
||||
local hunks
|
||||
local cnt = buf:lineCount()
|
||||
if ts ~= ib.tabstop or sw ~= ib.shiftWidth then
|
||||
ib.tabstop, ib.shiftWidth = ts, sw
|
||||
hunks = {{1, cnt}}
|
||||
else
|
||||
hunks = ib:getMissHunks(1, cnt)
|
||||
end
|
||||
if sw == 0 then
|
||||
sw = ts
|
||||
end
|
||||
local levels = ib.levels
|
||||
for _, hunk in ipairs(hunks) do
|
||||
local startLnum, endLnum = hunk[1], hunk[2]
|
||||
local lines = buf:lines(startLnum, endLnum)
|
||||
for i, line in ipairs(lines) do
|
||||
local level = -1
|
||||
local n = 0
|
||||
for col = 1, #line do
|
||||
-- compare byte is slightly faster than a char in the string
|
||||
local b = line:byte(col, col)
|
||||
if b == 0x20 then
|
||||
-- ' '
|
||||
n = n + 1
|
||||
elseif b == 0x09 then
|
||||
-- '\t'
|
||||
n = n + (ts - (n % ts))
|
||||
else
|
||||
level = math.ceil(n / sw)
|
||||
break
|
||||
end
|
||||
end
|
||||
levels[startLnum + i - 1] = level
|
||||
end
|
||||
end
|
||||
|
||||
ib.version = buf:changedtick()
|
||||
ib.hrtime = uv.hrtime()
|
||||
|
||||
local ranges = {}
|
||||
local stack = {}
|
||||
@ -66,4 +121,83 @@ function Indent.getFolds(bufnr)
|
||||
return ranges
|
||||
end
|
||||
|
||||
---
|
||||
---@param bufnr number
|
||||
---@return UfoIndentBuffer
|
||||
function Indent:getBuffer(bufnr)
|
||||
return self.buffers[bufnr]
|
||||
end
|
||||
|
||||
function Indent:addBuffer(bufnr)
|
||||
local buf = bufmanager:get(bufnr)
|
||||
if not buf then
|
||||
return
|
||||
end
|
||||
self.buffers[bufnr] = IndentBuffer:new(buf)
|
||||
if self.bufNum == 0 then
|
||||
self.eventsDisposables = self:createEvents()
|
||||
end
|
||||
self.bufNum = self.bufNum + 1
|
||||
return self.buffers[bufnr]
|
||||
end
|
||||
|
||||
function Indent:removeBuffer(bufnr)
|
||||
if self.bufNum == 0 then
|
||||
return
|
||||
end
|
||||
local ib = self:getBuffer(bufnr)
|
||||
if ib then
|
||||
self.buffers[bufnr] = nil
|
||||
self.bufNum = self.bufNum - 1
|
||||
if self.bufNum == 0 then
|
||||
self:destroyEvents()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Indent:createEvents()
|
||||
local disposables = {}
|
||||
event:on('BufLinesChanged', function(bufnr, changedtick, firstLine, lastLine, lastLineUpdated)
|
||||
local ib = self:getBuffer(bufnr)
|
||||
if ib then
|
||||
ib.levels = ib.buf:handleLinesChanged(ib.levels, firstLine, lastLine, lastLineUpdated)
|
||||
-- May become fallback provider, compare the version with changedtick to remove
|
||||
if changedtick > ib.version + 20 then
|
||||
-- 20s interval
|
||||
if uv.hrtime() - ib.hrtime > 20 * 1e9 then
|
||||
self:removeBuffer(bufnr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end, disposables)
|
||||
event:on('BufDetach', function(bufnr)
|
||||
self:removeBuffer(bufnr)
|
||||
end, disposables)
|
||||
event:on('BufReload', function(bufnr)
|
||||
self:removeBuffer(bufnr)
|
||||
end, disposables)
|
||||
return disposables
|
||||
end
|
||||
|
||||
function Indent:destroyEvents()
|
||||
disposable.disposeAll(self.eventsDisposables)
|
||||
end
|
||||
|
||||
function Indent:dispose()
|
||||
self:destroyEvents()
|
||||
self:initialize()
|
||||
end
|
||||
|
||||
function Indent:initialize()
|
||||
self.bufNum = 0
|
||||
self.buffers = {}
|
||||
self.eventsDisposables = {}
|
||||
end
|
||||
|
||||
local function init()
|
||||
Indent:initialize()
|
||||
end
|
||||
|
||||
init()
|
||||
|
||||
return Indent
|
||||
|
||||
@ -1,81 +1,221 @@
|
||||
local uv = vim.loop
|
||||
|
||||
local foldingrange = require('ufo.model.foldingrange')
|
||||
local bufmanager = require('ufo.bufmanager')
|
||||
local utils = require('ufo.utils')
|
||||
|
||||
local event = require('ufo.lib.event')
|
||||
local disposable = require('ufo.lib.disposable')
|
||||
|
||||
-- Provider implementation
|
||||
|
||||
---@class UfoMarkerProvider
|
||||
---@field buffers table
|
||||
---@field bufNum number
|
||||
---@field disposables UfoDisposable[]
|
||||
local Marker = {}
|
||||
|
||||
local OPEN = -1
|
||||
local CLOSE = 1
|
||||
|
||||
-- Data necessary to query folding ranges from VS Code region folding
|
||||
local vs_code_marker = {
|
||||
'#region', -- Start of marker
|
||||
'#endregion', -- End of marker
|
||||
'region', -- Kind to be applied to a VS Code region folding
|
||||
}
|
||||
---@class UfoMarkerBuffer
|
||||
---@field buf UfoBuffer
|
||||
---@field hrtime number
|
||||
---@field version number
|
||||
---@field markerLines number[]
|
||||
---@field foldmarker string
|
||||
local MarkerBuffer = {}
|
||||
MarkerBuffer.__index = MarkerBuffer
|
||||
|
||||
function MarkerBuffer:new(buf)
|
||||
local o = self == MarkerBuffer and setmetatable({}, self) or self
|
||||
o.buf = buf
|
||||
o.hrtime = uv.hrtime()
|
||||
o.version = 0
|
||||
o.markerLines = {}
|
||||
return o
|
||||
end
|
||||
|
||||
function MarkerBuffer:getMissHunks(lnum, endLnum)
|
||||
return self.buf:buildMissingHunk(self.markerLines, lnum, endLnum)
|
||||
end
|
||||
|
||||
function MarkerBuffer:handleFoldedLinesChanged(first, last, lastUpdated)
|
||||
self.markerLines = self.buf:handleLinesChanged(self.markerLines, first, last, lastUpdated)
|
||||
end
|
||||
|
||||
--- Function that returns folds for the provided buffer based in the markers
|
||||
--- @param bufnr number Vim buffer number
|
||||
--- @return UfoFoldingRange[]|nil Folds List of marker folds in the buffer, or `nil` if they can not be queried
|
||||
function Marker.getFolds(bufnr)
|
||||
local buf = bufmanager:get(bufnr)
|
||||
local winid = utils.getWinByBuf(bufnr)
|
||||
|
||||
-- Does not work with buffers or windows that are not managed by UFO
|
||||
if not buf or winid < 0 then
|
||||
if winid < 0 then
|
||||
return
|
||||
end
|
||||
|
||||
-- Defines the 'start' and 'end' markers that the provider will search, and the kind to apply
|
||||
-- to these markers. Each element of the `markers` list is a list of the 'start', 'end' markers
|
||||
-- and kind applied, in this order. Example: `local markers = { { 'start marker', 'end marker', 'marker kind' } }`
|
||||
-- The search is done by marker pair. One marker pair does not affect the other. So the end marker of `markers[0]`
|
||||
-- will not close the start marker of `markers[1]`, by example.
|
||||
local markers = {
|
||||
vim.fn.split(vim.wo[winid].foldmarker .. ',marker', ','), -- Configured Vim marker
|
||||
vs_code_marker
|
||||
}
|
||||
local self = Marker
|
||||
local mb = self:getBuffer(bufnr) or self:addBuffer(bufnr)
|
||||
if not mb then
|
||||
return
|
||||
end
|
||||
|
||||
-- Query the markers, generate the folding ranges and save in the `folds` variable
|
||||
local lines = buf:lines(1, -1)
|
||||
local folds = {}
|
||||
|
||||
for _, marker in ipairs(markers) do
|
||||
local openMarkerLines = {}
|
||||
|
||||
for lineNum, line in ipairs(lines) do
|
||||
-- Open marker
|
||||
local start_column, end_column = line:find(marker[1], 1, true)
|
||||
|
||||
if start_column then
|
||||
table.insert(openMarkerLines, lineNum)
|
||||
local buf = mb.buf
|
||||
local foldmarker = vim.wo[winid].foldmarker
|
||||
local hunks
|
||||
local cnt = buf:lineCount()
|
||||
if mb.foldmarker ~= foldmarker then
|
||||
mb.foldmarker = foldmarker
|
||||
hunks = {{1, cnt}}
|
||||
else
|
||||
hunks = mb:getMissHunks(1, cnt)
|
||||
end
|
||||
local markerLines = mb.markerLines
|
||||
local startPat, endPat = unpack(vim.split(foldmarker, ',', {plain = true}))
|
||||
for _, hunk in ipairs(hunks) do
|
||||
local startLnum, endLnum = hunk[1], hunk[2]
|
||||
local lines = buf:lines(startLnum, endLnum)
|
||||
for i, line in ipairs(lines) do
|
||||
-- open position start, close position start
|
||||
local ops, cps = 0, 0
|
||||
-- open position end, close position end
|
||||
local ope, cpe
|
||||
local j = 1
|
||||
local res = {}
|
||||
local len = #line
|
||||
while true do
|
||||
if ops <= len and j > ops then
|
||||
ops, ope = line:find(startPat, j, true)
|
||||
if not ops then
|
||||
ops = len + 1
|
||||
end
|
||||
end
|
||||
if cps <= len and j > cps then
|
||||
cps, cpe = line:find(endPat, j, true)
|
||||
if not cps then
|
||||
cps = len + 1
|
||||
end
|
||||
end
|
||||
if ops > len and cps > len then
|
||||
break
|
||||
end
|
||||
if ops <= cps then
|
||||
table.insert(res, OPEN)
|
||||
j = ope + 1
|
||||
else
|
||||
table.insert(res, CLOSE)
|
||||
j = cpe + 1
|
||||
end
|
||||
end
|
||||
markerLines[startLnum + i - 1] = res
|
||||
end
|
||||
end
|
||||
|
||||
-- Close marker
|
||||
start_column = line:find(marker[2], end_column or 1, true)
|
||||
mb.version = buf:changedtick()
|
||||
mb.hrtime = uv.hrtime()
|
||||
|
||||
if start_column then
|
||||
local relatedOpenMarkerLine = table.remove(openMarkerLines)
|
||||
|
||||
if relatedOpenMarkerLine then
|
||||
table.insert(
|
||||
folds,
|
||||
foldingrange.new(relatedOpenMarkerLine - 1, lineNum - 1, nil, nil, marker[3])
|
||||
local ranges = {}
|
||||
local stack = {}
|
||||
for lnum, lmarkers in ipairs(markerLines) do
|
||||
for _, v in ipairs(lmarkers) do
|
||||
if v == OPEN then
|
||||
table.insert(stack, lnum)
|
||||
else
|
||||
local last = stack[#stack]
|
||||
if last then
|
||||
table.remove(stack)
|
||||
table.insert(ranges, foldingrange.new(last - 1, lnum - 1,
|
||||
nil, nil, 'marker')
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Closes all remaining open markers (they will be open to the end of the file)
|
||||
for _, markerStart in ipairs(openMarkerLines) do
|
||||
table.insert(folds, foldingrange.new(markerStart - 1, #lines, nil, nil, marker[3]))
|
||||
end
|
||||
end
|
||||
|
||||
return folds
|
||||
while #stack > 0 do
|
||||
local last = table.remove(stack)
|
||||
table.insert(ranges, foldingrange.new(last - 1, cnt - 1,
|
||||
nil, nil, 'marker'))
|
||||
end
|
||||
|
||||
return ranges
|
||||
end
|
||||
|
||||
---
|
||||
---@param bufnr number
|
||||
---@return UfoMarkerBuffer
|
||||
function Marker:getBuffer(bufnr)
|
||||
return self.buffers[bufnr]
|
||||
end
|
||||
|
||||
function Marker:addBuffer(bufnr)
|
||||
local buf = bufmanager:get(bufnr)
|
||||
if not buf then
|
||||
return
|
||||
end
|
||||
self.buffers[bufnr] = MarkerBuffer:new(buf)
|
||||
if self.bufNum == 0 then
|
||||
self.eventsDisposables = self:createEvents()
|
||||
end
|
||||
self.bufNum = self.bufNum + 1
|
||||
return self.buffers[bufnr]
|
||||
end
|
||||
|
||||
function Marker:removeBuffer(bufnr)
|
||||
if self.bufNum == 0 then
|
||||
return
|
||||
end
|
||||
local ib = self:getBuffer(bufnr)
|
||||
if ib then
|
||||
self.buffers[bufnr] = nil
|
||||
self.bufNum = self.bufNum - 1
|
||||
if self.bufNum == 0 then
|
||||
self:destroyEvents()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Marker:createEvents()
|
||||
local disposables = {}
|
||||
event:on('BufLinesChanged', function(bufnr, changedtick, firstLine, lastLine, lastLineUpdated)
|
||||
local ib = self:getBuffer(bufnr)
|
||||
if ib then
|
||||
ib.markerLines = ib.buf:handleLinesChanged(ib.markerLines, firstLine, lastLine, lastLineUpdated)
|
||||
-- May become fallback provider, compare the version with changedtick to remove
|
||||
if changedtick > ib.version + 20 then
|
||||
-- 20s interval
|
||||
if uv.hrtime() - ib.hrtime > 20 * 1e9 then
|
||||
self:removeBuffer(bufnr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end, disposables)
|
||||
event:on('BufDetach', function(bufnr)
|
||||
self:removeBuffer(bufnr)
|
||||
end, disposables)
|
||||
event:on('BufReload', function(bufnr)
|
||||
self:removeBuffer(bufnr)
|
||||
end, disposables)
|
||||
return disposables
|
||||
end
|
||||
|
||||
function Marker:destroyEvents()
|
||||
disposable.disposeAll(self.eventsDisposables)
|
||||
end
|
||||
|
||||
function Marker:dispose()
|
||||
self:destroyEvents()
|
||||
self:initialize()
|
||||
end
|
||||
|
||||
function Marker:initialize()
|
||||
self.bufNum = 0
|
||||
self.buffers = {}
|
||||
self.eventsDisposables = {}
|
||||
end
|
||||
|
||||
local function init()
|
||||
Marker:initialize()
|
||||
end
|
||||
|
||||
init()
|
||||
|
||||
return Marker
|
||||
|
||||
@ -90,7 +90,7 @@ local function iterFoldMatches(bufnr, parser, root, rootLang)
|
||||
return function() end
|
||||
end
|
||||
---@diagnostic disable-next-line: need-check-nil
|
||||
local iter = q:iter_matches(p.root, p.source, p.start, p.stop)
|
||||
local iter = q:iter_matches(p.root, p.source, p.start, p.stop, { all = false })
|
||||
return function()
|
||||
local pattern, match, metadata = iter()
|
||||
local matches = {}
|
||||
@ -179,7 +179,8 @@ function Treesitter.getFolds(bufnr)
|
||||
stop = stop - 1
|
||||
end
|
||||
if stop > start then
|
||||
table.insert(ranges, foldingrange.new(start, stop))
|
||||
local type = node.type and node:type() or nil
|
||||
table.insert(ranges, foldingrange.new(start, stop, nil, nil, type))
|
||||
end
|
||||
end
|
||||
foldingrange.sortRanges(ranges)
|
||||
|
||||
Reference in New Issue
Block a user