Skip to content

Commit

Permalink
feat(provider): marker provider (#218)
Browse files Browse the repository at this point in the history
* feat(provider): marker provider

Add a provider that can fold generic markers. The default ones are:

* 'foldmarker' option
* '#region' and '#endregion' from VS Code
  • Loading branch information
LucasAVasco authored Jul 12, 2024
1 parent a57e088 commit 1b5f283
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 1 deletion.
1 change: 1 addition & 0 deletions lua/ufo/model/foldingrange.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
---| 'comment'
---| 'imports'
---| 'region'
---| 'marker'

---@class UfoFoldingRange
---@field startLine number
Expand Down
2 changes: 1 addition & 1 deletion lua/ufo/provider/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ local log = require('ufo.lib.log')
---@field modules table
local Provider = {
modulePathPrefix = 'ufo.provider.',
innerProviders = {'lsp', 'treesitter', 'indent'}
innerProviders = {'lsp', 'treesitter', 'indent', 'marker'}
}

local function needFallback(reason)
Expand Down
81 changes: 81 additions & 0 deletions lua/ufo/provider/marker.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
local foldingrange = require('ufo.model.foldingrange')
local bufmanager = require('ufo.bufmanager')
local utils = require('ufo.utils')


-- Provider implementation

local Marker = {}


-- 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
}


--- 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
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
}

-- 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)
end

-- Close marker
start_column = line:find(marker[2], end_column or 1, true)

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])
)
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
end


return Marker

0 comments on commit 1b5f283

Please sign in to comment.