feat(vim.version): add vim.version.intersect()

Problem: No way to compute intersection of two version ranges, which is
useful when computing version range that fits inside several reference
ranges.

Solution: Add `vim.version.intersect()`.
This commit is contained in:
Evgeni Chasnovski
2025-06-30 16:08:39 +03:00
parent 649ff924d9
commit 773075b2bc
4 changed files with 159 additions and 0 deletions

View File

@@ -145,6 +145,131 @@ describe('version', function()
end)
end)
describe('intersect', function()
local check = function(input, output)
local r1 = vim.version.range(input[1])
local r2 = vim.version.range(input[2])
if output == nil then
eq(vim.version.intersect(r1, r2), nil)
eq(vim.version.intersect(r2, r1), nil)
else
local ref = vim.version.range(output)
eq(vim.version.intersect(r1, r2), ref)
eq(vim.version.intersect(r2, r1), ref)
end
end
it('returns biggest common range', function()
check({ '>=1.2.3', '>=2.0.0' }, '>=2.0.0')
check({ '>=1.2.3', '>=1.3.0' }, '>=1.3.0')
check({ '>=1.2.3', '>=1.2.4' }, '>=1.2.4')
check({ '>=1.2.3', '>=1.2.3' }, '>=1.2.3')
check({ '>=1.2.3', '>1.2.4' }, '>1.2.4')
check({ '>=1.2.3', '>1.2.3' }, '>1.2.3')
check({ '>=1.2.3', '>1.2.2' }, '>=1.2.3')
check({ '>1.2.3', '>1.2.4' }, '>1.2.4')
check({ '>1.2.3', '>1.2.3' }, '>1.2.3')
check({ '>=1.2.3', '1.2.0 - 1.2.2' }, nil)
check({ '>=1.2.3', '1.2.0 - 1.2.2' }, nil)
check({ '>=1.2.3', '1.2.0 - 1.2.3' }, nil)
check({ '>=1.2.3', '1.2.0 - 1.2.4' }, '1.2.3 - 1.2.4')
check({ '>=1.2.3', '1.2.3 - 1.2.4' }, '1.2.3 - 1.2.4')
check({ '>=1.2.3', '1.2.4 - 1.3.0' }, '1.2.4 - 1.3.0')
check({ '>1.2.3', '1.2.0 - 1.2.2' }, nil)
check({ '>1.2.3', '1.2.0 - 1.2.2' }, nil)
check({ '>1.2.3', '1.2.0 - 1.2.3' }, nil)
check({ '>1.2.3', '1.2.0 - 1.2.4' }, '1.2.4-0 - 1.2.4')
check({ '>1.2.3', '1.2.3 - 1.2.4' }, '1.2.4-0 - 1.2.4')
check({ '>1.2.3', '1.2.4 - 1.3.0' }, '1.2.4 - 1.3.0')
check({ '>=1.2.3', '=1.2.4' }, '=1.2.4')
check({ '>=1.2.3', '=1.2.3' }, '=1.2.3')
check({ '>=1.2.3', '=1.2.2' }, nil)
check({ '>1.2.3', '=1.2.4' }, '=1.2.4')
check({ '>1.2.3', '=1.2.3' }, nil)
check({ '>1.2.3', '=1.2.2' }, nil)
check({ '>=1.2.3', '<=1.3.0' }, '1.2.3 - 1.3.1-0')
check({ '>=1.2.3', '<1.3.0' }, '1.2.3 - 1.3.0')
check({ '>=1.2.3', '<=1.2.3' }, '1.2.3 - 1.2.4-0') -- A better result would be '=1.2.3'
check({ '>=1.2.3', '<1.2.3' }, nil)
check({ '>=1.2.3', '<=1.2.2' }, nil)
check({ '>=1.2.3', '<1.2.2' }, nil)
check({ '>1.2.3', '<=1.3.0' }, '1.2.4-0 - 1.3.1-0')
check({ '>1.2.3', '<1.3.0' }, '1.2.4-0 - 1.3.0')
check({ '>1.2.3', '<=1.2.3' }, nil)
check({ '>1.2.3', '<1.2.3' }, nil)
check({ '>1.2.3', '<=1.2.2' }, nil)
check({ '>1.2.3', '<1.2.2' }, nil)
check({ '1.2.3 - 1.3.0', '1.3.1 - 1.4.0' }, nil)
check({ '1.2.3 - 1.3.0', '1.3.0 - 1.4.0' }, nil)
check({ '1.2.3 - 1.3.0', '1.2.4 - 1.4.0' }, '1.2.4 - 1.3.0')
check({ '1.2.3 - 1.3.0', '1.2.3 - 1.4.0' }, '1.2.3 - 1.3.0')
check({ '1.2.3 - 1.3.0', '1.2.2 - 1.4.0' }, '1.2.3 - 1.3.0')
check({ '1.2.3 - 1.3.0', '1.2.4 - 1.3.0' }, '1.2.4 - 1.3.0')
check({ '1.2.3 - 1.3.0', '1.2.3 - 1.3.0' }, '1.2.3 - 1.3.0')
check({ '1.2.3 - 1.3.0', '=1.4.0' }, nil)
check({ '1.2.3 - 1.3.0', '=1.3.0' }, nil)
check({ '1.2.3 - 1.3.0', '=1.2.4' }, '=1.2.4')
check({ '1.2.3 - 1.3.0', '=1.2.3' }, '=1.2.3')
check({ '1.2.3 - 1.3.0', '=1.2.2' }, nil)
check({ '1.2.3 - 1.3.0', '<=1.4.0' }, '1.2.3 - 1.3.0')
check({ '1.2.3 - 1.3.0', '<1.4.0' }, '1.2.3 - 1.3.0')
check({ '1.2.3 - 1.3.0', '<=1.3.0' }, '1.2.3 - 1.3.0')
check({ '1.2.3 - 1.3.0', '<1.3.0' }, '1.2.3 - 1.3.0')
check({ '1.2.3 - 1.3.0', '<=1.2.4' }, '1.2.3 - 1.2.5-0')
check({ '1.2.3 - 1.3.0', '<1.2.5' }, '1.2.3 - 1.2.5')
check({ '1.2.3 - 1.3.0', '<=1.2.3' }, '1.2.3 - 1.2.4-0') -- A better result would be '=1.2.3'
check({ '1.2.3 - 1.3.0', '<1.2.3' }, nil)
check({ '1.2.3 - 1.3.0', '<=1.2.2' }, nil)
check({ '1.2.3 - 1.3.0', '<1.2.2' }, nil)
check({ '=1.2.3', '=1.2.4' }, nil)
check({ '=1.2.3', '=1.2.3' }, '=1.2.3')
check({ '=1.2.3', '<1.2.3' }, nil)
check({ '<=1.2.2', '=1.2.3' }, nil)
check({ '=1.2.3', '<=1.3.0' }, '=1.2.3')
check({ '=1.2.3', '<1.3.0' }, '=1.2.3')
check({ '=1.2.3', '<=1.2.3' }, '=1.2.3')
check({ '=1.2.3', '<1.2.3' }, nil)
check({ '=1.2.3', '<=1.2.2' }, nil)
check({ '=1.2.3', '<1.2.2' }, nil)
check({ '<=1.2.3', '<=1.3.0' }, '<=1.2.3')
check({ '<=1.2.3', '<1.3.0' }, '<=1.2.3')
check({ '<=1.2.3', '<=1.2.3' }, '<=1.2.3')
check({ '<=1.2.3', '<1.2.3' }, '<1.2.3')
check({ '<=1.2.3', '<=1.2.2' }, '<=1.2.2')
check({ '<=1.2.3', '<1.2.2' }, '<1.2.2')
check({ '<1.2.3', '<=1.3.0' }, '<1.2.3')
check({ '<1.2.3', '<1.3.0' }, '<1.2.3')
check({ '<1.2.3', '<=1.2.3' }, '<1.2.3')
check({ '<1.2.3', '<1.2.3' }, '<1.2.3')
check({ '<1.2.3', '<=1.2.2' }, '<=1.2.2')
check({ '<1.2.3', '<1.2.2' }, '<1.2.2')
-- Selective coverage of ranges with pre-releases
check({ '>=1.2.3-0', '>=1.2.3-1' }, '>=1.2.3-1')
check({ '>=1.2.3-alpha', '>=1.2.3-beta' }, '>=1.2.3-beta')
check({ '>=1.2.3-0', '>=1.2.3-alpha' }, '>=1.2.3-alpha')
check({ '>=1.2.3-0', '<1.2.3' }, '1.2.3-0 - 1.2.3')
check({ '>=1.2.3-0', '<1.2.3-1' }, '1.2.3-0 - 1.2.3-1')
check({ '>=1.2.3-alpha', '<1.2.3-beta' }, '1.2.3-alpha - 1.2.3-beta')
check({ '>=1.2.3-0', '1.2.2 - 1.2.3' }, '1.2.3-0 - 1.2.3')
check({ '>=1.2.3-0', '<=1.2.2' }, nil)
check({ '<=1.2.3-0', '>=1.2.3' }, nil)
check({ '<=1.2.3-0', '=1.2.3' }, nil)
check({ '>=1.2.3-0', '<1.2.3-2' }, '1.2.3-0 - 1.2.3-2')
end)
end)
describe('cmp()', function()
local testcases = {
{ v1 = 'v0.0.99', v2 = 'v9.0.0', want = -1 },