You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 lines
22 KiB

  1. # -*- mode: sh; sh-indentation: 4; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
  2. # Copyright (c) 2018 Sebastian Gniazdowski
  3. # Copyright (c) 2018 plexigras
  4. #
  5. # The old chroma function for command `git'. It colorizes the part of command
  6. # line that holds `git' invocation.
  7. #
  8. # $1 - 0 or 1, denoting if it's first call to the chroma, or following one
  9. # $2 - the current token, also accessible by $__arg from the above scope -
  10. # basically a private copy of $__arg
  11. # $3 - a private copy of $_start_pos, i.e. the position of the token in the
  12. # command line buffer, used to add region_highlight entry (see man),
  13. # because Zsh colorizes by *ranges* in command line buffer
  14. # $4 - a private copy of $_end_pos from the above scope
  15. #
  16. (( next_word = 2 | 8192 ))
  17. local __first_call="$1" __wrd="$2" __start_pos="$3" __end_pos="$4"
  18. local __style
  19. integer __idx1 __idx2
  20. local -a __lines_list chroma_git_remote_subcommands
  21. chroma_git_remote_subcommands=(add rename remove set-head set-branches get-url set-url set-url set-url show prune update)
  22. if (( __first_call )); then
  23. # Called for the first time - new command
  24. # FAST_HIGHLIGHT is used because it survives between calls, and
  25. # allows to use a single global hash only, instead of multiple
  26. # global variables
  27. FAST_HIGHLIGHT[chroma-git-counter]=0
  28. FAST_HIGHLIGHT[chroma-git-got-subcommand]=0
  29. FAST_HIGHLIGHT[chroma-git-subcommand]=""
  30. FAST_HIGHLIGHT[chrome-git-got-msg1]=0
  31. FAST_HIGHLIGHT[chrome-git-got-anymsg]=0
  32. FAST_HIGHLIGHT[chrome-git-occurred-double-hyphen]=0
  33. FAST_HIGHLIGHT[chroma-git-checkout-new]=0
  34. FAST_HIGHLIGHT[chroma-git-fetch-multiple]=0
  35. FAST_HIGHLIGHT[chroma-git-branch-change]=0
  36. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=0
  37. return 1
  38. else
  39. # Following call, i.e. not the first one
  40. # Check if chroma should end – test if token is of type
  41. # "starts new command", if so pass-through – chroma ends
  42. [[ "$__arg_type" = 3 ]] && return 2
  43. if [[ "$__wrd" = "--" ]]; then
  44. FAST_HIGHLIGHT[chrome-git-occurred-double-hyphen]=1
  45. __style=${FAST_THEME_NAME}double-hyphen-option
  46. elif [[ "$__wrd" = -* && ${FAST_HIGHLIGHT[chroma-git-got-subcommand]} -eq 0 ]]; then
  47. # Options occuring before a subcommand
  48. if (( FAST_HIGHLIGHT[chroma-git-option-with-argument-active] == 0 )); then
  49. if [[ "$__wrd" = -[^[:space:]-]#C ]]; then
  50. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=2
  51. elif [[ "$__wrd" = -[^[:space:]-]#c ]]; then
  52. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=1
  53. fi
  54. fi
  55. return 1
  56. else
  57. # If at e.g. '>' or destination/source spec (of the redirection)
  58. if (( in_redirection > 0 || this_word & 128 )) || [[ $__wrd == "<<<" ]]; then
  59. return 1
  60. # If at main git option taking argument in a separate word (-C and -c)
  61. elif (( FAST_HIGHLIGHT[chroma-git-option-with-argument-active] > 0 && \
  62. 0 == FAST_HIGHLIGHT[chroma-git-got-subcommand] ))
  63. then
  64. # Remember the value
  65. __idx2=${FAST_HIGHLIGHT[chroma-git-option-with-argument-active]}
  66. # Reset the is-argument mark-field
  67. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=0
  68. (( __idx2 == 2 )) && return 1
  69. # Other options' args (i.e. arg of -c) aren't routed to the big-loop
  70. # as they aren't paths and aren't handled in any special way there
  71. elif (( FAST_HIGHLIGHT[chroma-git-got-subcommand] == 0 )); then
  72. FAST_HIGHLIGHT[chroma-git-got-subcommand]=1
  73. # Check if the command is an alias - we want to highlight the
  74. # aliased command just like the target command of the alias
  75. .fast-run-command "git config --get-regexp 'alias.*'" chroma-git-alias-list "" $(( 10 * 60 ))
  76. # Grep for line: alias.{user-entered-subcmd}[[:space:]], and remove alias. prefix
  77. __lines_list=( ${${(M)__lines_list[@]:#alias.${__wrd}[[:space:]]##*}#alias.} )
  78. if (( ${#__lines_list} > 0 )); then
  79. # (*)
  80. # First remove alias name (#*[[:space:]]) and the space after it, then
  81. # remove any leading spaces from what's left (##[[:space:]]##), then
  82. # remove everything except the first word that's in the left line
  83. # (%%[[:space:]]##*, i.e.: "everything from right side up to any space")
  84. FAST_HIGHLIGHT[chroma-git-subcommand]="${${${__lines_list[1]#*[[:space:]]}##[[:space:]]##}%%[[:space:]]##*}"
  85. else
  86. FAST_HIGHLIGHT[chroma-git-subcommand]="$__wrd"
  87. fi
  88. if (( __start_pos >= 0 )); then
  89. # if subcommand exists
  90. LANG=C .fast-run-command "git help -a" chroma-git-subcmd-list "" $(( 10 * 60 ))
  91. # (s: :) will split on every space, but because the expression
  92. # isn't double-quoted, the empty elements will be eradicated
  93. # Some further knowledge-base: s-flag is special, it skips
  94. # empty elements and creates an array (not a concatenated
  95. # string) even when double-quoted. The normally needed @-flag
  96. # that logically breaks the concaetnated string back into array
  97. # in case of double-quoting has additional effect for s-flag:
  98. # it finally blocks empty-elements eradication.
  99. if [[ "${__lines_list[1]}" = See* ]]; then
  100. # (**)
  101. # git >= v2.20
  102. __lines_list=( ${(M)${${${(M)__lines_list[@]:# [[:blank:]]#[a-z]*}##[[:blank:]]##}%%[[:blank:]]##*}:#${FAST_HIGHLIGHT[chroma-git-subcommand]}} )
  103. else
  104. # (**)
  105. # git < v2.20
  106. __lines_list=( ${(M)${(s: :)${(M)__lines_list[@]:# [a-z]*}}:#${FAST_HIGHLIGHT[chroma-git-subcommand]}} )
  107. fi
  108. # Above we've checked:
  109. # 1) If given subcommand is an alias (*)
  110. # 2) If the command, or command pointed by the alias, exists (**)
  111. # 3) There's little problem, git v2.20 outputs aliases in git help -a,
  112. # which means that alias will be recognized as correct if it will
  113. # point at another alias or on itself. That's a minor problem, a
  114. # TODO for future planned optimization for v2.20 Git
  115. # 4) Notice that the above situation is better than the previous - the
  116. # alias is being verified to point to a valid git subcommand
  117. # That's all that's needed to decide on the correctnes:
  118. if (( ${#__lines_list} > 0 )); then
  119. __style=${FAST_THEME_NAME}subcommand
  120. else
  121. __style=${FAST_THEME_NAME}incorrect-subtle
  122. fi
  123. fi
  124. # The counter includes the subcommand itself
  125. (( FAST_HIGHLIGHT[chroma-git-counter] += 1 ))
  126. else
  127. __wrd="${__wrd//\`/x}"
  128. __arg="${__arg//\`/x}"
  129. __wrd="${(Q)__wrd}"
  130. if [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "push" \
  131. || "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "pull" \
  132. || "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "fetch" ]] \
  133. && (( ${FAST_HIGHLIGHT[chroma-git-fetch-multiple]} == 0 )); then
  134. # if not option
  135. if [[ "$__wrd" != -* || "${FAST_HIGHLIGHT[chrome-git-occurred-double-hyphen]}" -eq 1 ]]; then
  136. (( FAST_HIGHLIGHT[chroma-git-counter] += 1, __idx1 = FAST_HIGHLIGHT[chroma-git-counter] ))
  137. if (( __idx1 == 2 )); then
  138. .fast-run-git-command "git remote" "chroma-git-remotes" ""
  139. else
  140. __wrd="${__wrd%%:*}"
  141. .fast-run-git-command "git for-each-ref --format='%(refname:short)' refs/heads" "chroma-git-branches" "refs/heads"
  142. fi
  143. # if remote/ref exists
  144. if [[ -n ${__lines_list[(r)$__wrd]} ]]; then
  145. (( __start=__start_pos-${#PREBUFFER}, __end=__start_pos+${#__wrd}-${#PREBUFFER}, __start >= 0 )) && \
  146. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}correct-subtle]}")
  147. # if ref (__idx1 == 3) does not exist and subcommand is push
  148. elif (( __idx1 != 2 )) && [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "push" ]]; then
  149. (( __start=__start_pos-${#PREBUFFER}, __end=__start_pos+${#__wrd}-${#PREBUFFER}, __start >= 0 )) && \
  150. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}incorrect-subtle]}")
  151. # if not existing remote name, because not an URL (i.e. no colon)
  152. elif [[ $__idx1 -eq 2 && $__wrd != *:* ]]; then
  153. (( __start=__start_pos-${#PREBUFFER}, __end=__start_pos+${#__wrd}-${#PREBUFFER}, __start >= 0 )) && \
  154. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}incorrect-subtle]}")
  155. fi
  156. # if option
  157. else
  158. if [[ "$__wrd" = "--multiple" && "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "fetch" ]]; then
  159. FAST_HIGHLIGHT[chroma-git-fetch-multiple]=1
  160. __style=${FAST_THEME_NAME}double-hyphen-option
  161. else
  162. return 1
  163. fi
  164. fi
  165. elif (( ${FAST_HIGHLIGHT[chroma-git-fetch-multiple]} )) \
  166. && [[ "$__wrd" != -* || "${FAST_HIGHLIGHT[chrome-git-occurred-double-hyphen]}" -eq 1 ]]; then
  167. .fast-run-git-command "git remote" "chroma-git-remotes" ""
  168. if [[ -n ${__lines_list[(r)$__wrd]} ]]; then
  169. __style=${FAST_THEME_NAME}correct-subtle
  170. fi
  171. elif [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "commit" ]]; then
  172. match[1]=""
  173. match[2]=""
  174. # if previous argument is -m or current argument is --message=something
  175. if (( FAST_HIGHLIGHT[chrome-git-got-msg1] == 1 && ! FAST_HIGHLIGHT[chrome-git-got-anymsg] )) \
  176. || [[ "$__wrd" = (#b)(--message=)(*) && "${FAST_HIGHLIGHT[chrome-git-occurred-double-hyphen]}" = 0 ]]; then
  177. FAST_HIGHLIGHT[chrome-git-got-msg1]=0
  178. FAST_HIGHLIGHT[chrome-git-got-anymsg]=1
  179. if [[ -n "${match[1]}" ]]; then
  180. __wrd="${(Q)${match[2]//\`/x}}"
  181. # highlight (--message=)something
  182. (( __start=__start_pos-${#PREBUFFER}, __end=__start_pos-${#PREBUFFER}+10, __start >= 0 )) && \
  183. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-hyphen-option]}")
  184. # highlight --message=(something)
  185. (( __start=__start_pos-${#PREBUFFER}+10, __end=__end_pos-${#PREBUFFER}, __start >= 0 )) && \
  186. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-quoted-argument]}")
  187. else
  188. (( __start=__start_pos-${#PREBUFFER}, __end=__end_pos-${#PREBUFFER}, __start >= 0 )) && \
  189. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-quoted-argument]}")
  190. fi
  191. local __firstline=${__wrd%%$'\n'*}
  192. if (( ${#__firstline} > 50 )); then
  193. for (( __idx1 = 1, __idx2 = 1; __idx1 <= 50; ++ __idx1, ++ __idx2 )); do
  194. while [[ "${__arg[__idx2]}" != "${__firstline[__idx1]}" ]]; do
  195. (( ++ __idx2 ))
  196. (( __idx2 > __asize )) && { __idx2=-1; break; }
  197. done
  198. (( __idx2 == -1 )) && break
  199. done
  200. if (( __idx2 != -1 )); then
  201. if [[ -n "${match[1]}" ]]; then
  202. (( __start=__start_pos-${#PREBUFFER}+__idx2, __end=__end_pos-${#PREBUFFER}-$#__wrd+$#__firstline-1, __start >= 0 )) && \
  203. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}incorrect-subtle]}")
  204. else
  205. (( __start=__start_pos-${#PREBUFFER}+__idx2-1, __end=__end_pos-${#PREBUFFER}-$#__wrd+$#__firstline-1, __start >= 0 )) && \
  206. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}incorrect-subtle]}")
  207. fi
  208. fi
  209. fi
  210. # if before --
  211. elif [[ "${FAST_HIGHLIGHT[chrome-git-occurred-double-hyphen]}" = 0 ]]; then
  212. if [[ "$__wrd" = -[^[:space:]-]#m ]]; then
  213. FAST_HIGHLIGHT[chrome-git-got-msg1]=1
  214. __style=${FAST_THEME_NAME}single-hyphen-option
  215. else
  216. return 1
  217. fi
  218. # if after -- is file
  219. elif [[ -e "$__wrd" ]]; then
  220. __style=${FAST_THEME_NAME}path
  221. else
  222. __style=${FAST_THEME_NAME}incorrect-subtle
  223. fi
  224. elif [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "checkout" ]] \
  225. || [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "revert" ]] \
  226. || [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "merge" ]] \
  227. || [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "diff" ]] \
  228. || [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "reset" ]] \
  229. || [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "rebase" ]]; then
  230. # if doing `git checkout -b ...'
  231. if [[ "$__wrd" = -[^[:space:]-]#b && "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "checkout" ]]; then
  232. FAST_HIGHLIGHT[chroma-git-checkout-new]=1
  233. __style=${FAST_THEME_NAME}single-hyphen-option
  234. # if command is not checkout -b something
  235. elif [[ "${FAST_HIGHLIGHT[chroma-git-checkout-new]}" = 0 ]]; then
  236. # if not option
  237. if [[ "$__wrd" != -* || "${FAST_HIGHLIGHT[chrome-git-occurred-double-hyphen]}" = 1 ]]; then
  238. (( FAST_HIGHLIGHT[chroma-git-counter] += 1, __idx1 = FAST_HIGHLIGHT[chroma-git-counter] ))
  239. if (( __idx1 == 2 )) || \
  240. [[ "$__idx1" = 3 && "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "diff" ]]; then
  241. # if is ref
  242. if command git rev-parse --verify --quiet "$__wrd" >/dev/null 2>&1; then
  243. __style=${FAST_THEME_NAME}correct-subtle
  244. # if is file and subcommand is checkout or diff
  245. elif [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "checkout" \
  246. || "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "reset" \
  247. || "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "diff" ]] && [[ -e ${~__wrd} ]]; then
  248. __style=${FAST_THEME_NAME}path
  249. elif [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "checkout" && \
  250. "1" = "$(command git rev-list --count --no-walk --glob="refs/remotes/${$(git \
  251. config --get checkout.defaultRemote):-*}/$__wrd")" ]]
  252. then
  253. __style=${FAST_THEME_NAME}correct-subtle
  254. else
  255. __style=${FAST_THEME_NAME}incorrect-subtle
  256. fi
  257. fi
  258. # if option
  259. else
  260. return 1
  261. fi
  262. # if option
  263. elif [[ "${FAST_HIGHLIGHT[chrome-git-occurred-double-hyphen]}" = 0 && "$__wrd" = -* ]]; then
  264. return 1
  265. fi
  266. elif [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "remote" && "$__wrd" != -* ]]; then
  267. (( FAST_HIGHLIGHT[chroma-git-counter] += 1, __idx1 = FAST_HIGHLIGHT[chroma-git-counter] ))
  268. if [[ "$__idx1" = 2 ]]; then
  269. if (( ${chroma_git_remote_subcommands[(I)$__wrd]} )); then
  270. FAST_HIGHLIGHT[chroma-git-remote-subcommand]="$__wrd"
  271. __style=${FAST_THEME_NAME}subcommand
  272. else
  273. __style=${FAST_THEME_NAME}incorrect-subtle
  274. fi
  275. elif [[ "$__idx1" = 3 && "$FAST_HIGHLIGHT[chroma-git-remote-subcommand]" = "add" ]]; then
  276. .fast-run-git-command "git remote" "chroma-git-remotes" ""
  277. if [[ -n ${__lines_list[(r)$__wrd]} ]]; then
  278. __style=${FAST_THEME_NAME}incorrect-subtle
  279. fi
  280. elif [[ "$__idx1" = 3 && -n "$FAST_HIGHLIGHT[chroma-git-remote-subcommand]" ]]; then
  281. .fast-run-git-command "git remote" "chroma-git-remotes" ""
  282. if [[ -n ${__lines_list[(r)$__wrd]} ]]; then
  283. __style=${FAST_THEME_NAME}correct-subtle
  284. else
  285. __style=${FAST_THEME_NAME}incorrect-subtle
  286. fi
  287. fi
  288. elif [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "branch" ]]; then
  289. if [[ "$__wrd" = --delete \
  290. || "$__wrd" = --edit-description \
  291. || "$__wrd" = --set-upstream-to=* \
  292. || "$__wrd" = --unset-upstream \
  293. || "$__wrd" = -[^[:space:]-]#d \
  294. || "$__wrd" = -[^[:space:]-]#D ]]; then
  295. FAST_HIGHLIGHT[chroma-git-branch-change]=1
  296. return 1
  297. elif [[ "$__wrd" != -* ]]; then
  298. .fast-run-git-command "git for-each-ref --format='%(refname:short)' refs/heads" "chroma-git-branches" "refs/heads"
  299. if [[ -n ${__lines_list[(r)$__wrd]} ]]; then
  300. __style=${FAST_THEME_NAME}correct-subtle
  301. elif (( FAST_HIGHLIGHT[chroma-git-branch-change] )); then
  302. __style=${FAST_THEME_NAME}incorrect-subtle
  303. fi
  304. else
  305. return 1
  306. fi
  307. elif [[ "${FAST_HIGHLIGHT[chroma-git-subcommand]}" = "tag" ]]; then
  308. if [[ "${FAST_HIGHLIGHT[chroma-git-option-with-argument-active]}" -le 0 ]]; then
  309. if [[ "$__wrd" = -[^[:space:]-]#(u|m) ]]; then
  310. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=1
  311. elif [[ "$__wrd" = -[^[:space:]-]#F ]]; then
  312. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=2
  313. elif [[ "$__wrd" = -[^[:space:]-]#d ]]; then
  314. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=3
  315. elif [[ "$__wrd" = (--contains|--no-contains|--points-at|--merged|--no-merged) ]]; then
  316. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=4
  317. fi
  318. if [[ "$__wrd" != -* ]]; then
  319. (( FAST_HIGHLIGHT[chroma-git-counter] += 1, __idx1 = FAST_HIGHLIGHT[chroma-git-counter] ))
  320. if [[ ${FAST_HIGHLIGHT[chroma-git-counter]} -eq 2 ]]; then
  321. .fast-run-git-command "git for-each-ref --format='%(refname:short)' refs/heads" "chroma-git-branches" "refs/heads"
  322. .fast-run-git-command "+git tag" "chroma-git-tags" ""
  323. [[ -n ${__lines_list[(r)$__wrd]} ]] && __style=${FAST_THEME_NAME}incorrect-subtle
  324. elif [[ ${FAST_HIGHLIGHT[chroma-git-counter]} -eq 3 ]]; then
  325. fi
  326. else
  327. return 1
  328. fi
  329. else
  330. case "${FAST_HIGHLIGHT[chroma-git-option-with-argument-active]}" in
  331. (1)
  332. __style=${FAST_THEME_NAME}optarg-string
  333. ;;
  334. (2)
  335. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=0
  336. return 1;
  337. ;;
  338. (3)
  339. .fast-run-git-command "git tag" "chroma-git-tags" ""
  340. [[ -n ${__lines_list[(r)$__wrd]} ]] && \
  341. __style=${FAST_THEME_NAME}correct-subtle || \
  342. __style=${FAST_THEME_NAME}incorrect-subtle
  343. ;;
  344. (4)
  345. if git rev-parse --verify --quiet "$__wrd" >/dev/null 2>&1; then
  346. __style=${FAST_THEME_NAME}correct-subtle
  347. else
  348. __style=${FAST_THEME_NAME}incorrect-subtle
  349. fi
  350. ;;
  351. esac
  352. FAST_HIGHLIGHT[chroma-git-option-with-argument-active]=0
  353. fi
  354. else
  355. return 1
  356. fi
  357. fi
  358. fi
  359. fi
  360. # Add region_highlight entry (via `reply' array)
  361. if [[ -n "$__style" ]]; then
  362. (( __start=__start_pos-${#PREBUFFER}, __end=__end_pos-${#PREBUFFER}, __start >= 0 )) \
  363. && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
  364. fi
  365. # We aren't passing-through, do obligatory things ourselves
  366. (( this_word = next_word ))
  367. _start_pos=$_end_pos
  368. return 0
  369. # vim:ft=zsh:et:sw=4