diff --git a/runtime/doc/pack.txt b/runtime/doc/pack.txt index e099eb0ca8..ebbccba702 100644 --- a/runtime/doc/pack.txt +++ b/runtime/doc/pack.txt @@ -220,7 +220,8 @@ is assumed that all plugins in the directory are managed exclusively by Uses Git to manage plugins and requires present `git` executable. Target plugins should be Git repositories with versions as named tags following -semver convention `v..`. +semver convention `v..` (with or without `v` prefix). +Like `v1.2.0` or `1.2.0`, but not `1.2` or `v1`. The latest state of all managed plugins is stored inside a *vim.pack-lockfile* located at `$XDG_CONFIG_HOME/nvim/nvim-pack-lock.json`. It is a JSON file that diff --git a/runtime/lua/vim/pack.lua b/runtime/lua/vim/pack.lua index 9b5c28bc5f..ae965c68df 100644 --- a/runtime/lua/vim/pack.lua +++ b/runtime/lua/vim/pack.lua @@ -12,7 +12,8 @@ --- ---Uses Git to manage plugins and requires present `git` executable. ---Target plugins should be Git repositories with versions as named tags ----following semver convention `v..`. +---following semver convention `v..` (with or without `v` prefix). +---Like `v1.2.0` or `1.2.0`, but not `1.2` or `v1`. --- ---The latest state of all managed plugins is stored inside a [vim.pack-lockfile]() ---located at `$XDG_CONFIG_HOME/nvim/nvim-pack-lock.json`. It is a JSON file that @@ -255,6 +256,10 @@ local function git_cmd(cmd, cwd) return (stdout:gsub('\n+$', '')) end +local function parse_semver(x) + return vim.version.parse(x, { strict = true }) +end + --- @type vim.Version local git_version @@ -274,7 +279,7 @@ local function git_clone(url, path) if vim.startswith(url, 'file://') then cmd[#cmd + 1] = '--no-hardlinks' - elseif git_version >= vim.version.parse('2.27') then + elseif git_version >= parse_semver('2.27.0') then cmd[#cmd + 1] = '--filter=blob:none' end @@ -343,7 +348,7 @@ end --- @param x string --- @return boolean local function is_semver(x) - return vim.version.parse(x) ~= nil + return parse_semver(x) ~= nil end local function is_nonempty_string(x) @@ -585,7 +590,7 @@ end local function get_last_semver_tag(tags, version_range) local last_tag, last_ver_tag --- @type string, vim.Version for _, tag in ipairs(tags) do - local ver_tag = vim.version.parse(tag) + local ver_tag = parse_semver(tag) if ver_tag then if version_range:has(ver_tag) and (not last_ver_tag or ver_tag > last_ver_tag) then last_tag, last_ver_tag = tag, ver_tag @@ -667,7 +672,7 @@ local function checkout(p, timestamp, skip_stash) if not skip_stash then local stash_cmd = { 'stash' } - if git_version > vim.version.parse('2.13') then + if git_version > parse_semver('2.13.0') then -- Use 'push' to avoid a 'stash -m' bug in versions prior to git v2.26 stash_cmd[#stash_cmd + 1] = 'push' stash_cmd[#stash_cmd + 1] = '--message' @@ -680,7 +685,7 @@ local function checkout(p, timestamp, skip_stash) git_cmd({ 'checkout', '--quiet', p.info.sha_target }, p.path) local submodule_cmd = { 'submodule', 'update', '--init', '--recursive' } - if git_version >= vim.version.parse('2.36') then + if git_version >= parse_semver('2.36.0') then submodule_cmd[#submodule_cmd + 1] = '--filter=blob:none' end git_cmd(submodule_cmd, p.path) @@ -760,7 +765,7 @@ local function infer_update_details(p) end local older_tags = '' - if git_version >= vim.version.parse('2.13') then + if git_version >= parse_semver('2.13.0') then older_tags = git_cmd({ 'tag', '--list', '--no-contains', sha_head }, p.path) end local cur_tags = git_cmd({ 'tag', '--list', '--points-at', sha_head }, p.path) diff --git a/test/functional/plugin/pack_spec.lua b/test/functional/plugin/pack_spec.lua index 5d416ea8e8..1b97921273 100644 --- a/test/functional/plugin/pack_spec.lua +++ b/test/functional/plugin/pack_spec.lua @@ -225,8 +225,8 @@ function repos_setup.semver() add_tag('v0.3.0') repo_write_file('semver', 'lua/semver.lua', 'return "semver middle-commit') git_add_commit('Add middle commit', 'semver') - add_tag('0.3.1') - add_tag('v0.4') + add_tag('0.3.1') -- Semver even without `v` prefix + add_tag('v0.4') -- Not semver since it requires all three version numbers add_tag('non-semver') add_tag('v0.2.1') -- Intentionally add version not in order add_tag('v1.0.0') @@ -946,7 +946,7 @@ describe('vim.pack', function() eq('basic some-tag', exec_lua('return require("basic")')) eq('defbranch main', exec_lua('return require("defbranch")')) - eq('semver v0.4', exec_lua('return require("semver")')) + eq('semver 0.3.1', exec_lua('return require("semver")')) end) it('respects plugin/ and after/plugin/ scripts', function() @@ -1063,7 +1063,7 @@ describe('vim.pack', function() 'Available:\nTags: some%-tag\nBranches: main, feat%-branch', -- Should report available branches and versions if no constraint match '`semver`', - 'Available:\nVersions: v1%.0%.0, v0%.4, 0%.3%.1, v0%.3%.0.*\nBranches: main\n', + 'Available:\nVersions: v1%.0%.0, 0%.3%.1, v0%.3%.0.*\nBranches: main\n', '`pluginerr`:\n', 'Wow, an error', } @@ -1260,7 +1260,7 @@ describe('vim.pack', function() -- This requires computing target hashes on each test run because they -- change due to source repos being cleanly created on each file test. local screen - screen = Screen.new(85, 35) + screen = Screen.new(85, 34) hashes.fetch_new = git_get_hash('main', 'fetch') short_hashes.fetch_new = git_get_short_hash('main', 'fetch') @@ -1301,7 +1301,6 @@ describe('vim.pack', function() | Available newer versions: | • {102:v1.0.0} | - • {102:v0.4} | • {102:0.3.1} | {1:~ }| | @@ -1453,8 +1452,8 @@ describe('vim.pack', function() { lnum = 3, col = 1, end_lnum = 9, end_col = 1, text = '[Module] defbranch' }, { lnum = 9, col = 1, end_lnum = 22, end_col = 1, text = '[Namespace] Update' }, { lnum = 11, col = 1, end_lnum = 22, end_col = 1, text = '[Module] fetch' }, - { lnum = 22, col = 1, end_lnum = 32, end_col = 1, text = '[Namespace] Same' }, - { lnum = 24, col = 1, end_lnum = 32, end_col = 1, text = '[Module] semver (not active)' }, + { lnum = 22, col = 1, end_lnum = 31, end_col = 1, text = '[Namespace] Same' }, + { lnum = 24, col = 1, end_lnum = 31, end_col = 1, text = '[Module] semver (not active)' }, } eq(ref_loclist, loclist) @@ -1497,8 +1496,7 @@ describe('vim.pack', function() assert_hover({ 20, 0 }, 'Commit to be added 1') assert_hover({ 27, 0 }, 'Add version v0.3.0') assert_hover({ 30, 0 }, 'Add version v1.0.0') - assert_hover({ 31, 0 }, 'Add version v0.4') - assert_hover({ 32, 0 }, 'Add version 0.3.1') + assert_hover({ 31, 0 }, 'Add version 0.3.1') -- textDocument/codeAction n.exec_lua(function() @@ -1560,7 +1558,7 @@ describe('vim.pack', function() -- - Only deletion should be available for not active plugins assert_action({ 24, 0 }, { 'Delete `semver`' }, 0) assert_action({ 28, 0 }, { 'Delete `semver`' }, 0) - assert_action({ 32, 0 }, { 'Delete `semver`' }, 0) + assert_action({ 31, 0 }, { 'Delete `semver`' }, 0) -- - Should correctly perform action and remove plugin's lines local function line_match(lnum, pattern) @@ -1633,7 +1631,7 @@ describe('vim.pack', function() -- - Should not wrap around the edge assert(']]', { 24, 0 }) - api.nvim_win_set_cursor(0, { 32, 1 }) + api.nvim_win_set_cursor(0, { 31, 1 }) assert('[[', { 24, 0 }) assert('[[', { 11, 0 }) assert('[[', { 3, 0 }) @@ -1652,7 +1650,7 @@ describe('vim.pack', function() -- Should correctly infer that 0.3.0 is the latest version and suggest -- versions greater than that local confirm_text = table.concat(api.nvim_buf_get_lines(0, 0, -1, false), '\n') - matches('Available newer versions:\n• v1%.0%.0\n• v0%.4\n• 0%.3%.1$', confirm_text) + matches('Available newer versions:\n• v1%.0%.0\n• 0%.3%.1$', confirm_text) end) it('updates lockfile', function()