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.

223 lines
8.9 KiB

преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 12 години
преди 13 години
преди 13 години
  1. #!/usr/bin/env zsh
  2. # -------------------------------------------------------------------------------------------------
  3. # Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without modification, are permitted
  7. # provided that the following conditions are met:
  8. #
  9. # * Redistributions of source code must retain the above copyright notice, this list of conditions
  10. # and the following disclaimer.
  11. # * Redistributions in binary form must reproduce the above copyright notice, this list of
  12. # conditions and the following disclaimer in the documentation and/or other materials provided
  13. # with the distribution.
  14. # * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
  15. # may be used to endorse or promote products derived from this software without specific prior
  16. # written permission.
  17. #
  18. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  19. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  20. # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  21. # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  24. # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  25. # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. # -------------------------------------------------------------------------------------------------
  27. # -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
  28. # vim: ft=zsh sw=2 ts=2 et
  29. # -------------------------------------------------------------------------------------------------
  30. # -------------------------------------------------------------------------------------------------
  31. # Core highlighting update system
  32. # -------------------------------------------------------------------------------------------------
  33. # Array declaring active highlighters names.
  34. typeset -ga ZSH_HIGHLIGHT_HIGHLIGHTERS
  35. # Update ZLE buffer syntax highlighting.
  36. #
  37. # Invokes each highlighter that needs updating.
  38. # This function is supposed to be called whenever the ZLE state changes.
  39. _zsh_highlight()
  40. {
  41. setopt localoptions nowarncreateglobal
  42. # Store the previous command return code to restore it whatever happens.
  43. local ret=$?
  44. # Do not highlight if there are more than 300 chars in the buffer. It's most
  45. # likely a pasted command or a huge list of files in that case..
  46. [[ -n ${ZSH_HIGHLIGHT_MAXLENGTH:-} ]] && [[ $#BUFFER -gt $ZSH_HIGHLIGHT_MAXLENGTH ]] && return $ret
  47. # Do not highlight if there are pending inputs (copy/paste).
  48. [[ $PENDING -gt 0 ]] && return $ret
  49. # Reset region highlight to build it from scratch
  50. region_highlight=();
  51. {
  52. local cache_place
  53. local -a region_highlight_copy
  54. # Select which highlighters in ZSH_HIGHLIGHT_HIGHLIGHTERS need to be invoked.
  55. local highlighter; for highlighter in $ZSH_HIGHLIGHT_HIGHLIGHTERS; do
  56. # eval cache place for current highlighter and prepare it
  57. cache_place="_zsh_highlight_${highlighter}_highlighter_cache"
  58. typeset -ga ${cache_place}
  59. # If highlighter needs to be invoked
  60. if "_zsh_highlight_${highlighter}_highlighter_predicate"; then
  61. # save a copy, and cleanup region_highlight
  62. region_highlight_copy=("${region_highlight[@]}")
  63. region_highlight=()
  64. # Execute highlighter and save result
  65. {
  66. "_zsh_highlight_${highlighter}_highlighter"
  67. } always {
  68. eval "${cache_place}=(\"\${region_highlight[@]}\")"
  69. }
  70. # Restore saved region_highlight
  71. region_highlight=("${region_highlight_copy[@]}")
  72. fi
  73. # Use value form cache if any cached
  74. eval "region_highlight+=(\"\${${cache_place}[@]}\")"
  75. done
  76. } always {
  77. _ZSH_HIGHLIGHT_PRIOR_BUFFER=$BUFFER
  78. _ZSH_HIGHLIGHT_PRIOR_CURSOR=$CURSOR
  79. return $ret
  80. }
  81. }
  82. # -------------------------------------------------------------------------------------------------
  83. # API/utility functions for highlighters
  84. # -------------------------------------------------------------------------------------------------
  85. # Array used by highlighters to declare user overridable styles.
  86. typeset -gA ZSH_HIGHLIGHT_STYLES
  87. # Whether the command line buffer has been modified or not.
  88. #
  89. # Returns 0 if the buffer has changed since _zsh_highlight was last called.
  90. _zsh_highlight_buffer_modified()
  91. {
  92. [[ "${_ZSH_HIGHLIGHT_PRIOR_BUFFER:-}" != "$BUFFER" ]]
  93. }
  94. # Whether the cursor has moved or not.
  95. #
  96. # Returns 0 if the cursor has moved since _zsh_highlight was last called.
  97. _zsh_highlight_cursor_moved()
  98. {
  99. [[ -n $CURSOR ]] && [[ -n ${_ZSH_HIGHLIGHT_PRIOR_CURSOR-} ]] && (($_ZSH_HIGHLIGHT_PRIOR_CURSOR != $CURSOR))
  100. }
  101. # -------------------------------------------------------------------------------------------------
  102. # Setup functions
  103. # -------------------------------------------------------------------------------------------------
  104. # Rebind all ZLE widgets to make them invoke _zsh_highlights.
  105. _zsh_highlight_bind_widgets()
  106. {
  107. # Load ZSH module zsh/zleparameter, needed to override user defined widgets.
  108. zmodload zsh/zleparameter 2>/dev/null || {
  109. echo 'zsh-syntax-highlighting: failed loading zsh/zleparameter.' >&2
  110. return 1
  111. }
  112. # Override ZLE widgets to make them invoke _zsh_highlight.
  113. local cur_widget
  114. for cur_widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|run-help|which-command|beep|yank*)}; do
  115. case $widgets[$cur_widget] in
  116. # Already rebound event: do nothing.
  117. user:$cur_widget|user:_zsh_highlight_widget_*);;
  118. # User defined widget: override and rebind old one with prefix "orig-".
  119. user:*) eval "zle -N orig-$cur_widget ${widgets[$cur_widget]#*:}; \
  120. _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \
  121. zle -N $cur_widget _zsh_highlight_widget_$cur_widget";;
  122. # Completion widget: override and rebind old one with prefix "orig-".
  123. completion:*) eval "zle -C orig-$cur_widget ${${widgets[$cur_widget]#*:}/:/ }; \
  124. _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \
  125. zle -N $cur_widget _zsh_highlight_widget_$cur_widget";;
  126. # Builtin widget: override and make it call the builtin ".widget".
  127. builtin) eval "_zsh_highlight_widget_$cur_widget() { builtin zle .$cur_widget -- \"\$@\" && _zsh_highlight }; \
  128. zle -N $cur_widget _zsh_highlight_widget_$cur_widget";;
  129. # Default: unhandled case.
  130. *) echo "zsh-syntax-highlighting: unhandled ZLE widget '$cur_widget'" >&2 ;;
  131. esac
  132. done
  133. }
  134. # Load highlighters from directory.
  135. #
  136. # Arguments:
  137. # 1) Path to the highlighters directory.
  138. _zsh_highlight_load_highlighters()
  139. {
  140. # Check the directory exists.
  141. [[ -d "$1" ]] || {
  142. echo "zsh-syntax-highlighting: highlighters directory '$1' not found." >&2
  143. return 1
  144. }
  145. # Load highlighters from highlighters directory and check they define required functions.
  146. local highlighter highlighter_dir
  147. for highlighter_dir ($1/*/); do
  148. highlighter="${highlighter_dir:t}"
  149. [[ -f "$highlighter_dir/${highlighter}-highlighter.zsh" ]] && {
  150. . "$highlighter_dir/${highlighter}-highlighter.zsh"
  151. type "_zsh_highlight_${highlighter}_highlighter" &> /dev/null &&
  152. type "_zsh_highlight_${highlighter}_highlighter_predicate" &> /dev/null || {
  153. echo "zsh-syntax-highlighting: '${highlighter}' highlighter should define both required functions '_zsh_highlight_${highlighter}_highlighter' and '_zsh_highlight_${highlighter}_highlighter_predicate' in '${highlighter_dir}/${highlighter}-highlighter.zsh'." >&2
  154. }
  155. }
  156. done
  157. }
  158. # -------------------------------------------------------------------------------------------------
  159. # Setup
  160. # -------------------------------------------------------------------------------------------------
  161. # Try binding widgets.
  162. _zsh_highlight_bind_widgets || {
  163. echo 'zsh-syntax-highlighting: failed binding ZLE widgets, exiting.' >&2
  164. return 1
  165. }
  166. # Resolve highlighters directory location.
  167. _zsh_highlight_load_highlighters "${ZSH_HIGHLIGHT_HIGHLIGHTERS_DIR:-${${0:A}:h}/highlighters}" || {
  168. echo 'zsh-syntax-highlighting: failed loading highlighters, exiting.' >&2
  169. return 1
  170. }
  171. # Reset scratch variables when commandline is done.
  172. _zsh_highlight_preexec_hook()
  173. {
  174. _ZSH_HIGHLIGHT_PRIOR_BUFFER=
  175. _ZSH_HIGHLIGHT_PRIOR_CURSOR=
  176. }
  177. autoload -U add-zsh-hook
  178. add-zsh-hook preexec _zsh_highlight_preexec_hook 2>/dev/null || {
  179. echo 'zsh-syntax-highlighting: failed loading add-zsh-hook.' >&2
  180. }
  181. # Initialize the array of active highlighters if needed.
  182. [[ $#ZSH_HIGHLIGHT_HIGHLIGHTERS -eq 0 ]] && ZSH_HIGHLIGHT_HIGHLIGHTERS=(main) || true