vim-patch.sh 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. #!/usr/bin/env bash
  2. set -e
  3. set -u
  4. # Use privileged mode, which e.g. skips using CDPATH.
  5. set -p
  6. readonly NVIM_SOURCE_DIR="${NVIM_SOURCE_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
  7. readonly VIM_SOURCE_DIR_DEFAULT="${NVIM_SOURCE_DIR}/.vim-src"
  8. readonly VIM_SOURCE_DIR="${VIM_SOURCE_DIR:-${VIM_SOURCE_DIR_DEFAULT}}"
  9. readonly BASENAME="$(basename "${0}")"
  10. readonly BRANCH_PREFIX="vim-"
  11. CREATED_FILES=()
  12. usage() {
  13. echo "Port Vim patches to Neovim"
  14. echo "https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim"
  15. echo
  16. echo "Usage: ${BASENAME} [-h | -l | -p vim-revision | -r pr-number]"
  17. echo
  18. echo "Options:"
  19. echo " -h Show this message and exit."
  20. echo " -l List missing Vim patches."
  21. echo " -L List missing Vim patches (for scripts)."
  22. echo " -M List all merged patch-numbers (at current v:version)."
  23. echo " -p {vim-revision} Download and generate a Vim patch. vim-revision"
  24. echo " can be a Vim version (8.0.xxx) or a Git hash."
  25. echo " -P {vim-revision} Download, generate and apply a Vim patch."
  26. echo " -g {vim-revision} Download a Vim patch."
  27. echo " -s Create a vim-patch pull request."
  28. echo " -r {pr-number} Review a vim-patch pull request."
  29. echo ' -V Clone the Vim source code to $VIM_SOURCE_DIR.'
  30. echo
  31. echo ' $VIM_SOURCE_DIR controls where Vim sources are found'
  32. echo " (default: '${VIM_SOURCE_DIR_DEFAULT}')"
  33. }
  34. msg_ok() {
  35. printf '\e[32m✔\e[0m %s\n' "$@"
  36. }
  37. msg_err() {
  38. printf '\e[31m✘\e[0m %s\n' "$@"
  39. }
  40. # Checks if a program is in the user's PATH, and is executable.
  41. check_executable() {
  42. test -x "$(command -v "${1}")"
  43. }
  44. require_executable() {
  45. if ! check_executable "${1}"; then
  46. >&2 echo "${BASENAME}: '${1}' not found in PATH or not executable."
  47. exit 1
  48. fi
  49. }
  50. clean_files() {
  51. if [[ ${#CREATED_FILES[@]} -eq 0 ]]; then
  52. return
  53. fi
  54. echo
  55. echo "Created files:"
  56. local file
  57. for file in "${CREATED_FILES[@]}"; do
  58. echo " • ${file}"
  59. done
  60. read -p "Delete these files (Y/n)? " -n 1 -r reply
  61. echo
  62. if [[ "${reply}" == n ]]; then
  63. echo "You can use 'git clean' to remove these files when you're done."
  64. else
  65. rm -- "${CREATED_FILES[@]}"
  66. fi
  67. }
  68. get_vim_sources() {
  69. require_executable git
  70. if [[ ! -d ${VIM_SOURCE_DIR} ]]; then
  71. echo "Cloning Vim into: ${VIM_SOURCE_DIR}"
  72. git clone https://github.com/vim/vim.git "${VIM_SOURCE_DIR}"
  73. cd "${VIM_SOURCE_DIR}"
  74. else
  75. cd "${VIM_SOURCE_DIR}"
  76. if ! [ -d ".git" ] \
  77. && ! [ "$(git rev-parse --show-toplevel)" = "${VIM_SOURCE_DIR}" ]; then
  78. msg_err "${VIM_SOURCE_DIR} does not appear to be a git repository."
  79. echo " Please remove it and try again."
  80. exit 1
  81. fi
  82. echo "Updating Vim sources: ${VIM_SOURCE_DIR}"
  83. git pull --ff &&
  84. msg_ok "Updated Vim sources." ||
  85. msg_err "Could not update Vim sources; ignoring error."
  86. fi
  87. }
  88. commit_message() {
  89. if [[ -n "$vim_tag" ]]; then
  90. printf '%s\n%s' "${vim_message}" "${vim_commit_url}"
  91. else
  92. printf 'vim-patch:%s\n\n%s\n%s' "$vim_version" "$vim_message" "$vim_commit_url"
  93. fi
  94. }
  95. find_git_remote() {
  96. git remote -v \
  97. | awk '$2 ~ /github.com[:\/]neovim\/neovim/ && $3 == "(fetch)" {print $1; exit}'
  98. }
  99. assign_commit_details() {
  100. if [[ ${1} =~ [0-9]\.[0-9]\.[0-9]{3,4} ]]; then
  101. # Interpret parameter as version number (tag).
  102. vim_version="${1}"
  103. vim_tag="v${1}"
  104. vim_commit=$(cd "${VIM_SOURCE_DIR}" \
  105. && git log -1 --format="%H" "${vim_tag}")
  106. local munge_commit_line=true
  107. else
  108. # Interpret parameter as commit hash.
  109. vim_version="${1:0:12}"
  110. vim_tag=
  111. vim_commit=$(cd "${VIM_SOURCE_DIR}" \
  112. && git log -1 --format="%H" "${vim_version}")
  113. local munge_commit_line=false
  114. fi
  115. vim_commit_url="https://github.com/vim/vim/commit/${vim_commit}"
  116. vim_message="$(cd "${VIM_SOURCE_DIR}" \
  117. && git log -1 --pretty='format:%B' "${vim_commit}" \
  118. | sed -e 's/\(#[0-9]\{1,\}\)/vim\/vim\1/g')"
  119. if [[ ${munge_commit_line} == "true" ]]; then
  120. # Remove first line of commit message.
  121. vim_message="$(echo "${vim_message}" | sed -e '1s/^patch /vim-patch:/')"
  122. fi
  123. patch_file="vim-${vim_version}.patch"
  124. }
  125. # Patch surgery
  126. preprocess_patch() {
  127. local file="$1"
  128. local nvim="nvim -u NORC -i NONE --headless"
  129. # Remove *.proto, Make*, gui_*, some if_*
  130. local na_src='proto\|Make*\|gui_*\|if_lua\|if_mzsch\|if_olepp\|if_ole\|if_perl\|if_py\|if_ruby\|if_tcl\|if_xcmdsrv'
  131. 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\S*\<\%(testdir/\)\@<!\%('${na_src}'\)@norm! d/\v(^diff)|%$ ' +w +q "$file"
  132. # Remove unwanted Vim doc files.
  133. local na_doc='channel\.txt\|netbeans\.txt\|os_\w\+\.txt\|term\.txt\|todo\.txt\|version\d\.txt\|sponsor\.txt\|intro\.txt\|tags'
  134. 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/runtime/doc/\<\%('${na_doc}'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
  135. # Remove "Last change ..." changes in doc files.
  136. 2>/dev/null $nvim --cmd 'set dir=/tmp' +'%s/^@@.*\n.*For Vim version.*Last change.*\n.*For Vim version.*Last change.*//' +w +q "$file"
  137. # Remove screen dumps, testdir/Make_*.mak files
  138. local na_src_testdir='Make_amiga.mak\|Make_dos.mak\|Make_ming.mak\|Make_vms.mms\|dumps/.*.dump'
  139. 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/testdir/\<\%('${na_src_testdir}'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
  140. # Remove version.c #7555
  141. local na_po='version.c'
  142. 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\<\%('${na_po}'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
  143. # Remove some *.po files. #5622
  144. 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'
  145. 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/po/\<\%('${na_po}'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
  146. # Remove vimrc_example.vim
  147. local na_vimrcexample='vimrc_example\.vim'
  148. 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/runtime/\<\%('${na_vimrcexample}'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
  149. # Rename src/ paths to src/nvim/
  150. LC_ALL=C sed -e 's/\( [ab]\/src\)/\1\/nvim/g' \
  151. "$file" > "$file".tmp && mv "$file".tmp "$file"
  152. # Rename path to matchit plugin.
  153. LC_ALL=C sed -e 's@\( [ab]/runtime\)/pack/dist/opt/matchit/\(plugin/matchit.vim\)@\1/\2@g' \
  154. "$file" > "$file".tmp && mv "$file".tmp "$file"
  155. LC_ALL=C sed -e 's@\( [ab]/runtime\)/pack/dist/opt/matchit/doc/\(matchit.txt\)@\1/doc/pi_\2@g' \
  156. "$file" > "$file".tmp && mv "$file".tmp "$file"
  157. # Rename test_urls.vim to check_urls.vim
  158. LC_ALL=C sed -e 's@\( [ab]\)/runtime/doc/test\(_urls.vim\)@\1/scripts/check\2@g' \
  159. "$file" > "$file".tmp && mv "$file".tmp "$file"
  160. # Rename path to check_colors.vim
  161. LC_ALL=C sed -e 's@\( [ab]/runtime\)/colors/\(tools/check_colors.vim\)@\1/\2@g' \
  162. "$file" > "$file".tmp && mv "$file".tmp "$file"
  163. }
  164. get_vimpatch() {
  165. get_vim_sources
  166. assign_commit_details "${1}"
  167. git log -1 "${vim_commit}" -- >/dev/null 2>&1 || {
  168. >&2 msg_err "Couldn't find Vim revision '${vim_commit}'."
  169. exit 3
  170. }
  171. msg_ok "Found Vim revision '${vim_commit}'."
  172. local patch_content
  173. patch_content="$(git --no-pager show --color=never -1 --pretty=medium "${vim_commit}")"
  174. cd "${NVIM_SOURCE_DIR}"
  175. printf "Creating patch...\n"
  176. echo "$patch_content" > "${NVIM_SOURCE_DIR}/${patch_file}"
  177. printf "Pre-processing patch...\n"
  178. preprocess_patch "${NVIM_SOURCE_DIR}/${patch_file}"
  179. msg_ok "Saved patch to '${NVIM_SOURCE_DIR}/${patch_file}'."
  180. }
  181. stage_patch() {
  182. get_vimpatch "$1"
  183. local try_apply="${2:-}"
  184. local git_remote
  185. git_remote="$(find_git_remote)"
  186. local checked_out_branch
  187. checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
  188. if [[ "${checked_out_branch}" == ${BRANCH_PREFIX}* ]]; then
  189. msg_ok "Current branch '${checked_out_branch}' seems to be a vim-patch"
  190. echo " branch; not creating a new branch."
  191. else
  192. printf '\nFetching "%s/master".\n' "${git_remote}"
  193. output="$(git fetch "${git_remote}" master 2>&1)" &&
  194. msg_ok "${output}" ||
  195. (msg_err "${output}"; false)
  196. local nvim_branch="${BRANCH_PREFIX}${vim_version}"
  197. echo
  198. echo "Creating new branch '${nvim_branch}' based on '${git_remote}/master'."
  199. cd "${NVIM_SOURCE_DIR}"
  200. output="$(git checkout -b "${nvim_branch}" "${git_remote}/master" 2>&1)" &&
  201. msg_ok "${output}" ||
  202. (msg_err "${output}"; false)
  203. fi
  204. printf "\nCreating empty commit with correct commit message.\n"
  205. output="$(commit_message | git commit --allow-empty --file 2>&1 -)" &&
  206. msg_ok "${output}" ||
  207. (msg_err "${output}"; false)
  208. if test -n "$try_apply" ; then
  209. if ! check_executable patch; then
  210. printf "\n"
  211. msg_err "'patch' command not found\n"
  212. else
  213. printf "\nApplying patch...\n"
  214. patch -p1 < "${patch_file}" || true
  215. find . -name '*.orig' -type f -delete
  216. fi
  217. printf "\nInstructions:\n Proceed to port the patch.\n"
  218. else
  219. 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}"
  220. fi
  221. printf '
  222. Stage your changes ("git add ..."), then use "git commit --amend" to commit.
  223. To port more patches (if any) related to %s,
  224. run "%s" again.
  225. * Do this only for _related_ patches (otherwise it increases the
  226. size of the pull request, making it harder to review)
  227. When you are done, try "%s -s" to create the pull request.
  228. See the wiki for more information:
  229. * https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim
  230. ' "${vim_version}" "${BASENAME}" "${BASENAME}"
  231. }
  232. hub_pr() {
  233. hub pull-request -m "$1"
  234. }
  235. git_hub_pr() {
  236. git hub pull new -m "$1"
  237. }
  238. submit_pr() {
  239. require_executable git
  240. local push_first
  241. push_first=1
  242. local submit_fn
  243. if check_executable hub; then
  244. submit_fn="hub_pr"
  245. elif check_executable git-hub; then
  246. push_first=0
  247. submit_fn="git_hub_pr"
  248. else
  249. >&2 echo "${BASENAME}: 'hub' or 'git-hub' not found in PATH or not executable."
  250. exit 1
  251. fi
  252. cd "${NVIM_SOURCE_DIR}"
  253. local checked_out_branch
  254. checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
  255. if [[ "${checked_out_branch}" != ${BRANCH_PREFIX}* ]]; then
  256. msg_err "Current branch '${checked_out_branch}' doesn't seem to be a vim-patch branch."
  257. exit 1
  258. fi
  259. local git_remote
  260. git_remote="$(find_git_remote)"
  261. local pr_body
  262. pr_body="$(git log --grep=vim-patch --reverse --format='#### %s%n%n%b%n' "${git_remote}"/master..HEAD)"
  263. local patches
  264. # Extract just the "vim-patch:X.Y.ZZZZ" or "vim-patch:sha" portion of each log
  265. patches=("$(git log --grep=vim-patch --reverse --format='%s' "${git_remote}"/master..HEAD | sed 's/: .*//')")
  266. patches=(${patches[@]//vim-patch:}) # Remove 'vim-patch:' prefix for each item in array.
  267. local pr_title="${patches[*]}" # Create space-separated string from array.
  268. pr_title="${pr_title// /,}" # Replace spaces with commas.
  269. local pr_message
  270. pr_message="$(printf '[RFC] vim-patch:%s\n\n%s\n' "${pr_title#,}" "${pr_body}")"
  271. if [[ $push_first -ne 0 ]]; then
  272. echo "Pushing to 'origin/${checked_out_branch}'."
  273. output="$(git push origin "${checked_out_branch}" 2>&1)" &&
  274. msg_ok "${output}" ||
  275. (msg_err "${output}"; false)
  276. echo
  277. fi
  278. echo "Creating pull request."
  279. output="$(${submit_fn} "${pr_message}" 2>&1)" &&
  280. msg_ok "${output}" ||
  281. (msg_err "${output}"; false)
  282. echo
  283. echo "Cleaning up files."
  284. local patch_file
  285. for patch_file in "${patches[@]}"; do
  286. patch_file="vim-${patch_file}.patch"
  287. if [[ ! -f "${NVIM_SOURCE_DIR}/${patch_file}" ]]; then
  288. continue
  289. fi
  290. rm -- "${NVIM_SOURCE_DIR}/${patch_file}"
  291. msg_ok "Removed '${NVIM_SOURCE_DIR}/${patch_file}'."
  292. done
  293. }
  294. # Gets all Vim commits since the "start" commit.
  295. list_vim_commits() { (
  296. cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v8.0.0000..HEAD
  297. ) }
  298. # Prints all (sorted) "vim-patch:xxx" tokens found in the Nvim git log.
  299. list_vimpatch_tokens() {
  300. local tokens
  301. # Find all "vim-patch:xxx" tokens in the Nvim git log.
  302. tokens="$(cd "${NVIM_SOURCE_DIR}" && git log -E --grep='vim-patch:[^ ]+' | grep 'vim-patch')"
  303. echo "$tokens" | grep -E 'vim-patch:[^ ,{]{7,}' \
  304. | sed 's/.*\(vim-patch:[.0-9a-z]\+\).*/\1/' \
  305. | sort \
  306. | uniq
  307. }
  308. # Prints all patch-numbers (for the current v:version) for which there is
  309. # a "vim-patch:xxx" token in the Nvim git log.
  310. list_vimpatch_numbers() {
  311. # Transform "vim-patch:X.Y.ZZZZ" to "ZZZZ".
  312. list_vimpatch_tokens | while read vimpatch_token; do
  313. echo "$vimpatch_token" | grep '8\.0\.' | sed 's/.*vim-patch:8\.0\.\([0-9a-z]\+\).*/\1/'
  314. done
  315. }
  316. # Prints a newline-delimited list of Vim commits, for use by scripts.
  317. list_missing_vimpatches() {
  318. local tokens vim_commit vim_commits is_missing vim_tag patch_number
  319. # Find all "vim-patch:xxx" tokens in the Nvim git log.
  320. tokens="$(list_vimpatch_tokens)"
  321. # Get missing Vim commits
  322. vim_commits="$(list_vim_commits)"
  323. for vim_commit in ${vim_commits}; do
  324. # Check for vim-patch:<commit_hash> (usually runtime updates).
  325. is_missing="$(echo "$tokens" | >/dev/null 2>&1 grep "vim\-patch:${vim_commit:0:7}" && echo false || echo true)"
  326. if ! [ "$is_missing" = "false" ] \
  327. && vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)"
  328. then
  329. # Vim version number (not commit hash).
  330. # Check for vim-patch:<tag> (not commit hash).
  331. patch_number="${vim_tag:1}" # "v7.4.0001" => "7.4.0001"
  332. is_missing="$(echo "$tokens" | >/dev/null 2>&1 grep "vim\-patch:${patch_number}" && echo false || echo true)"
  333. vim_commit="${vim_tag#v}"
  334. fi
  335. if ! [ "$is_missing" = "false" ]; then
  336. echo "${vim_commit}"
  337. fi
  338. done
  339. }
  340. # Prints a human-formatted list of Vim commits, with instructional messages.
  341. show_vimpatches() {
  342. get_vim_sources
  343. printf "\nVim patches missing from Neovim:\n"
  344. list_missing_vimpatches | while read vim_commit; do
  345. if (cd "${VIM_SOURCE_DIR}" && git --no-pager show --color=never --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then
  346. printf ' • %s (+runtime)\n' "${vim_commit}"
  347. else
  348. printf ' • %s\n' "${vim_commit}"
  349. fi
  350. done
  351. printf "Instructions:
  352. To port one of the above patches to Neovim, execute
  353. this script with the patch revision as argument and
  354. follow the instructions.
  355. Examples: '%s -p 7.4.487'
  356. '%s -p 1e8ebf870720e7b671f98f22d653009826304c4f'
  357. NOTE: Please port the _oldest_ patch if you possibly can.
  358. Out-of-order patches increase the possibility of bugs.
  359. " "${BASENAME}" "${BASENAME}"
  360. }
  361. review_commit() {
  362. local nvim_commit_url="${1}"
  363. local nvim_patch_url="${nvim_commit_url}.patch"
  364. local git_patch_prefix='Subject: \[PATCH\] '
  365. local nvim_patch
  366. nvim_patch="$(curl -Ssf "${nvim_patch_url}")"
  367. local vim_version
  368. vim_version="$(head -n 4 <<< "${nvim_patch}" | sed -n 's/'"${git_patch_prefix}"'vim-patch:\([a-z0-9.]*\)\(:.*\)\{0,1\}$/\1/p')"
  369. echo
  370. if [[ -n "${vim_version}" ]]; then
  371. msg_ok "Detected Vim patch '${vim_version}'."
  372. else
  373. msg_err "Could not detect the Vim patch number."
  374. echo " This script assumes that the PR contains only commits"
  375. echo " with 'vim-patch:XXX' in their title."
  376. echo
  377. printf -- '%s\n\n' "$(head -n 4 <<< "${nvim_patch}")"
  378. local reply
  379. read -p "Continue reviewing (y/N)? " -n 1 -r reply
  380. if [[ "${reply}" == y ]]; then
  381. echo
  382. return
  383. fi
  384. exit 1
  385. fi
  386. assign_commit_details "${vim_version}"
  387. echo
  388. echo "Creating files."
  389. echo "${nvim_patch}" > "${NVIM_SOURCE_DIR}/n${patch_file}"
  390. msg_ok "Saved pull request diff to '${NVIM_SOURCE_DIR}/n${patch_file}'."
  391. CREATED_FILES+=("${NVIM_SOURCE_DIR}/n${patch_file}")
  392. local nvim="nvim -u NORC -n -i NONE --headless"
  393. 2>/dev/null $nvim --cmd 'set dir=/tmp' +'1,/^$/g/^ /-1join' +w +q "${NVIM_SOURCE_DIR}/n${patch_file}"
  394. local expected_commit_message
  395. expected_commit_message="$(commit_message)"
  396. local message_length
  397. message_length="$(wc -l <<< "${expected_commit_message}")"
  398. local commit_message
  399. commit_message="$(tail -n +4 "${NVIM_SOURCE_DIR}/n${patch_file}" | head -n "${message_length}")"
  400. if [[ "${commit_message#${git_patch_prefix}}" == "${expected_commit_message}" ]]; then
  401. msg_ok "Found expected commit message."
  402. else
  403. msg_err "Wrong commit message."
  404. echo " Expected:"
  405. echo "${expected_commit_message}"
  406. echo " Actual:"
  407. echo "${commit_message#${git_patch_prefix}}"
  408. fi
  409. get_vimpatch "${vim_version}"
  410. CREATED_FILES+=("${NVIM_SOURCE_DIR}/${patch_file}")
  411. echo
  412. echo "Launching nvim."
  413. nvim -c "cd ${NVIM_SOURCE_DIR}" \
  414. -O "${NVIM_SOURCE_DIR}/${patch_file}" "${NVIM_SOURCE_DIR}/n${patch_file}"
  415. }
  416. review_pr() {
  417. require_executable curl
  418. require_executable nvim
  419. require_executable jq
  420. get_vim_sources
  421. local pr="${1}"
  422. echo
  423. echo "Downloading data for pull request #${pr}."
  424. local pr_commit_urls=($(curl -Ssf "https://api.github.com/repos/neovim/neovim/pulls/${pr}/commits" \
  425. | jq -r '.[].html_url'))
  426. echo "Found ${#pr_commit_urls[@]} commit(s)."
  427. local pr_commit_url
  428. local reply
  429. for pr_commit_url in "${pr_commit_urls[@]}"; do
  430. review_commit "${pr_commit_url}"
  431. if [[ "${pr_commit_url}" != "${pr_commit_urls[-1]}" ]]; then
  432. read -p "Continue with next commit (Y/n)? " -n 1 -r reply
  433. echo
  434. if [[ "${reply}" == n ]]; then
  435. break
  436. fi
  437. fi
  438. done
  439. clean_files
  440. }
  441. while getopts "hlLMVp:P:g:r:s" opt; do
  442. case ${opt} in
  443. h)
  444. usage
  445. exit 0
  446. ;;
  447. l)
  448. show_vimpatches
  449. exit 0
  450. ;;
  451. L)
  452. list_missing_vimpatches
  453. exit 0
  454. ;;
  455. M)
  456. list_vimpatch_numbers
  457. exit 0
  458. ;;
  459. p)
  460. stage_patch "${OPTARG}"
  461. exit 0
  462. ;;
  463. P)
  464. stage_patch "${OPTARG}" TRY_APPLY
  465. exit 0
  466. ;;
  467. g)
  468. get_vimpatch "${OPTARG}"
  469. exit 0
  470. ;;
  471. r)
  472. review_pr "${OPTARG}"
  473. exit 0
  474. ;;
  475. s)
  476. submit_pr
  477. exit 0
  478. ;;
  479. V)
  480. get_vim_sources
  481. exit 0
  482. ;;
  483. *)
  484. exit 1
  485. ;;
  486. esac
  487. done
  488. usage
  489. # vim: et sw=2