|
| 1 | +# ------------------------------------------------------------------------------------------------- |
| 2 | +# Copyright (c) 2010-2020 zsh-syntax-highlighting contributors |
| 3 | +# All rights reserved. |
| 4 | +# |
| 5 | +# Redistribution and use in source and binary forms, with or without modification, are permitted |
| 6 | +# provided that the following conditions are met: |
| 7 | +# |
| 8 | +# * Redistributions of source code must retain the above copyright notice, this list of conditions |
| 9 | +# and the following disclaimer. |
| 10 | +# * Redistributions in binary form must reproduce the above copyright notice, this list of |
| 11 | +# conditions and the following disclaimer in the documentation and/or other materials provided |
| 12 | +# with the distribution. |
| 13 | +# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors |
| 14 | +# may be used to endorse or promote products derived from this software without specific prior |
| 15 | +# written permission. |
| 16 | +# |
| 17 | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR |
| 18 | +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| 19 | +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| 20 | +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 21 | +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 22 | +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
| 23 | +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| 24 | +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 | +# ------------------------------------------------------------------------------------------------- |
| 26 | +# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- |
| 27 | +# vim: ft=zsh sw=2 ts=2 et |
| 28 | +# ------------------------------------------------------------------------------------------------- |
| 29 | + |
| 30 | +# Set $0 to the expected value, regardless of functionargzero. |
| 31 | +0=${(%):-%N} |
| 32 | +fpath+=(${0:P:h}) |
| 33 | +if true; then |
| 34 | + # $0 is reliable |
| 35 | + typeset -g ZSH_HIGHLIGHT_VERSION=$(<"${0:A:h}"/.version) |
| 36 | + typeset -g ZSH_HIGHLIGHT_REVISION=$(<"${0:A:h}"/.revision-hash) |
| 37 | + if [[ $ZSH_HIGHLIGHT_REVISION == \$Format:* ]]; then |
| 38 | + # When running from a source tree without 'make install', $ZSH_HIGHLIGHT_REVISION |
| 39 | + # would be set to '$Format:%H$' literally. That's an invalid value, and obtaining |
| 40 | + # the valid value (via `git rev-parse HEAD`, as Makefile does) might be costly, so: |
| 41 | + ZSH_HIGHLIGHT_REVISION=HEAD |
| 42 | + fi |
| 43 | +fi |
| 44 | + |
| 45 | +# This function takes a single argument F and returns True iff F is an autoload stub. |
| 46 | +_zsh_highlight__function_is_autoload_stub_p() { |
| 47 | + if zmodload -e zsh/parameter; then |
| 48 | + #(( ${+functions[$1]} )) && |
| 49 | + [[ "$functions[$1]" == *"builtin autoload -X"* ]] |
| 50 | + else |
| 51 | + #[[ $(type -wa -- "$1") == *'function'* ]] && |
| 52 | + [[ "${${(@f)"$(which -- "$1")"}[2]}" == $'\t'$histchars[3]' undefined' ]] |
| 53 | + fi |
| 54 | + # Do nothing here: return the exit code of the if. |
| 55 | +} |
| 56 | + |
| 57 | +# Return True iff the argument denotes a function name. |
| 58 | +_zsh_highlight__is_function_p() { |
| 59 | + if zmodload -e zsh/parameter; then |
| 60 | + (( ${+functions[$1]} )) |
| 61 | + else |
| 62 | + [[ $(type -wa -- "$1") == *'function'* ]] |
| 63 | + fi |
| 64 | +} |
| 65 | + |
| 66 | +# This function takes a single argument F and returns True iff F denotes the |
| 67 | +# name of a callable function. A function is callable if it is fully defined |
| 68 | +# or if it is marked for autoloading and autoloading it at the first call to it |
| 69 | +# will succeed. In particular, if a function has been marked for autoloading |
| 70 | +# but is not available in $fpath, then this function will return False therefor. |
| 71 | +# |
| 72 | +# See users/21671 http://www.zsh.org/cgi-bin/mla/redirect?USERNUMBER=21671 |
| 73 | +_zsh_highlight__function_callable_p() { |
| 74 | + if _zsh_highlight__is_function_p "$1" && |
| 75 | + ! _zsh_highlight__function_is_autoload_stub_p "$1" |
| 76 | + then |
| 77 | + # Already fully loaded. |
| 78 | + return 0 # true |
| 79 | + else |
| 80 | + # "$1" is either an autoload stub, or not a function at all. |
| 81 | + # |
| 82 | + # Use a subshell to avoid affecting the calling shell. |
| 83 | + # |
| 84 | + # We expect 'autoload +X' to return non-zero if it fails to fully load |
| 85 | + # the function. |
| 86 | + ( autoload -U +X -- "$1" 2>/dev/null ) |
| 87 | + return $? |
| 88 | + fi |
| 89 | +} |
| 90 | + |
| 91 | +# ------------------------------------------------------------------------------------------------- |
| 92 | +# Core highlighting update system |
| 93 | +# ------------------------------------------------------------------------------------------------- |
| 94 | + |
| 95 | +# Use workaround for bug in ZSH? |
| 96 | +# zsh-users/zsh@48cadf4 http://www.zsh.org/mla/workers//2017/msg00034.html |
| 97 | +autoload -Uz is-at-least |
| 98 | +if is-at-least 5.4; then |
| 99 | + typeset -g zsh_highlight__pat_static_bug=false |
| 100 | +else |
| 101 | + typeset -g zsh_highlight__pat_static_bug=true |
| 102 | +fi |
| 103 | + |
| 104 | +# Array declaring active highlighters names. |
| 105 | +typeset -ga ZSH_HIGHLIGHT_HIGHLIGHTERS |
| 106 | + |
| 107 | + |
| 108 | +# ------------------------------------------------------------------------------------------------- |
| 109 | +# API/utility functions for highlighters |
| 110 | +# ------------------------------------------------------------------------------------------------- |
| 111 | + |
| 112 | +# Array used by highlighters to declare user overridable styles. |
| 113 | +typeset -gA ZSH_HIGHLIGHT_STYLES |
| 114 | + |
| 115 | +# Whether the command line buffer has been modified or not. |
| 116 | +# |
| 117 | +# Returns 0 if the buffer has changed since _zsh_highlight was last called. |
| 118 | +_zsh_highlight_buffer_modified() |
| 119 | +{ |
| 120 | + [[ "${_ZSH_HIGHLIGHT_PRIOR_BUFFER:-}" != "$BUFFER" ]] |
| 121 | +} |
| 122 | + |
| 123 | +# Whether the cursor has moved or not. |
| 124 | +# |
| 125 | +# Returns 0 if the cursor has moved since _zsh_highlight was last called. |
| 126 | +_zsh_highlight_cursor_moved() |
| 127 | +{ |
| 128 | + [[ -n $CURSOR ]] && [[ -n ${_ZSH_HIGHLIGHT_PRIOR_CURSOR-} ]] && (($_ZSH_HIGHLIGHT_PRIOR_CURSOR != $CURSOR)) |
| 129 | +} |
| 130 | + |
| 131 | +# Add a highlight defined by ZSH_HIGHLIGHT_STYLES. |
| 132 | +# |
| 133 | +# Should be used by all highlighters aside from 'pattern' (cf. ZSH_HIGHLIGHT_PATTERN). |
| 134 | +# Overwritten in tests/test-highlighting.zsh when testing. |
| 135 | +_zsh_highlight_add_highlight() |
| 136 | +{ |
| 137 | + local -i start end |
| 138 | + local highlight |
| 139 | + start=$1 |
| 140 | + end=$2 |
| 141 | + shift 2 |
| 142 | + for highlight; do |
| 143 | + if (( $+ZSH_HIGHLIGHT_STYLES[$highlight] )); then |
| 144 | + region_highlight+=("$start $end $ZSH_HIGHLIGHT_STYLES[$highlight], memo=zsh-syntax-highlighting") |
| 145 | + break |
| 146 | + fi |
| 147 | + done |
| 148 | +} |
| 149 | + |
| 150 | +# ------------------------------------------------------------------------------------------------- |
| 151 | +# Setup functions |
| 152 | +# ------------------------------------------------------------------------------------------------- |
| 153 | + |
| 154 | +# Load highlighters from directory. |
| 155 | +# |
| 156 | +# Arguments: |
| 157 | +# 1) Path to the highlighters directory. |
| 158 | +_zsh_highlight_load_highlighters() |
| 159 | +{ |
| 160 | + setopt localoptions noksharrays bareglobqual |
| 161 | + |
| 162 | + # Check the directory exists. |
| 163 | + [[ -d "$1" ]] || { |
| 164 | + print -r -- >&2 "zsh-syntax-highlighting: highlighters directory ${(qq)1} not found." |
| 165 | + return 1 |
| 166 | + } |
| 167 | + |
| 168 | + # Load highlighters from highlighters directory and check they define required functions. |
| 169 | + local highlighter highlighter_dir |
| 170 | + for highlighter_dir ($1/*/(/)); do |
| 171 | + highlighter="${highlighter_dir:t}" |
| 172 | + [[ -f "$highlighter_dir${highlighter}-highlighter.zsh" ]] && |
| 173 | + . "$highlighter_dir${highlighter}-highlighter.zsh" |
| 174 | + if [[ -f "${highlighter_dir}_zsh_highlight_highlighter_${highlighter}_paint" ]] && |
| 175 | + [[ -f "${highlighter_dir}_zsh_highlight_highlighter_${highlighter}_predicate" ]]; then |
| 176 | + # New (0.8.0) autoload style highlighter |
| 177 | + fpath+=(${highlighter_dir%/}) |
| 178 | + autoload -Uz "_zsh_highlight_highlighter_${highlighter}_paint" "_zsh_highlight_highlighter_${highlighter}_predicate" |
| 179 | + else |
| 180 | + if type "_zsh_highlight_highlighter_${highlighter}_paint" &> /dev/null && |
| 181 | + type "_zsh_highlight_highlighter_${highlighter}_predicate" &> /dev/null; |
| 182 | + then |
| 183 | + # New (0.5.0) function names |
| 184 | + elif type "_zsh_highlight_${highlighter}_highlighter" &> /dev/null && |
| 185 | + type "_zsh_highlight_${highlighter}_highlighter_predicate" &> /dev/null; |
| 186 | + then |
| 187 | + # Old (0.4.x) function names |
| 188 | + if false; then |
| 189 | + # TODO: only show this warning for plugin authors/maintainers, not for end users |
| 190 | + print -r -- >&2 "zsh-syntax-highlighting: warning: ${(qq)highlighter} highlighter uses deprecated entry point names; please ask its maintainer to update it: https://github.com/zsh-users/zsh-syntax-highlighting/issues/329" |
| 191 | + fi |
| 192 | + # Make it work. |
| 193 | + eval "_zsh_highlight_highlighter_${(q)highlighter}_paint() { _zsh_highlight_${(q)highlighter}_highlighter \"\$@\" }" |
| 194 | + eval "_zsh_highlight_highlighter_${(q)highlighter}_predicate() { _zsh_highlight_${(q)highlighter}_highlighter_predicate \"\$@\" }" |
| 195 | + else |
| 196 | + print -r -- >&2 "zsh-syntax-highlighting: ${(qq)highlighter} highlighter should define both required functions '_zsh_highlight_highlighter_${highlighter}_paint' and '_zsh_highlight_highlighter_${highlighter}_predicate' in ${(qq):-"$highlighter_dir${highlighter}-highlighter.zsh"}." |
| 197 | + fi |
| 198 | + fi |
| 199 | + done |
| 200 | +} |
| 201 | + |
| 202 | + |
| 203 | +# ------------------------------------------------------------------------------------------------- |
| 204 | +# Setup |
| 205 | +# ------------------------------------------------------------------------------------------------- |
| 206 | + |
| 207 | +autoload -Uz _zsh_highlight_internal |
| 208 | + |
| 209 | +# Resolve highlighters directory location. |
| 210 | +_zsh_highlight_load_highlighters "${ZSH_HIGHLIGHT_HIGHLIGHTERS_DIR:-${${0:A}:h}/highlighters}" || { |
| 211 | + print -r -- >&2 'zsh-syntax-highlighting: failed loading highlighters, exiting.' |
| 212 | + return 1 |
| 213 | +} |
| 214 | + |
| 215 | +# Reset scratch variables when commandline is done. |
| 216 | +_zsh_highlight_preexec_hook() |
| 217 | +{ |
| 218 | + typeset -g _ZSH_HIGHLIGHT_PRIOR_BUFFER= |
| 219 | + typeset -gi _ZSH_HIGHLIGHT_PRIOR_CURSOR= |
| 220 | +} |
| 221 | +autoload -Uz add-zsh-hook |
| 222 | +add-zsh-hook preexec _zsh_highlight_preexec_hook 2>/dev/null || { |
| 223 | + print -r -- >&2 'zsh-syntax-highlighting: failed loading add-zsh-hook.' |
| 224 | + } |
| 225 | + |
| 226 | +# Load zsh/parameter module if available |
| 227 | +zmodload zsh/parameter 2>/dev/null || true |
| 228 | + |
| 229 | +# Initialize the array of active highlighters if needed. |
| 230 | +[[ $#ZSH_HIGHLIGHT_HIGHLIGHTERS -eq 0 ]] && ZSH_HIGHLIGHT_HIGHLIGHTERS=(main) |
| 231 | + |
| 232 | +if (( $+X_ZSH_HIGHLIGHT_DIRS_BLACKLIST )); then |
| 233 | + print >&2 'zsh-syntax-highlighting: X_ZSH_HIGHLIGHT_DIRS_BLACKLIST is deprecated. Please use ZSH_HIGHLIGHT_DIRS_BLACKLIST.' |
| 234 | + ZSH_HIGHLIGHT_DIRS_BLACKLIST=($X_ZSH_HIGHLIGHT_DIRS_BLACKLIST) |
| 235 | + unset X_ZSH_HIGHLIGHT_DIRS_BLACKLIST |
| 236 | +fi |
0 commit comments