Merge #36585 feat: has() can check multiple Vim versions

This commit is contained in:
Justin M. Keyes
2025-12-03 00:28:53 -05:00
committed by GitHub
10 changed files with 4395 additions and 2490 deletions

View File

@@ -33,7 +33,7 @@ usage() {
echo " -l [git-log opts] List missing Vim patches."
echo " -L [git-log opts] List missing Vim patches (for scripts)."
echo " -m {vim-revision} List previous (older) missing Vim patches."
echo " -M List all merged patch-numbers (at current v:version)."
echo " -M List all merged patch-numbers (since current v:version) in ascending order."
echo " -n List possible N/A Vim patches."
echo " -p {vim-revision} Download and generate a Vim patch. vim-revision"
echo " can be a Vim version (8.1.xxx) or a Git hash."
@@ -570,13 +570,23 @@ list_vimpatch_tokens() {
| sed -nEe 's/^(vim-patch:([0-9]+\.[^ ]+|[0-9a-z]{7,7})).*/\1/p'
}
# Prints all patch-numbers (for the current v:version) for which there is
# a "vim-patch:xxx" token in the Nvim git log.
# Prints all merged patches (since current v:version) in ascending order.
#
# Search "vim-patch:xxx" tokens in the Nvim git log.
# Ignore tokens older than current v:version.
# Left-pad the patch number of "vim-patch:xxx" for stable sort + dedupe.
# Filter reverted Vim tokens.
list_vimpatch_numbers() {
# Transform "vim-patch:X.Y.ZZZZ" to "ZZZZ".
list_vimpatch_tokens | while read -r vimpatch_token; do
echo "$vimpatch_token" | grep -F '8.1.' | sed -Ee 's/.*vim-patch:8\.1\.([0-9a-z]+).*/\1/'
done
local patch_pat='(8\.[12]|9\.[0-9])\.[0-9]{1,4}'
diff "${NVIM_SOURCE_DIR}/scripts/vimpatch_token_reverts.txt" <(
git -C "${NVIM_SOURCE_DIR}" log --format="%s%n%b" -E --grep="^[* ]*vim-patch:${patch_pat}" |
grep -oE "^[* ]*vim-patch:${patch_pat}" |
sed -nEe 's/^[* ]*vim-patch:('"${patch_pat}"').*$/\1/p' |
awk '{split($0, a, "."); printf "%d.%d.%04d\n", a[1], a[2], a[3]}' |
sort |
uniq ) |
grep -e '^> ' |
sed -e 's/^> //'
}
declare -A tokens

View File

@@ -15,48 +15,109 @@ local function systemlist(...)
return rv
end
local function vimpatch_sh_list_numbers()
local function vimpatch_sh_list_tokens()
return systemlist({ { 'bash', '-c', 'scripts/vim-patch.sh -M' } })
end
-- Generates the lines to be inserted into the src/version.c
-- `included_patches[]` definition.
-- Generate the data,lines to update src/nvim/version.c.
-- - `vim_versions[]`
-- - `Versions[]`
-- - `num_patches[]`
-- - `included_patchsets[]`
local function gen_version_c_lines()
-- Set of merged Vim 8.1.zzzz patch numbers.
local merged_patch_numbers = {}
local highest = 0
for _, n in ipairs(vimpatch_sh_list_numbers()) do
n = tonumber(n)
-- List of version sets where each set contains:
-- 1. major_minor_version (int)
-- 2. major_minor_version (string)
-- 3. set of merged patch numbers
local merged_version_list = {}
for _, token in ipairs(vimpatch_sh_list_tokens()) do
local major_version, minor_version, patch_num = string.match(token, '^(%d+).(%d+).(%d+)$')
local n = tonumber(patch_num)
if n then
merged_patch_numbers[n] = true
highest = math.max(highest, n)
local major_minor_version = major_version * 100 + minor_version
local len = #merged_version_list
if len == 0 or merged_version_list[len][1] ~= major_minor_version then
local vstr = '"' .. major_version .. '.' .. minor_version .. '"'
table.insert(merged_version_list, { major_minor_version, vstr, { n } })
else
table.insert(merged_version_list[len][3], n)
end
end
end
local lines = {}
for i = highest, 0, -1 do
local is_merged = (nil ~= merged_patch_numbers[i])
if is_merged then
table.insert(lines, string.format(' %s,', i))
else
table.insert(lines, string.format(' // %s,', i))
local major_vim_versions = {}
local major_vim_versions_str = {}
local num_patches = {}
local patch_lines = {}
for _, version_set in ipairs(merged_version_list) do
local major_minor_version, major_minor_version_str, patch_set = unpack(version_set)
table.insert(major_vim_versions, major_minor_version)
table.insert(major_vim_versions_str, major_minor_version_str)
table.insert(num_patches, #patch_set)
table.insert(patch_lines, ' (const int[]) { // ' .. major_minor_version)
local patchset_set = {}
for i = #patch_set, 1, -1 do
local patch = patch_set[i]
local next_patch = patch_set[i - 1]
local patch_diff = patch - (next_patch or 0)
table.insert(patchset_set, patch)
-- guard against last patch or `make formatc`
if #patchset_set > 15 or i == 1 or patch_diff > 1 then
table.insert(patch_lines, ' ' .. table.concat(patchset_set, ', ') .. ',')
patchset_set = {}
end
if i == 1 and patch > 0 then
local line = ' // 0'
if patch > 1 then
line = line .. '-' .. (patch - 1)
end
table.insert(patch_lines, line)
elseif patch_diff > 1 then
local line = ' // ' .. (next_patch + 1)
if patch_diff > 2 then
line = line .. '-' .. (patch - 1)
end
table.insert(patch_lines, line)
end
end
table.insert(patch_lines, ' },')
end
return lines
return major_vim_versions, major_vim_versions_str, num_patches, patch_lines
end
local function patch_version_c()
local lines = gen_version_c_lines()
local major_vim_versions, major_vim_versions_str, num_patches, patch_lines = gen_version_c_lines()
nvim.nvim_command('silent noswapfile noautocmd edit src/nvim/version.c')
nvim.nvim_command('/static const int included_patches')
nvim.nvim_command([[/^char \*Versions]])
-- Replace the line.
nvim.nvim_call_function('setline', {
nvim.nvim_eval('line(".")'),
'char *Versions[] = { ' .. table.concat(major_vim_versions_str, ', ') .. ' };',
})
nvim.nvim_command([[/^static const int vim_versions]])
-- Replace the line.
nvim.nvim_call_function('setline', {
nvim.nvim_eval('line(".")'),
'static const int vim_versions[] = { ' .. table.concat(major_vim_versions, ', ') .. ' };',
})
nvim.nvim_command([[/^static const int num_patches]])
-- Replace the line.
nvim.nvim_call_function('setline', {
nvim.nvim_eval('line(".")'),
'static const int num_patches[] = { ' .. table.concat(num_patches, ', ') .. ' };',
})
nvim.nvim_command([[/^static const int \*included_patchsets]])
-- Delete the existing lines.
nvim.nvim_command('silent normal! j0d/};\rk')
-- Insert the lines.
nvim.nvim_call_function('append', {
nvim.nvim_eval('line(".")'),
lines,
patch_lines,
})
nvim.nvim_command('silent write')
end

View File

@@ -0,0 +1,3 @@
8.1.2294
9.1.0055
9.2.1731

View File

@@ -3800,14 +3800,15 @@ static int chk_modeline(linenr_T lnum, int flags)
continue;
}
const int vim_version = min_vim_version();
if (*e == ':'
&& (s[0] != 'V'
|| strncmp(skipwhite(e + 1), "set", 3) == 0)
&& (s[3] == ':'
|| (VIM_VERSION_100 >= vers && isdigit((uint8_t)s[3]))
|| (VIM_VERSION_100 < vers && s[3] == '<')
|| (VIM_VERSION_100 > vers && s[3] == '>')
|| (VIM_VERSION_100 == vers && s[3] == '='))) {
|| (vim_version >= vers && isdigit((uint8_t)s[3]))
|| (vim_version < vers && s[3] == '<')
|| (vim_version > vers && s[3] == '>')
|| (vim_version == vers && s[3] == '='))) {
break;
}
}

View File

@@ -2812,14 +2812,10 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int minor = atoi(end + 1);
// Expect "patch-9.9.01234".
n = (major < VIM_VERSION_MAJOR
|| (major == VIM_VERSION_MAJOR
&& (minor < VIM_VERSION_MINOR
|| (minor == VIM_VERSION_MINOR
&& has_vim_patch(atoi(end + 3))))));
n = has_vim_patch(atoi(end + 3), major * 100 + minor);
}
} else if (ascii_isdigit(name[5])) {
n = has_vim_patch(atoi(name + 5));
n = has_vim_patch(atoi(name + 5), 0);
}
} else if (STRNICMP(name, "nvim-", 5) == 0) {
// Expect "nvim-x.y.z"

View File

@@ -281,8 +281,9 @@ void evalvars_init(void)
hash_add(&compat_hashtab, p->vv_di.di_key);
}
}
set_vim_var_nr(VV_VERSION, VIM_VERSION_100);
set_vim_var_nr(VV_VERSIONLONG, VIM_VERSION_100 * 10000 + highest_patch());
const int vim_version = min_vim_version();
set_vim_var_nr(VV_VERSION, vim_version);
set_vim_var_nr(VV_VERSIONLONG, vim_version * 10000 + highest_patch());
dict_T *const msgpack_types_dict = tv_dict_alloc();
for (size_t i = 0; i < ARRAY_SIZE(msgpack_type_names); i++) {

View File

@@ -330,7 +330,7 @@ int ml_open(buf_T *buf)
b0p->b0_magic_int = B0_MAGIC_INT;
b0p->b0_magic_short = (int16_t)B0_MAGIC_SHORT;
b0p->b0_magic_char = B0_MAGIC_CHAR;
xstrlcpy(xstpcpy(b0p->b0_version, "VIM "), Version, 6);
xstrlcpy(xstpcpy(b0p->b0_version, "VIM "), Versions[0], 6);
long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
if (!buf->b_spell) {

File diff suppressed because it is too large Load Diff

View File

@@ -5,26 +5,10 @@
#include "nvim/macros_defs.h"
// defined in version.c
extern char *Version;
extern char *Versions[];
extern char *longVersion;
#ifndef NDEBUG
extern char *version_cflags;
#endif
//
// Vim version number, name, etc. Patchlevel is defined in version.c.
//
// Values that change for a new release
#define VIM_VERSION_MAJOR 8
#define VIM_VERSION_MINOR 1
// Values based on the above
#define VIM_VERSION_MAJOR_STR STR(VIM_VERSION_MAJOR)
#define VIM_VERSION_MINOR_STR STR(VIM_VERSION_MINOR)
#define VIM_VERSION_100 (VIM_VERSION_MAJOR * 100 + VIM_VERSION_MINOR)
// swap file compatibility (max. length is 6 chars)
#define VIM_VERSION_SHORT VIM_VERSION_MAJOR_STR "." VIM_VERSION_MINOR_STR
#include "version.h.generated.h"

View File

@@ -104,4 +104,39 @@ describe('has()', function()
fn.has('python3') -- use a call whose implementation shells out
eq(73, fn.eval('v:shell_error'))
end)
it('"patch[0-9]\\+"', function()
eq(1, fn.has('patch0'))
eq(1, fn.has('patch1'))
end)
it('"patch-x.y.z"', function()
-- versions older than current v:version always succeed
-- unless minor version has 2+ digits
eq(1, fn.has('patch-7.4.0'))
eq(0, fn.has('patch-7.40.0'))
eq(1, fn.has('patch-8.0.0'))
eq(0, fn.has('patch-8.00.0'))
eq(1, fn.has('patch-8.1.0'))
eq(1, fn.has('patch-8.1.1'))
eq(1, fn.has('patch-8.1.0001'))
eq(1, fn.has('patch-8.1.1939'))
eq(1, fn.has('patch-8.1.2424'))
eq(0, fn.has('patch-8.2.0'))
eq(1, fn.has('patch-8.2.1'))
eq(1, fn.has('patch-8.2.2999'))
eq(1, fn.has('patch-8.2.5171'))
eq(0, fn.has('patch-9.0.0'))
eq(1, fn.has('patch-9.0.1'))
eq(1, fn.has('patch-9.0.998'))
eq(1, fn.has('patch-9.0.2190'))
eq(0, fn.has('patch-9.1.0'))
eq(1, fn.has('patch-9.1.1'))
eq(1, fn.has('patch-9.1.690'))
eq(1, fn.has('patch-9.1.1934'))
end)
end)