zed.zsh 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. # vim: set filetype=zsh foldmethod=marker foldmarker=[[[,]]] :
  2. declare -gA ZED
  3. ZED[name]="${ZED[name]:-zed}"
  4. ZED[self]="${0:A}"
  5. ZED[CACHE_DIR]="${ZED[CACHE_DIR]:-${XDG_CACHE_HOME:-${HOME}/.cache}/zsh/.zed}"
  6. ZED[DATA_DIR]="${ZED[DATA_DIR]:-${XDG_DATA_HOME:-${HOME}/.local/share}/zsh/.zed}"
  7. # logging [[[
  8. function __zed_log_err() {
  9. echo $@ >&2
  10. }
  11. function __zed_log_info() {
  12. echo $@
  13. }
  14. # ]]]
  15. # completion [[[
  16. ZED[ZCOMPDUMP_PATH]="${ZED[ZCOMPDUMP_PATH]:-${ZDOTDIR:-$HOME}/.zcompdump}"
  17. function __zed_compinit() {
  18. if [[ -z ${ZED[ZCOMPDUMP_PATH]}(N.mh+24) ]] || [[ ! -e ${ZED[ZCOMPDUMP_PATH]} ]]; then
  19. compinit -d "${ZED[ZCOMPDUMP_PATH]}"
  20. if [[ ! -s "${ZED[ZCOMPDUMP_PATH]}.zwc" ]] || [[ "${ZED[ZCOMPDUMP_PATH]}" -nt "${ZED[ZCOMPDUMP_PATH]}.zwc" ]]; then
  21. zcompile "${ZED[ZCOMPDUMP_PATH]}"
  22. fi
  23. else
  24. compinit -C -d "${ZED[ZCOMPDUMP_PATH]}"
  25. fi
  26. }
  27. function __zed_compdef() {
  28. ZED_COMPDEF_REPLAY+=("${(j: :)${(q)@}}")
  29. }
  30. function __zed_compdef_intercept_on() {
  31. if (( ${+functions[compdef]} )); then
  32. ZED[function-compdef]="${functions[compdef]}"
  33. fi
  34. functions[compdef]='__zed_compdef "$@";'
  35. }
  36. function __zed_compdef_intercept_off() {
  37. if (( ${+ZED[function-compdef]} )); then
  38. functions[compdef]="${ZED[function-compdef]}"
  39. else
  40. unfunction compdef
  41. fi
  42. }
  43. function __zed_compdef_replay() {
  44. local compdef_entry pos
  45. for compdef_entry in ${ZED_COMPDEF_REPLAY[@]}; do
  46. pos=( "${(z)compdef_entry}" )
  47. if [[ ${#pos[@]} = 1 && -z ${pos[-1]} ]]; then
  48. continue
  49. fi
  50. pos=( "${(Q)pos[@]}" )
  51. compdef "${pos[@]}"
  52. done
  53. }
  54. # ]]]
  55. # registry [[[
  56. function :zed_plugin_registry() {
  57. local action="${1}"; shift
  58. local key val
  59. case ${action} in
  60. get)
  61. key="${1}"
  62. ZED_CTX=("${(@Q)${(@z)_zed_plugin_registry[${key}]}}")
  63. ;;
  64. set)
  65. key="${ZED_CTX[id]}"
  66. val="${(j: :)${(@qkv)ZED_CTX}}"
  67. _zed_plugin_registry[${key}]="${val}"
  68. ;;
  69. esac
  70. }
  71. # ]]]
  72. function :zed_install_or_update() {
  73. local plugin_dir="${ZED[DATA_DIR]}/plugins/${ZED_CTX[name]}"
  74. local name="${ZED_CTX[name]}"
  75. local src_uri="${ZED_CTX[src]}"
  76. __zed_log_info "${name} pulling..."
  77. if [[ "${ZED_CTX[src][1]}" = "/" ]] || [[ "${ZED_CTX[src][1]}" = "~" ]]; then
  78. ZED_CTX[from]="file"
  79. mkdir -p "${plugin_dir}"
  80. if [[ -f "${src_uri}" ]]; then
  81. cp "${src_uri}" "${plugin_dir}/${ZED_CTX[name]}.plugin.zsh"
  82. elif [[ -d "${src_uri}" ]]; then
  83. cp -r ${src_uri}/** "${plugin_dir}/"
  84. fi
  85. else
  86. ZED_CTX[from]="git"
  87. if [[ ${src_uri} != *://* ]]; then
  88. src_uri="https://${src_uri%.git}.git"
  89. fi
  90. if [[ -d "${plugin_dir}" ]]; then
  91. command git -C "${plugin_dir}" pull --quiet --recurse-submodules --rebase --autostash
  92. else
  93. mkdir -p "${plugin_dir:h}"
  94. command git -C "${plugin_dir:h}" clone --depth 1 --recursive --shallow-submodules "${src_uri}" "${plugin_dir:t}"
  95. fi
  96. fi
  97. if [[ $? -ne 0 ]]; then
  98. __zed_log_err "${name} pull failed"
  99. return 1
  100. fi
  101. __zed_log_info "${name} pulled"
  102. pushd -q "${plugin_dir}${ZED_CTX[dir]}"
  103. eval "${ZED_CTX[onpull]}"
  104. if [[ ! -f "${ZED_CTX[pick]}" ]]; then
  105. return 1
  106. fi
  107. local file
  108. for file in ${(s: :)${ZED_CTX[compile]:-${ZED_CTX[pick]}}}; do
  109. zcompile -U "${(e)file}"
  110. done
  111. popd -q
  112. }
  113. function _zed_list() {
  114. local -a items=(${(k)ZED[(I)plugin-*]#plugin-})
  115. print -l ${items[@]}
  116. }
  117. function _zed_pull() {
  118. local -a ids=($@)
  119. if [[ ${#ids[@]} -eq 0 ]]; then
  120. ids=($(_zed_list))
  121. fi
  122. local -A pulled_ids
  123. local id
  124. for id in ${ids[@]}; do
  125. :zed_plugin_registry get "${id}"
  126. if [[ -z "${pulled_ids[${ZED_CTX[name]}]}" ]]; then
  127. :zed_install_or_update
  128. fi
  129. pulled_ids[${ZED_CTX[name]}]=true
  130. done
  131. }
  132. function _zed_pull-self() {
  133. __zed_log_info "zed pulling..."
  134. command git -C "${ZED[self]:h}" pull --quiet --recurse-submodules --rebase --autostash
  135. __zed_log_info "zed pulled"
  136. zcompile -U "${ZED[self]}"
  137. }
  138. function _zed_load() {
  139. ZED_CTX[src]="${1}"; shift
  140. local ctx_key ctx_val
  141. while (( $# )); do
  142. ctx_key="${1%%:*}"
  143. ctx_val="${1#*:}"
  144. ZED_CTX[${ctx_key}]="${ctx_val}"
  145. shift
  146. done
  147. if [[ -z "${ZED_CTX[name]}" ]]; then
  148. ZED_CTX[name]="${${ZED_CTX[src]:t}%.git}"
  149. fi
  150. if [[ -z "${ZED_CTX[pick]}" ]]; then
  151. if [[ -z "${ZED_CTX[dir]}" ]]; then
  152. ZED_CTX[pick]="${ZED_CTX[name]}.plugin.zsh"
  153. else
  154. ZED_CTX[pick]="${ZED_CTX[dir]:t}.plugin.zsh"
  155. fi
  156. fi
  157. ZED_CTX[dir]="${ZED_CTX[dir]:+/${ZED_CTX[dir]}}"
  158. ZED_CTX[id]="${ZED_CTX[name]}${ZED_CTX[dir]:+:::${ZED_CTX[dir]:t}}"
  159. :zed_plugin_registry set
  160. local plugin_dir="${ZED[DATA_DIR]}/plugins/${ZED_CTX[name]}"
  161. if [[ ! -f "${plugin_dir}${ZED_CTX[dir]}/${ZED_CTX[pick]}" ]]; then
  162. :zed_install_or_update
  163. fi
  164. if [[ ! -f "${plugin_dir}${ZED_CTX[dir]}/${ZED_CTX[pick]}" ]]; then
  165. __zed_log_err "failed to load plugin:"
  166. __zed_log_err " ${ZED_CTX[src]} ${ZED_CTX[name]:+name:${ZED_CTX[name]}}"
  167. return 1
  168. fi
  169. fpath+="${plugin_dir}"
  170. if [[ -d "${plugin_dir}/functions" ]]; then
  171. fpath+="${plugin_dir}/functions"
  172. fi
  173. __zed_compdef_intercept_on
  174. source "${plugin_dir}${ZED_CTX[dir]}/${ZED_CTX[pick]}"
  175. if [[ -n "${ZED_CTX[onload]}" ]]; then
  176. eval "pushd -q ${plugin_dir}${ZED_CTX[dir]} && ${ZED_CTX[onload]} && popd -q"
  177. fi
  178. __zed_compdef_intercept_off
  179. ZED[plugin-${ZED_CTX[id]}]=true
  180. }
  181. function _zed_done() {
  182. __zed_compinit
  183. __zed_compdef_replay
  184. }
  185. function _zed_init() {
  186. declare -gA _zed_plugin_registry
  187. declare -ga ZED_COMPDEF_REPLAY
  188. if [[ ! -d "${ZED[CACHE_DIR]}" ]]; then
  189. mkdir -p "${ZED[CACHE_DIR]}"
  190. fi
  191. autoload -Uz compinit
  192. }
  193. function ${ZED[name]}() {
  194. local cmd="${1}"
  195. local REPLY
  196. if (( ${+functions[_zed_${cmd}]} )); then
  197. shift
  198. local -A ZED_CTX
  199. ZED_CTX=()
  200. _zed_${cmd} $@
  201. return $?
  202. else
  203. __zed_log_err "zed unknown command: ${cmd}"
  204. return 1
  205. fi
  206. }