mirror of
https://github.com/neovim/neovim.git
synced 2026-11-06 05:16:52 +00:00
* build(vim-patch): v9.1.0500 is n/a * build(vim-patch): n/a change in src/po/Make* Nvim uses "TARGET_FILE:nvim_bin" in CMake. * build(vim-patch): runtime/doc/pi_netrw.txt should be n/a Minor differences between netrw docs are not relevant to Neovim. Vim keeps pi_netrw.txt to add/override few lines but it is partly "behind" upstream netrw. - runtime/doc/pi_netrw.txt - runtime/pack/dist/opt/netrw/doc/netrw.txt * build(vim-patch): track ':Tutor' patches ":Tutor" remains maintained based on recent Github issues such that Neovim does not rely on Vim patches to fix its own implementation. Develepor may port Vim patches that fix Vim's implementation of ":Tutor" but Vim and Neovim remain incompatible after Neovim replace metadata JSON files with inline comments, https://github.com/neovim/neovim/issues/38527 . Vim and Neovim are not obligated to restrict their tutor files in order to ensure 100% (backward) compatibility on both editors. Both will use their exclusive and incompatible features to enhance the user experience in ":Tutor". Continue to track ":Tutor" patches to not discourage contributors on both projects. Target 6fa304f27d630f4c11c903a61d434f739230e8e1 . * build(vim-patch): n/a tabpanel changes from v9.1.1391
1144 lines
42 KiB
Bash
Executable File
1144 lines
42 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -e
|
|
set -u
|
|
# Use privileged mode, which e.g. skips using CDPATH.
|
|
set -p
|
|
# https://www.shellcheck.net/wiki/SC2031
|
|
shopt -s lastpipe
|
|
|
|
# Ensure that the user has a bash that supports -A
|
|
if [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then
|
|
>&2 echo "error: script requires bash 4+ (you have ${BASH_VERSION})."
|
|
exit 1
|
|
fi
|
|
|
|
readonly NVIM_SOURCE_DIR="${NVIM_SOURCE_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
readonly VIM_SOURCE_DIR_DEFAULT="${NVIM_SOURCE_DIR}/.vim-src"
|
|
readonly VIM_SOURCE_DIR="${VIM_SOURCE_DIR:-${VIM_SOURCE_DIR_DEFAULT}}"
|
|
BASENAME="$(basename "${0}")"
|
|
readonly BASENAME
|
|
readonly BRANCH_PREFIX="vim-"
|
|
readonly VIMPATCH_RANGE=38fb83585421c45828a4934fc75f7952b2baf116..HEAD
|
|
|
|
CREATED_FILES=()
|
|
|
|
usage() {
|
|
echo "Port Vim patches to Neovim"
|
|
echo "https://neovim.io/doc/user/dev_vimpatch.html"
|
|
echo
|
|
echo "Usage: ${BASENAME} [-h | -l | -p vim-revision | -r pr-number]"
|
|
echo
|
|
echo "Options:"
|
|
echo " -h Show this message and exit."
|
|
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 (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."
|
|
echo " -P {vim-revision} Download, generate and apply a Vim patch."
|
|
echo " -g {vim-revision} Download a Vim patch."
|
|
echo " -s [pr args] Create a vim-patch pull request."
|
|
echo " -r {pr-number} Review a vim-patch pull request."
|
|
echo " -V Clone the Vim source code to \$VIM_SOURCE_DIR."
|
|
echo
|
|
echo " \$VIM_SOURCE_DIR controls where Vim sources are found"
|
|
echo " (default: '${VIM_SOURCE_DIR_DEFAULT}')"
|
|
echo
|
|
echo "Examples:"
|
|
echo
|
|
echo " - List missing patches for a given file (in the Vim source):"
|
|
echo " $0 -l -- src/edit.c"
|
|
}
|
|
|
|
# Run git with inline config to avoid error with developer's .gitconfig.
|
|
_git() {
|
|
local -a git_args
|
|
git_args=("$@")
|
|
git -c log.showSignature=false "${git_args[@]}"
|
|
}
|
|
|
|
msg_ok() {
|
|
printf '\e[32m✔\e[0m %s\n' "$@"
|
|
}
|
|
|
|
msg_err() {
|
|
printf '\e[31m✘\e[0m %s\n' "$@" >&2
|
|
}
|
|
|
|
# Checks if a program is in the user's PATH, and is executable.
|
|
check_executable() {
|
|
test -x "$(command -v "${1}")"
|
|
}
|
|
|
|
require_executable() {
|
|
if ! check_executable "${1}"; then
|
|
>&2 echo "${BASENAME}: '${1}' not found in PATH or not executable."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
clean_files() {
|
|
if [[ ${#CREATED_FILES[@]} -eq 0 ]]; then
|
|
return
|
|
fi
|
|
|
|
echo
|
|
echo "Created files:"
|
|
local file
|
|
for file in "${CREATED_FILES[@]}"; do
|
|
echo " • ${file}"
|
|
done
|
|
|
|
read -p "Delete these files (Y/n)? " -n 1 -r reply
|
|
echo
|
|
if [[ "${reply}" == n ]]; then
|
|
echo "You can use 'git clean' to remove these files when you're done."
|
|
else
|
|
rm -- "${CREATED_FILES[@]}"
|
|
fi
|
|
}
|
|
|
|
get_vim_sources() {
|
|
require_executable git
|
|
|
|
if [[ ! -d ${VIM_SOURCE_DIR} ]]; then
|
|
echo "Cloning Vim into: ${VIM_SOURCE_DIR}"
|
|
git clone https://github.com/vim/vim.git "${VIM_SOURCE_DIR}"
|
|
cd "${VIM_SOURCE_DIR}"
|
|
elif [[ "${1-}" == update ]]; then
|
|
cd "${VIM_SOURCE_DIR}"
|
|
if ! [ -d ".git" ] \
|
|
&& ! [ "$(git rev-parse --show-toplevel)" = "${VIM_SOURCE_DIR}" ]; then
|
|
msg_err "${VIM_SOURCE_DIR} does not appear to be a git repository."
|
|
echo " Please remove it and try again."
|
|
exit 1
|
|
fi
|
|
echo "Updating Vim sources: ${VIM_SOURCE_DIR}"
|
|
if git pull --ff; then
|
|
msg_ok "Updated Vim sources."
|
|
else
|
|
msg_err "Could not update Vim sources; ignoring error."
|
|
fi
|
|
else
|
|
cd "${VIM_SOURCE_DIR}"
|
|
fi
|
|
}
|
|
|
|
commit_message() {
|
|
if [[ "${vim_message}" == "vim-patch:${vim_version}:"* ]]; then
|
|
printf '%s\n\n%s\n\n%s' "${vim_message}" "${vim_commit_url}" "${vim_coauthors}"
|
|
else
|
|
printf 'vim-patch:%s: %s\n\n%s\n\n%s' "${vim_version:0:7}" "${vim_message}" "${vim_commit_url}" "${vim_coauthors}"
|
|
fi
|
|
}
|
|
|
|
find_git_remote() {
|
|
local git_remote
|
|
if [[ "${1-}" == fork ]]; then
|
|
git_remote=$(git remote -v | awk '$2 !~ /github.com[:\/]neovim\/neovim/ && $3 == "(fetch)" {print $1; exit}')
|
|
else
|
|
git_remote=$(git remote -v | awk '$2 ~ /github.com[:\/]neovim\/neovim/ && $3 == "(fetch)" {print $1; exit}')
|
|
fi
|
|
if [[ -z "$git_remote" ]]; then
|
|
git_remote="origin"
|
|
fi
|
|
echo "$git_remote"
|
|
}
|
|
|
|
# Assign variables for a given Vim tag, patch version, or commit.
|
|
# Might exit in case it cannot be found, after updating Vim sources.
|
|
assign_commit_details() {
|
|
local vim_commit_ref
|
|
if [[ ${1} =~ v?[0-9]\.[0-9]\.[0-9]{3,4} ]]; then
|
|
# Interpret parameter as version number (tag).
|
|
if [[ "${1:0:1}" == v ]]; then
|
|
vim_version="${1:1}"
|
|
vim_tag="${1}"
|
|
else
|
|
vim_version="${1}"
|
|
vim_tag="v${1}"
|
|
fi
|
|
vim_commit_ref="$vim_tag"
|
|
local munge_commit_line=true
|
|
else
|
|
# Interpret parameter as commit hash.
|
|
vim_version="${1:0:7}"
|
|
vim_tag=
|
|
vim_commit_ref="$vim_version"
|
|
local munge_commit_line=false
|
|
fi
|
|
|
|
local get_vim_commit_cmd="_git -C ${VIM_SOURCE_DIR} log -1 --format=%H ${vim_commit_ref} --"
|
|
vim_commit=$($get_vim_commit_cmd 2>&1) || {
|
|
# Update Vim sources.
|
|
get_vim_sources update
|
|
vim_commit=$($get_vim_commit_cmd 2>&1) || {
|
|
>&2 msg_err "Couldn't find Vim revision '${vim_commit_ref}': git error: ${vim_commit}."
|
|
exit 3
|
|
}
|
|
}
|
|
|
|
vim_commit_url="https://github.com/vim/vim/commit/${vim_commit}"
|
|
vim_message="$(_git -C "${VIM_SOURCE_DIR}" log -1 --pretty='format:%B' "${vim_commit}" \
|
|
| sed -Ee 's/([^A-Za-z0-9])(#[0-9]{1,})/\1vim\/vim\2/g')"
|
|
local vim_coauthor0
|
|
vim_coauthor0="$(_git -C "${VIM_SOURCE_DIR}" log -1 --pretty='format:Co-authored-by: %an <%ae>' "${vim_commit}")"
|
|
# Extract co-authors from the commit message.
|
|
vim_coauthors="$(echo "${vim_message}" | (grep -E '^Co-[Aa]uthored-[Bb]y: ' || true) | (grep -Fxv "${vim_coauthor0}" || true))"
|
|
vim_coauthors="$(echo "${vim_coauthor0}"; echo "${vim_coauthors}")"
|
|
# Upstream may credit an AI tool; we don't advertise those, see AGENTS.md.
|
|
vim_coauthors="$(echo "${vim_coauthors}" \
|
|
| (grep -Eiv '^Co-authored-by: .*(aider|anthropic|chatgpt|claude|codex|copilot|cursor|devin|gemini|openai|opencode|windsurf)' || true))"
|
|
# Remove Co-authored-by and Signed-off-by lines from the commit message.
|
|
vim_message="$(echo "${vim_message}" | grep -Ev '^(Co-[Aa]uthored|Signed-[Oo]ff)-[Bb]y: ')"
|
|
if [[ ${munge_commit_line} == "true" ]]; then
|
|
# Remove first line of commit message.
|
|
vim_message="$(echo "${vim_message}" | sed -Ee '1s/^patch /vim-patch:/')"
|
|
fi
|
|
patch_file="vim-${vim_version}.patch"
|
|
}
|
|
|
|
# Patch surgery
|
|
preprocess_patch() {
|
|
local file="$1"
|
|
local nvim="nvim -u NONE -n -i NONE --headless"
|
|
|
|
# Remove Filelist, README
|
|
local na_files='Filelist\|README.*'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/\<\%('"${na_files}"'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Remove *.proto, Make*, INSTALL*, gui_*, beval.*, some if_*, gvim, libvterm, tee, VisVim, xpm, xxd
|
|
local na_src='auto\|configure.*\|GvimExt\|hardcopy.*\|libvterm\|proto\|tee\|VisVim\|xpm\|xxd\|Make.*\|INSTALL.*\|beval.*\|gui.*\|if_cscop\|if_lua\|if_mzsch\|if_olepp\|if_ole\|if_perl\|if_py\|if_ruby\|if_tcl\|if_xcmdsrv'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/src/\S*\<\%(testdir/\)\@<!\%('"${na_src}"'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Remove runtime/print/
|
|
local na_rt='print\/.*'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/runtime/\<\%('"${na_rt}"'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Remove unwanted Vim doc files.
|
|
local na_doc='channel\.txt\|if_cscop\.txt\|netbeans\.txt\|os_\w\+\.txt\|print\.txt\|term\.txt\|testing\.txt\|todo\.txt\|vim9\.txt\|tags\|test_urls\.vim'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/runtime/doc/\<\%('"${na_doc}"'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Remove "Last change ..." changes in doc files.
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'%s/^@@.*\n.*For Vim version.*Last change.*\n.*For Vim version.*Last change.*//' +w +q "$file"
|
|
|
|
# Remove gui, setup, screen dumps, testdir/Make_*.mak files
|
|
local na_src_testdir='gui_.*\|Make_amiga\.mak\|Make_dos\.mak\|Make_ming\.mak\|Make_vms\.mms\|dumps/.*\.dump\|setup_gui\.vim'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/src/testdir/\<\%('"${na_src_testdir}"'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Remove testdir/test_*.vim files
|
|
local na_src_testdir='balloon.*\|behave\.vim\|channel.*\|crypt\.vim\|cscope\.vim\|hardcopy\.vim\|job_fails\.vim\|json\.vim\|listener\.vim\|mzscheme\.vim\|netbeans.*\|paste\.vim\|popupwin.*\|python2\.vim\|pyx2\.vim\|restricted\.vim\|shortpathname\.vim\|sound\.vim\|tcl\.vim\|terminal.*\|xxd\.vim'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/src/testdir/\<test_\%('"${na_src_testdir}"'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Remove runtime/*/testdir/ files
|
|
local na_runtime_testdir='.\+'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/runtime/\f\+/testdir/\%('${na_runtime_testdir}'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Remove N/A src/*.[ch] files: sound.c, version.c
|
|
local na_src_c='sound\|version'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/src/\<\%('"${na_src_c}"'\)\.[ch]\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Remove some *.po files. #5622
|
|
# Also remove vim.pot which is updated on almost every source change.
|
|
local na_po='sjiscorr\.c\|ja\.sjis\.po\|ko\.po\|pl\.cp1250\.po\|pl\.po\|ru\.cp1251\.po\|uk\.cp1251\.po\|zh_CN\.cp936\.po\|zh_CN\.po\|zh_TW\.po\|vim\.pot'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/src/po/\<\%('${na_po}'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Remove vimrc_example.vim
|
|
local na_vimrcexample='vimrc_example\.vim'
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git [ab]/runtime/\<\%('${na_vimrcexample}'\)\>@exe "norm! d/\\v(^diff)|%$\r"' +w +q "$file"
|
|
|
|
# Rename src/testdir/ paths to test/old/testdir/
|
|
LC_ALL=C sed -Ee 's/( [ab])\/src\/testdir/\1\/test\/old\/testdir/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename src/ paths to src/nvim/
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src)/\1\/nvim/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename evalfunc.c to eval/funcs.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/evalfunc\.c/\1\/eval\/funcs.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename list.c to eval/list.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/list\.c/\1\/eval\/list.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename evalvars.c to eval/vars.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/evalvars\.c/\1\/eval\/vars.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename userfunc.c to eval/userfunc.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/userfunc\.c/\1\/eval\/userfunc.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename evalbuffer.c to eval/buffer.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/evalbuffer\.c/\1\/eval\/buffer.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename evalwindow.c to eval/window.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/evalwindow\.c/\1\/eval\/window.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename cindent.c to indent_c.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/cindent\.c/\1\/indent_c.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename map.c to mapping.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/map\.c/\1\/mapping.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename getchar.c to input.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/getchar\.c/\1\/input.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename edit.c to insert.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/edit\.c/\1\/insert.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename profiler.c to profile.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/profiler\.c/\1\/profile.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename regexp_(bt|nfa).c to regexp.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/regexp_(bt|nfa)\.c/\1\/regexp.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename scriptfile.c to runtime.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/scriptfile\.c/\1\/runtime.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename session.c to ex_session.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/session\.c/\1\/ex_session.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename highlight.c to highlight_group.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/highlight\.c/\1\/highlight_group.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename locale.c to os/lang.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/locale\.c/\1\/os\/lang.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename keymap.h to keycodes.h
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/keymap\.h/\1\/keycodes.h/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename term.c to keycodes.c
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/term\.c/\1\/keycodes.c/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename option.h to option_vars.h
|
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/option\.h/\1\/option_vars.h/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename runtime/doc/eval.txt to runtime/doc/vimeval.txt
|
|
LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/eval\.txt/\1\/vimeval.txt/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename <lang>.txt to l10n-<lang>.txt
|
|
LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/(arabic|hebrew|russian|vietnamese)\.txt/\1\/l10n-\2.txt/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename version*.txt to news.txt
|
|
LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/version[0-9]+\.txt/\1\/news.txt/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename sponsor.txt to intro.txt
|
|
LC_ALL=C sed -Ee 's/( [ab]\/runtime\/doc)\/sponsor\.txt/\1\/intro.txt/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
|
|
# Rename path to check_colors.vim
|
|
LC_ALL=C sed -Ee 's/( [ab]\/runtime)\/colors\/(tools\/check_colors\.vim)/\1\/\2/g' \
|
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
|
}
|
|
|
|
uncrustify_patch() {
|
|
git diff --quiet || {
|
|
>&2 echo 'Vim source working tree dirty, aborting.'
|
|
exit 1
|
|
}
|
|
|
|
local patch_path="$NVIM_SOURCE_DIR"/build/vim_patch
|
|
rm -rf "$patch_path"
|
|
mkdir -p "$patch_path"/{a,b}
|
|
|
|
local commit="$1"
|
|
for file in $(git diff-tree --name-only --no-commit-id -r --diff-filter=a "$commit"); do
|
|
git --work-tree="$patch_path"/a checkout --quiet "$commit"~ -- "$file"
|
|
done
|
|
for file in $(git diff-tree --name-only --no-commit-id -r --diff-filter=d "$commit"); do
|
|
git --work-tree="$patch_path"/b checkout --quiet "$commit" -- "$file"
|
|
done
|
|
git reset --quiet --hard HEAD
|
|
|
|
# If the difference are drastic enough uncrustify may need to be used more
|
|
# than once. This is obviously a bug that needs to be fixed on uncrustify's
|
|
# end, but in the meantime this workaround is sufficient.
|
|
for _ in {1..2}; do
|
|
"$NVIM_SOURCE_DIR"/build/usr/bin/uncrustify -c "$NVIM_SOURCE_DIR"/src/uncrustify.cfg -q --replace --no-backup "$patch_path"/{a,b}/src/*.[ch]
|
|
done
|
|
|
|
(cd "$patch_path" && (git --no-pager diff --no-index --no-prefix --patch --unified=5 --color=never a/ b/ || true))
|
|
}
|
|
|
|
get_vimpatch() {
|
|
get_vim_sources
|
|
|
|
assign_commit_details "${1}"
|
|
|
|
msg_ok "Found Vim revision '${vim_commit}'."
|
|
|
|
local patch_content
|
|
if check_executable "$NVIM_SOURCE_DIR"/build/usr/bin/uncrustify; then
|
|
patch_content="$(uncrustify_patch "${vim_commit}")"
|
|
else
|
|
patch_content="$(git --no-pager show --unified=5 --color=never -1 --pretty=medium "${vim_commit}")"
|
|
fi
|
|
|
|
cd "${NVIM_SOURCE_DIR}"
|
|
|
|
printf "Creating patch...\n"
|
|
echo "$patch_content" > "${NVIM_SOURCE_DIR}/${patch_file}"
|
|
|
|
printf "Pre-processing patch...\n"
|
|
preprocess_patch "${NVIM_SOURCE_DIR}/${patch_file}"
|
|
|
|
msg_ok "Saved patch to '${NVIM_SOURCE_DIR}/${patch_file}'."
|
|
}
|
|
|
|
stage_patch() {
|
|
get_vimpatch "$1"
|
|
local try_apply="${2:-}"
|
|
|
|
local nvim_remote
|
|
nvim_remote="$(find_git_remote)"
|
|
local checked_out_branch
|
|
checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
|
|
|
|
if [[ "${checked_out_branch}" == ${BRANCH_PREFIX}* ]]; then
|
|
msg_ok "Current branch '${checked_out_branch}' seems to be a vim-patch"
|
|
echo " branch; not creating a new branch."
|
|
else
|
|
printf '\nFetching "%s/master".\n' "${nvim_remote}"
|
|
if output="$(git fetch "$nvim_remote" master 2>&1)"; then
|
|
msg_ok "$output"
|
|
else
|
|
msg_err "$output"
|
|
exit 1
|
|
fi
|
|
|
|
local nvim_branch="${BRANCH_PREFIX}${vim_version}"
|
|
echo
|
|
echo "Creating new branch '${nvim_branch}' based on '${nvim_remote}/master'."
|
|
cd "${NVIM_SOURCE_DIR}"
|
|
if output="$(git checkout -b "$nvim_branch" "$nvim_remote/master" 2>&1)"; then
|
|
msg_ok "$output"
|
|
else
|
|
msg_err "$output"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
printf "\nCreating empty commit with correct commit message.\n"
|
|
if output="$(commit_message | git commit --allow-empty --file 2>&1 -)"; then
|
|
msg_ok "$output"
|
|
else
|
|
msg_err "$output"
|
|
exit 1
|
|
fi
|
|
|
|
local ret=0
|
|
if test -n "$try_apply" ; then
|
|
if ! check_executable patch; then
|
|
printf "\n"
|
|
msg_err "'patch' command not found\n"
|
|
else
|
|
printf "\nApplying patch...\n"
|
|
patch -p1 --fuzz=1 --no-backup-if-mismatch < "${patch_file}" || ret=$?
|
|
fi
|
|
printf "\nInstructions:\n Proceed to port the patch.\n"
|
|
else
|
|
printf '\nInstructions:\n Proceed to port the patch.\n Try the "patch" command (or use "%s -P ..." next time):\n patch -p1 < %s\n' "${BASENAME}" "${patch_file}"
|
|
fi
|
|
|
|
printf '
|
|
Stage your changes ("git add ..."), then use "git commit --amend" to commit.
|
|
|
|
To port more patches (if any) related to %s,
|
|
run "%s" again.
|
|
* Do this only for _related_ patches (otherwise it increases the
|
|
size of the pull request, making it harder to review)
|
|
|
|
When you are done, try "%s -s" to create the pull request,
|
|
or "%s -s --draft" to create a draft pull request.
|
|
|
|
See the wiki for more information:
|
|
* https://neovim.io/doc/user/dev_vimpatch.html
|
|
' "${vim_version}" "${BASENAME}" "${BASENAME}" "${BASENAME}"
|
|
return $ret
|
|
}
|
|
|
|
gh_pr() {
|
|
local pr_title
|
|
local pr_body
|
|
pr_title="$1"
|
|
pr_body="$2"
|
|
shift 2
|
|
gh pr create --title "${pr_title}" --body "${pr_body}" "$@"
|
|
}
|
|
|
|
git_hub_pr() {
|
|
local pr_message
|
|
pr_message="$(printf '%s\n\n%s\n' "$1" "$2")"
|
|
shift 2
|
|
git hub pull new -m "${pr_message}" "$@"
|
|
}
|
|
|
|
submit_pr() {
|
|
require_executable git
|
|
local push_first
|
|
push_first=1
|
|
local submit_fn
|
|
if check_executable gh; then
|
|
submit_fn="gh_pr"
|
|
elif check_executable git-hub; then
|
|
push_first=0
|
|
submit_fn="git_hub_pr"
|
|
else
|
|
>&2 echo "${BASENAME}: 'gh' or 'git-hub' not found in PATH or not executable."
|
|
>&2 echo " Get it here: https://cli.github.com/"
|
|
exit 1
|
|
fi
|
|
|
|
cd "${NVIM_SOURCE_DIR}"
|
|
local checked_out_branch
|
|
checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
|
|
if [[ "${checked_out_branch}" != ${BRANCH_PREFIX}* ]]; then
|
|
msg_err "Current branch '${checked_out_branch}' doesn't seem to be a vim-patch branch."
|
|
exit 1
|
|
fi
|
|
|
|
local nvim_remote
|
|
nvim_remote="$(find_git_remote)"
|
|
local pr_body
|
|
pr_body="$(_git log --grep=vim-patch --reverse --format='#### %s%n%n%b%n' "${nvim_remote}"/master..HEAD)"
|
|
local patches
|
|
# Extract just the "vim-patch:X.Y.ZZZZ" or "vim-patch:sha" portion of each log
|
|
patches=("$(_git log --grep=vim-patch --reverse --format='%s' "${nvim_remote}"/master..HEAD | sed 's/: .*//')")
|
|
# shellcheck disable=SC2206
|
|
patches=(${patches[@]//vim-patch:}) # Remove 'vim-patch:' prefix for each item in array.
|
|
local pr_title="${patches[*]}" # Create space-separated string from array.
|
|
pr_title="${pr_title// /,}" # Replace spaces with commas.
|
|
pr_title="$(printf 'vim-patch:%s' "${pr_title#,}")"
|
|
|
|
if [[ $push_first -ne 0 ]]; then
|
|
local push_remote
|
|
push_remote="$(git config --get branch."${checked_out_branch}".pushRemote || true)"
|
|
if [[ -z "$push_remote" ]]; then
|
|
push_remote="$(git config --get remote.pushDefault || true)"
|
|
if [[ -z "$push_remote" ]]; then
|
|
push_remote="$(git config --get branch."${checked_out_branch}".remote || true)"
|
|
if [[ -z "$push_remote" ]] || [[ "$push_remote" == "$nvim_remote" ]]; then
|
|
push_remote="$(find_git_remote fork)"
|
|
fi
|
|
fi
|
|
fi
|
|
echo "Pushing to '${push_remote}/${checked_out_branch}'."
|
|
if output="$(git push "$push_remote" "$checked_out_branch" 2>&1)"; then
|
|
msg_ok "$output"
|
|
else
|
|
msg_err "$output"
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
fi
|
|
|
|
echo "Creating pull request."
|
|
if output="$($submit_fn "$pr_title" "$pr_body" "$@" 2>&1)"; then
|
|
msg_ok "$output"
|
|
else
|
|
msg_err "$output"
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "Cleaning up files."
|
|
local patch_file
|
|
for patch_file in "${patches[@]}"; do
|
|
patch_file="vim-${patch_file}.patch"
|
|
if [[ ! -f "${NVIM_SOURCE_DIR}/${patch_file}" ]]; then
|
|
continue
|
|
fi
|
|
rm -- "${NVIM_SOURCE_DIR}/${patch_file}"
|
|
msg_ok "Removed '${NVIM_SOURCE_DIR}/${patch_file}'."
|
|
done
|
|
}
|
|
|
|
# Prints all (sorted) "vim-patch:xxx" tokens found in the Nvim git log
|
|
# where xxx is Git commit hash, not X.Y.Z version
|
|
list_vimpatch_hashes() {
|
|
local patch_pat='[a-z0-9]{7,}'
|
|
# Use sed…{7,7} to normalize (internal) Git hashes (for tokens caches).
|
|
diff "${NVIM_SOURCE_DIR}/scripts/vimpatch_commit_ignore.txt" <(
|
|
_git -C "${NVIM_SOURCE_DIR}" log --format="%H" -E --grep="vim-patch:$patch_pat" "$VIMPATCH_RANGE"
|
|
) |
|
|
grep -e '^> ' |
|
|
sed -e 's/^> //' |
|
|
_git -C "${NVIM_SOURCE_DIR}" log --no-walk --stdin \
|
|
| grep -oE "vim-patch:$patch_pat" \
|
|
| grep -v "vim-patch:partial" |
|
|
sed -nEe "s/^vim-patch:($patch_pat).*/\1/p" |
|
|
sort |
|
|
uniq
|
|
}
|
|
|
|
# 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() {
|
|
local patch_pat='(8\.[12]|9\.[0-9])\.[0-9]{1,4}'
|
|
diff "${NVIM_SOURCE_DIR}/scripts/vimpatch_commit_ignore.txt" <(
|
|
_git -C "${NVIM_SOURCE_DIR}" log --format="%H" -E --grep="^[* ]*vim-patch:${patch_pat}" "$VIMPATCH_RANGE"
|
|
) |
|
|
grep -e '^> ' |
|
|
sed -e 's/^> //' |
|
|
_git -C "${NVIM_SOURCE_DIR}" log --no-walk --stdin --format="%s%n%b" |
|
|
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
|
|
}
|
|
|
|
# Prints a newline-delimited list of Vim commits, for use by scripts.
|
|
# "$1": use extended format? (with subject)
|
|
# "$@": extra arguments to git-log.
|
|
list_missing_vimpatches() {
|
|
local VIM_VERSION_0_DATE git_log_format missing_hashes missing_numbers
|
|
declare -a git_log_args
|
|
VIM_VERSION_0_DATE=2018-05-17:15:00:00Z
|
|
|
|
local extended_format=$1; shift
|
|
|
|
# XXX(@janlazo): Delimiter "%x00" required to detect tagged commits
|
|
# https://git-scm.com/docs/git-log#Documentation/git-log.txt-x00
|
|
if [[ "$extended_format" == 1 ]]; then
|
|
git_log_format="%H%x00%d%x00: %s"
|
|
else
|
|
git_log_format="%H%x00%(decorate:prefix=,suffix=,tag=)"
|
|
fi
|
|
|
|
# Massage arguments for git-log.
|
|
declare -A git_log_replacements=(
|
|
[^\(.*/\)?src/nvim/\(.*\)]="\${BASH_REMATCH[1]}src/\${BASH_REMATCH[2]}"
|
|
[^\(.*/\)?test/old/\(.*\)]="\${BASH_REMATCH[1]}src/\${BASH_REMATCH[2]}"
|
|
[^\(.*/\)?\.vim-src/\(.*\)]="\${BASH_REMATCH[2]}"
|
|
)
|
|
local i j
|
|
for i in "$@"; do
|
|
for j in "${!git_log_replacements[@]}"; do
|
|
if [[ "$i" =~ $j ]]; then
|
|
eval "git_log_args+=(${git_log_replacements[$j]})"
|
|
continue 2
|
|
fi
|
|
done
|
|
git_log_args+=("$i")
|
|
done
|
|
|
|
missing_numbers=$(_git -C "${VIM_SOURCE_DIR}" log --decorate-refs='refs/tags/*' --reverse --since="${VIM_VERSION_0_DATE}" --no-walk --tags --format='%(decorate:prefix=,suffix=,tag=)' |
|
|
grep -v -F -f <(list_vimpatch_numbers) |
|
|
grep -oE 'v[0-9]+\.[0-9]+\.[0-9]{4}')
|
|
missing_hashes=$(_git -C "${VIM_SOURCE_DIR}" log --decorate-refs='refs/tags/*' --reverse --since="${VIM_VERSION_0_DATE}" --format='%H%D' |
|
|
grep -v -e 'tag:' |
|
|
grep -v -f <(list_vimpatch_hashes | sed -E 's/(.*)/^\1/'))
|
|
(echo "${missing_numbers}"; echo "${missing_hashes}") |
|
|
_git --no-pager -C "${VIM_SOURCE_DIR}" log --decorate-refs='refs/tags/*' --reverse --no-walk --stdin --format="${git_log_format}" "${git_log_args[@]}" |
|
|
awk -F '\0' '{ print $2 ? $2$3 : $1$3 }'
|
|
}
|
|
|
|
# Prints a human-formatted list of Vim commits, with instructional messages.
|
|
# Passes "$@" onto list_missing_vimpatches (args for git-log).
|
|
show_vimpatches() {
|
|
get_vim_sources update
|
|
printf "Vim patches missing from Neovim:\n"
|
|
|
|
local -A runtime_commits
|
|
for commit in $(_git -C "${VIM_SOURCE_DIR}" log --format="%H %D" -- runtime | sed -Ee 's/,\? tag: / /g'); do
|
|
runtime_commits[$commit]=1
|
|
done
|
|
|
|
list_missing_vimpatches 1 "$@" | while read -r vim_commit; do
|
|
if [[ "${runtime_commits[$vim_commit]-}" ]]; then
|
|
printf ' • %s (+runtime)\n' "${vim_commit}"
|
|
else
|
|
printf ' • %s\n' "${vim_commit}"
|
|
fi
|
|
done
|
|
|
|
cat << EOF
|
|
|
|
Instructions:
|
|
To port one of the above patches to Neovim, execute this script with the patch revision as argument and follow the instructions, e.g.
|
|
'${BASENAME} -p v8.1.1234', or '${BASENAME} -P v8.1.1234'
|
|
|
|
NOTE: Please port the _oldest_ patch if you possibly can.
|
|
You can use '${BASENAME} -l path/to/file' to see what patches are missing for a file.
|
|
EOF
|
|
}
|
|
|
|
list_missing_previous_vimpatches_for_patch() {
|
|
local for_vim_patch="${1}"
|
|
local vim_commit vim_tag
|
|
assign_commit_details "${for_vim_patch}"
|
|
|
|
local file
|
|
local -a missing_list
|
|
local -a fnames
|
|
while IFS= read -r line ; do
|
|
fnames+=("$line")
|
|
done < <(git -C "${VIM_SOURCE_DIR}" diff-tree --no-commit-id --name-only -r "${vim_commit}" -- . ':!src/version.c')
|
|
local i=0
|
|
local n=${#fnames[@]}
|
|
printf '=== getting missing patches for %d files ===\n' "$n"
|
|
if [[ -z "${vim_tag}" ]]; then
|
|
printf 'NOTE: "%s" is not a Vim tag - listing all oldest missing patches\n' "${for_vim_patch}" >&2
|
|
fi
|
|
for fname in "${fnames[@]}"; do
|
|
i=$(( i+1 ))
|
|
printf '[%.*d/%d] %s: ' "${#n}" "$i" "$n" "$fname"
|
|
|
|
list_missing_vimpatches 1 -- "${fname}" | while read -r missing_vim_commit_info; do
|
|
if [[ -z "${missing_vim_commit_info}" ]]; then
|
|
printf -- "-\r"
|
|
else
|
|
printf -- "-\r"
|
|
local missing_vim_commit="${missing_vim_commit_info%%:*}"
|
|
if [[ -z "${vim_tag}" ]] || [[ "${missing_vim_commit}" < "${vim_tag}" ]]; then
|
|
printf -- "%s\n" "$missing_vim_commit_info"
|
|
missing_list+=("$missing_vim_commit_info")
|
|
else
|
|
printf -- "-\r"
|
|
fi
|
|
fi
|
|
done
|
|
done
|
|
|
|
set +u # Avoid "unbound variable" with bash < 4.4 below.
|
|
if [[ -z "${missing_list[*]}" ]]; then
|
|
msg_ok 'no missing previous Vim patches'
|
|
set -u
|
|
return 0
|
|
fi
|
|
set -u
|
|
|
|
local -a missing_unique
|
|
local stat
|
|
while IFS= read -r line; do
|
|
local commit="${line%%:*}"
|
|
stat="$(git -C "${VIM_SOURCE_DIR}" show --format= --shortstat "${commit}")"
|
|
missing_unique+=("$(printf '%s\n %s' "$line" "$stat")")
|
|
done < <(printf '%s\n' "${missing_list[@]}" | sort -u)
|
|
|
|
msg_err "$(printf '%d missing previous Vim patches:' ${#missing_unique[@]})"
|
|
printf ' - %s\n' "${missing_unique[@]}"
|
|
return 1
|
|
}
|
|
|
|
review_commit() {
|
|
local nvim_commit_url="${1}"
|
|
local nvim_patch_url="${nvim_commit_url}.patch"
|
|
|
|
local git_patch_prefix='Subject: \[PATCH\] '
|
|
local nvim_patch
|
|
nvim_patch="$(curl -Ssf "${nvim_patch_url}")"
|
|
local vim_version
|
|
vim_version="$(head -n 4 <<< "${nvim_patch}" | sed -nEe 's/'"${git_patch_prefix}"'vim-patch:([a-z0-9.]*)(:.*){0,1}$/\1/p')"
|
|
|
|
echo
|
|
if [[ -n "${vim_version}" ]]; then
|
|
msg_ok "Detected Vim patch '${vim_version}'."
|
|
else
|
|
msg_err "Could not detect the Vim patch number."
|
|
echo " This script assumes that the PR contains only commits"
|
|
echo " with 'vim-patch:XXX' in their title."
|
|
echo
|
|
printf -- '%s\n\n' "$(head -n 4 <<< "${nvim_patch}")"
|
|
local reply
|
|
read -p "Continue reviewing (y/N)? " -n 1 -r reply
|
|
if [[ "${reply}" == y ]]; then
|
|
echo
|
|
return
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
assign_commit_details "${vim_version}"
|
|
|
|
echo
|
|
echo "Creating files."
|
|
echo "${nvim_patch}" > "${NVIM_SOURCE_DIR}/n${patch_file}"
|
|
msg_ok "Saved pull request diff to '${NVIM_SOURCE_DIR}/n${patch_file}'."
|
|
CREATED_FILES+=("${NVIM_SOURCE_DIR}/n${patch_file}")
|
|
|
|
local nvim="nvim -u NONE -n -i NONE --headless"
|
|
2>/dev/null $nvim --cmd 'set dir=/tmp' +'1,/^$/g/^ /-1join' +w +q "${NVIM_SOURCE_DIR}/n${patch_file}"
|
|
|
|
local expected_commit_message
|
|
expected_commit_message="$(commit_message)"
|
|
local message_length
|
|
message_length="$(wc -l <<< "${expected_commit_message}")"
|
|
local commit_message
|
|
commit_message="$(tail -n +4 "${NVIM_SOURCE_DIR}/n${patch_file}" | head -n "${message_length}")"
|
|
if [[ "${commit_message#"$git_patch_prefix"}" == "${expected_commit_message}" ]]; then
|
|
msg_ok "Found expected commit message."
|
|
else
|
|
msg_err "Wrong commit message."
|
|
echo " Expected:"
|
|
echo "${expected_commit_message}"
|
|
echo " Actual:"
|
|
echo "${commit_message#"$git_patch_prefix"}"
|
|
fi
|
|
|
|
get_vimpatch "${vim_version}"
|
|
CREATED_FILES+=("${NVIM_SOURCE_DIR}/${patch_file}")
|
|
|
|
echo
|
|
echo "Launching nvim."
|
|
nvim -c "cd ${NVIM_SOURCE_DIR}" \
|
|
-O "${NVIM_SOURCE_DIR}/${patch_file}" "${NVIM_SOURCE_DIR}/n${patch_file}"
|
|
}
|
|
|
|
review_pr() {
|
|
require_executable curl
|
|
require_executable nvim
|
|
require_executable jq
|
|
|
|
get_vim_sources
|
|
|
|
local pr="${1}"
|
|
echo
|
|
echo "Downloading data for pull request #${pr}."
|
|
|
|
local -a pr_commit_urls
|
|
while IFS= read -r pr_commit_url; do
|
|
pr_commit_urls+=("$pr_commit_url")
|
|
done < <(curl -Ssf "https://api.github.com/repos/neovim/neovim/pulls/${pr}/commits" \
|
|
| jq -r '.[].html_url')
|
|
|
|
echo "Found ${#pr_commit_urls[@]} commit(s)."
|
|
|
|
local pr_commit_url
|
|
local reply
|
|
for pr_commit_url in "${pr_commit_urls[@]}"; do
|
|
review_commit "${pr_commit_url}"
|
|
if [[ "${pr_commit_url}" != "${pr_commit_urls[-1]}" ]]; then
|
|
read -p "Continue with next commit (Y/n)? " -n 1 -r reply
|
|
echo
|
|
if [[ "${reply}" == n ]]; then
|
|
break
|
|
fi
|
|
fi
|
|
done
|
|
|
|
clean_files
|
|
}
|
|
|
|
is_na_patch() {
|
|
local patch=$1
|
|
local NA_REGEXP="$NVIM_SOURCE_DIR/scripts/vim_na_regexp.txt"
|
|
local NA_FILELIST="$NVIM_SOURCE_DIR/scripts/vim_na_files.txt"
|
|
local NA_HUNKS_C="$NVIM_SOURCE_DIR/scripts/vim_na_hunks_c.txt"
|
|
local NA_HUNKS_H="$NVIM_SOURCE_DIR/scripts/vim_na_hunks_h.txt"
|
|
local NA_HUNKS_HELP="$NVIM_SOURCE_DIR/scripts/vim_na_hunks_help.txt"
|
|
local NA_HUNKS_MAKE_PO="$NVIM_SOURCE_DIR/scripts/vim_na_hunks_make_po.txt"
|
|
local NA_HUNKS_VIM="$NVIM_SOURCE_DIR/scripts/vim_na_hunks_vim.txt"
|
|
|
|
local FILES_REMAINING HUNKS HUNK_NUM_FINAL
|
|
FILES_REMAINING="$(diff <(git -C "${VIM_SOURCE_DIR}" diff-tree --no-commit-id -r -b --name-only "$patch" | grep -v -f "$NA_REGEXP") "$NA_FILELIST" |
|
|
grep '^<' | sed 's/^< //')" || true
|
|
test -z "$FILES_REMAINING" && return 0
|
|
|
|
for file in $FILES_REMAINING; do
|
|
case ${file} in
|
|
runtime/doc/*.txt | runtime/pack/dist/opt/*/doc/*.txt)
|
|
HUNKS=$(git -c core.attributesfile="$NVIM_SOURCE_DIR"/.gitattributes -c 'diff.helphelp.xfuncname=^.*\*[^*[:space:]]+\*$' -C "${VIM_SOURCE_DIR}" \
|
|
diff-tree --no-commit-id -r -b -U0 \
|
|
'-I^\s+$' \
|
|
'-I^[-=]+$' \
|
|
'-I^(Functions:|GUI|Other)\s~$' \
|
|
'-I^[A-Z]\s+\*\+sodium\*\s+compiled with ' \
|
|
'-I^\|(ch|popup)_[_a-z]+\(\)\|' \
|
|
'-I^'\''tabpanel[a-z]*'\' \
|
|
'-I^popup_[_a-z]+\(' \
|
|
'-I^sodium\s+Compiled with ' \
|
|
'-I\*\s+For Vim version [0-9]\.[0-9]\.\s+Last change: [0-9]+ [A-Z][a-z]+ [0-9]+' \
|
|
'-I compiled (with|without) .*\(\|.+\|\) feature\.$' \
|
|
'-I\{.+ (available|compiled) (with|without) .+\}' \
|
|
'-I\|(added|changed|patches|version)-[0-9]+\.[0-9]+\|' \
|
|
'-I\|:(cscope|export|import|redrawtabpanel)\|' \
|
|
'-I\|52\.6\|' \
|
|
'-I\|channel-open-[^|]+\|' \
|
|
'-I\|comment-install\|' \
|
|
'-I\|os_haiku.txt\|' \
|
|
'-I\|popup-windows\|' \
|
|
'-I\|tabpanel\|' \
|
|
'-I\|xdg\.vim\|' \
|
|
'-I\sGTK\s?4\s' \
|
|
'-I\spopup window\s' \
|
|
'-I\sterm_start\(\)\s' \
|
|
'-I\svim\s.*VIMRUNTIME/tutor/tutor' \
|
|
'-I[[:space:],]tpl_vert[[:space:]:]' \
|
|
'-I\-gui=gtk' \
|
|
"$patch" -- "${file}")
|
|
if test -n "$HUNKS"; then
|
|
HUNK_NUM_FINAL=$(echo "$HUNKS" | grep '^@@ .* @@' | sed 's/^@@ .* @@ //' | grep -cv -f "$NA_HUNKS_HELP")
|
|
test "$HUNK_NUM_FINAL" -ne 0 && return 1
|
|
fi
|
|
;;
|
|
runtime/syntax/vim.vim)
|
|
HUNKS=$(git -C "${VIM_SOURCE_DIR}" diff-tree --no-commit-id -r -b -U0 \
|
|
'-I^\s+$' \
|
|
'-I^" Last Change:\s' \
|
|
'-I^\s*syn\s+keyword\s+(vimCommand|vimFuncName)\s+contained\s+' \
|
|
'-I^\s*syn\s+keyword\s+vimAutoEvent\s+contained\s+[^U]' \
|
|
'-I^\s*syn\s+match\s+vimFuncName\s+contained\s+"\\<nvim_' \
|
|
"$patch" -- "${file}")
|
|
test -n "$HUNKS" && return 1
|
|
;;
|
|
src/po/Make*)
|
|
HUNKS=$(git -C "${VIM_SOURCE_DIR}" diff-tree --no-commit-id -r -b -U0 \
|
|
'-I^\$\([_A-Z]+\)\.pot:' \
|
|
'-I^VIM(PROG)?\s=\s' \
|
|
"$patch" -- "${file}")
|
|
if test -n "$HUNKS"; then
|
|
# shellcheck disable=SC2016
|
|
HUNK_NUM_FINAL=$(echo "$HUNKS" | grep '^@@ .* @@' | sed 's/^@@ .* @@ //' | grep -cv -f "$NA_HUNKS_MAKE_PO")
|
|
test "$HUNK_NUM_FINAL" -ne 0 && return 1
|
|
fi
|
|
;;
|
|
src/testdir/Makefile)
|
|
HUNKS=$(git -C "${VIM_SOURCE_DIR}" diff-tree --no-commit-id -r -b -U0 \
|
|
'-IREDIR_TEST_TO_NULL = ' \
|
|
"$patch" -- "${file}")
|
|
test -n "$HUNKS" && return 1
|
|
;;
|
|
src/testdir/Make_all.mak)
|
|
HUNKS=$(git -C "${VIM_SOURCE_DIR}" diff-tree --no-commit-id -r -b -U0 \
|
|
'-I\stest8[67]\.out \\$' \
|
|
"$patch" -- "${file}")
|
|
if test -n "$HUNKS"; then
|
|
HUNK_NUM_FINAL=$(echo "$HUNKS" | grep '^@@ .* @@' | sed 's/^@@ .* @@ //' | grep -cv -e '^NEW_TESTS\(\|_RES\) = \\$')
|
|
test "$HUNK_NUM_FINAL" -ne 0 && return 1
|
|
fi
|
|
;;
|
|
src/testdir/*.vim)
|
|
HUNKS=$(git -C "${VIM_SOURCE_DIR}" diff-tree --no-commit-id -r -b -U0 \
|
|
"$patch" -- "${file}")
|
|
if test -n "$HUNKS"; then
|
|
HUNK_NUM_FINAL=$(echo "$HUNKS" | grep '^@@ .* @@' | sed 's/^@@ .* @@ //' | grep -cv -f "$NA_HUNKS_VIM")
|
|
test "$HUNK_NUM_FINAL" -ne 0 && return 1
|
|
fi
|
|
;;
|
|
*.h)
|
|
HUNKS=$(git -C "${VIM_SOURCE_DIR}" diff-tree --no-commit-id -r -b -U0 \
|
|
'-I^\s+$' \
|
|
'-I^\s*/?\*/?$' \
|
|
'-I^\s*(//|/?\*).*\s\+?([vV]im9|E[0-9]{,4} unused|E[0-9]{4} - |FEAT_|JSON-RPC|channel|job|popup|sound|tabpanel|terminal)' \
|
|
'-I^#\s*((ifdef|ifndef|undef)|(if|elif)\s.*defined\().*(FEAT_[^_]|USE_GTK)' \
|
|
'-I^#\s*(else|endif)' \
|
|
'-I^#\s*define\s+(FEAT|POPUPWIN|XDG|t)_[^_]' \
|
|
'-I^\s+(&&|\|\|)\s.*defined\(.*FEAT_[^_]' \
|
|
'-IEVENT_TERMINALWINOPEN' \
|
|
'-I^#\s*define\s+(ASSIGN_VAR|IN_TABPANEL|POPF_CURSORLINE)\s' \
|
|
'-I^typedef enum \{$' \
|
|
'-I^\s+(CH_MODE|POPCLOSE)_[A-Z]+,?(\s+//.+)?$' \
|
|
'-I^\} popclose_T;$' \
|
|
'-I^EXTERN\schar\s+\*popup_transparent' \
|
|
'-I^EXTERN\schar_u\s+\*p_tplo?;' \
|
|
'-I^EXTERN\sint\s+[_a-z]+_for_testing\s' \
|
|
'-I^EXTERN\slong\s+p_stpl;' \
|
|
'-I^EXTERN type_T static_types\[' \
|
|
'-I^EXTERN type_T t_.* INIT[2-9]\(' \
|
|
'-I^EXTERN\swin_T\s+\*popup_dragwin' \
|
|
'-I^EXTERN char e_(abstract|const|class|enum|final|interface|public|static|type)_' \
|
|
'-I^EXTERN char e_.*def_function' \
|
|
'-I^EXTERN char e_.*enddef' \
|
|
'-I^EXTERN char e_.*vim9' \
|
|
'-I^EXTERN char e_[_a-zA-Z]+_(channel|redrawtabpanel)' \
|
|
'-I^EXTERN char e_cannot_add(_redraw|)_listener_in_listener_callback' \
|
|
'-I^EXTERN char e_cannot_declare_.*variable_str' \
|
|
'-I^EXTERN char e_cannot_define_new_.+_as_static' \
|
|
'-I^EXTERN char e_cannot_listen_on_port' \
|
|
'-I^EXTERN char e_cannot_open_a_popup_window_to_a_closing_buffer' \
|
|
'-I^EXTERN char e_cannot_use_a_return_type_with_new' \
|
|
'-I^EXTERN char e_dictionary_not_set' \
|
|
'-I^EXTERN char e_dictnull' \
|
|
'-I^EXTERN char e_failed_to_source_defaults' \
|
|
'-I^EXTERN char e_gethostbyname_in_channel_' \
|
|
'-I^EXTERN char e_invalid_identifier_in_defineannotype' \
|
|
'-I^EXTERN int\s+redraw_tabpanel\s' \
|
|
'-I\sINIT\(= .+"E[0-9]+: (Abstract|Const|Class|Enum|Final|Interface|Public|Static|Type) ' \
|
|
'-I\sINIT\(= .+"E[0-9]+: .*:def ' \
|
|
'-I\sINIT\(= .+"E[0-9]+: .*enddef"' \
|
|
'-I\sINIT\(= .+"E[0-9]+: .*([vV]im9|interface)' \
|
|
'-I\sINIT\(= .+"E[0-9]+: .* (ch|channel)_[_a-z]+\(\)' \
|
|
'-I\sINIT\(= .+"E649: Invalid identifier name in defineAnnoType' \
|
|
'-I\sINIT\(= .+"E1016: Cannot declare .* variable: ' \
|
|
'-I\sINIT\(= .+"E1103: Dictionary not set' \
|
|
'-I\sINIT\(= .+"E1187: .*defaults\.vim' \
|
|
'-I\sINIT\(= .+"E1365: Cannot use a return type with the \\"new\\" function"' \
|
|
'-I\sINIT\(= .+"E1370: Cannot define a .+ as static' \
|
|
'-I\sINIT\(= .+"E15[0-9]+: Cannot use .*listener_add in a .* listener callback"' \
|
|
'-I\sINIT\(= .+"E1547: .+ :redrawtabpanel"' \
|
|
'-I\sINIT\(= .+"E1551: Cannot open a popup window to a closing buffer' \
|
|
'-I\sINIT\(= .+"E157[34]: ' \
|
|
'-I\sHLF_TPL[SF]?\s+//\stabpanel' \
|
|
'-I\s(bool|char(|_u)|int)\s+w_popup_image_[_a-zA-Z]+;' \
|
|
'-I\schar(|_u)\s+\*w_popup_title;' \
|
|
'-I\sint\s+ch_[_a-zA-Z]+;' \
|
|
'-I\sint\s+sv_const;' \
|
|
'-I\sint\s+tpl_vert;' \
|
|
'-I\sint\s+w_(filter_mode|firstline|popup_drag|want_scrollbar);' \
|
|
'-I\slist_T\s+\*w_popup_mask;' \
|
|
'-I\spopclose_T\sw_popup_close;' \
|
|
'-I\s\*?w_popup_prop_[_a-z]+;' \
|
|
"$patch" -- "${file}")
|
|
if test -n "$HUNKS"; then
|
|
HUNK_NUM_FINAL=$(echo "$HUNKS" | grep '^@@ .* @@' | sed 's/^@@ .* @@ //' | grep -cv -f "$NA_HUNKS_H")
|
|
test "$HUNK_NUM_FINAL" -ne 0 && return 1
|
|
fi
|
|
;;
|
|
*.c)
|
|
HUNKS=$(git -C "${VIM_SOURCE_DIR}" diff-tree --no-commit-id -r -b -U0 \
|
|
'-I^\s+$' \
|
|
'-I^\s*/?\*/?$' \
|
|
'-I^\s*(//|/?\*).*\s\+?([vV]im9|E[0-9]{4} - |FEAT_|channel|job|popup|sound|tabpanel|terminal|uf_type_list)' \
|
|
'-I^#\s*((ifdef|ifndef|undef)|(if|elif)\s.*defined\().*(FEAT_[^_]|USE_GTK)' \
|
|
'-I^#\s*(else|endif)' \
|
|
'-I^#\s*define\s+(FEAT|POPUPWIN|XDG|t)_[^_]' \
|
|
'-I^\s+(&&|\|\|)\s.*defined\(.*FEAT_[^_]' \
|
|
'-IEVENT_TERMINALWINOPEN' \
|
|
'-I^#\s*include\s+<proto/' \
|
|
'-I^\s+\{"(ch|popup)_[_a-z]+",.*\sFEARG_[1-9],\s+arg[1-9]_[_a-z]+' \
|
|
'-I^\s+\{"(popup|prop|sound)_[_a-z]+",.*f_(popup|prop|sound)_[_a-z]+\)?},$' \
|
|
'-I^\s+ret_[_a-z]+,\s+(JOB|PROP)_FUNC\(f_.+\)},$' \
|
|
'-I^\s*(static)?\s(char(|_u)|hashtab_T|int|void)( \*)?$' \
|
|
'-I^static\sargcheck_T\sarg[1-9]_[_a-z]+' \
|
|
'-I^static\s(char(|_u)|hashtab_T|int|void)\s\*?[^*]+\(.+\);$' \
|
|
'-I^static\schar\s\*\(p_tpl_values' \
|
|
'-I#\s*define.*ex_ni$' \
|
|
'-I[.>]b_p_key' \
|
|
'-I[_.>]sc_version = ' \
|
|
'-I[_.>]uf_script_ctx_version = ' \
|
|
'-I[_.>]uf_type_list' \
|
|
'-I = skip_type\(.+\);$' \
|
|
'-Icheck_typval_type\(.+\)' \
|
|
'-Icrypt_get_method_nr\(.+\)' \
|
|
'-Ie_failed_to_source_defaults' \
|
|
'-Imsg\(.*".*GTK.*"\)' \
|
|
'-I\s"default link TabPanel.+",' \
|
|
'-I\sif\s\((in|redraw)_tabpanel[[:space:])]' \
|
|
'-I\s(in|redraw)_tabpanel =' \
|
|
'-I\sdraw_tabpanel\(\);$' \
|
|
'-I\spopup_set_firstline\(.+\);' \
|
|
'-I\sterm_focus_change\(.+\);$' \
|
|
'-I\supdate_vim9_script_var\(.+\);$' \
|
|
'-I\svim_free\(.*w_popup_title\);' \
|
|
"$patch" -- "${file}")
|
|
if test -n "$HUNKS"; then
|
|
HUNK_NUM_FINAL=$(echo "$HUNKS" | grep '^@@ .* @@' | sed 's/^@@ .* @@ //' | grep -cv -f "$NA_HUNKS_C")
|
|
test "$HUNK_NUM_FINAL" -ne 0 && return 1
|
|
fi
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
list_na_patches() {
|
|
list_missing_vimpatches 0 | while read -r patch; do
|
|
if is_na_patch "$patch"; then
|
|
if (echo "$patch" | grep -q '^v[0-9]\.[0-9]\.[0-9]') && _git -C "${VIM_SOURCE_DIR}" show-ref --exists "refs/tags/$patch" 2>/dev/null; then
|
|
echo "vim-patch:${patch:1}: $(_git -C "${VIM_SOURCE_DIR}" log -1 --format="%s" "$patch")"
|
|
else
|
|
echo "vim-patch:$(_git -C "${VIM_SOURCE_DIR}" log -1 --oneline "$patch")"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
while getopts "hlLmnMVp:P:g:r:s" opt; do
|
|
case ${opt} in
|
|
h)
|
|
usage
|
|
exit 0
|
|
;;
|
|
l)
|
|
shift # remove opt
|
|
show_vimpatches "$@"
|
|
exit 0
|
|
;;
|
|
L)
|
|
shift # remove opt
|
|
list_missing_vimpatches 0 "$@"
|
|
exit 0
|
|
;;
|
|
M)
|
|
list_vimpatch_numbers
|
|
exit 0
|
|
;;
|
|
m)
|
|
shift # remove opt
|
|
list_missing_previous_vimpatches_for_patch "$@"
|
|
exit 0
|
|
;;
|
|
n)
|
|
list_na_patches
|
|
exit 0
|
|
;;
|
|
p)
|
|
stage_patch "${OPTARG}"
|
|
exit
|
|
;;
|
|
P)
|
|
stage_patch "${OPTARG}" TRY_APPLY
|
|
exit 0
|
|
;;
|
|
g)
|
|
get_vimpatch "${OPTARG}"
|
|
exit 0
|
|
;;
|
|
r)
|
|
review_pr "${OPTARG}"
|
|
exit 0
|
|
;;
|
|
s)
|
|
shift # remove opt
|
|
submit_pr "$@"
|
|
exit 0
|
|
;;
|
|
V)
|
|
get_vim_sources update
|
|
exit 0
|
|
;;
|
|
*)
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
usage
|
|
|
|
# vim: et sw=2
|