diff --git a/README.md b/README.md index 7546395fe..e663e32c6 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,21 @@ -zsh-syntax-highlighting -======================= +Fork of zsh-syntax-highlighting +=============================== -**[Fish shell](http://www.fishshell.com) like syntax highlighting for [Zsh](http://www.zsh.org).** +**THIS FORK IS NO LONGER MAINTAINED. +YOU MAY WANT TO TEST ITS SUCCESSOR: [chromatic-zsh](https://github.com/jimmijj/chromatic-zsh) +YOU MAY WANT TO TEST THE PARENT PROJECT: [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting)** -*Requirements: zsh 4.3.17+.* +Enhanced highlighting of the [Zsh](http://www.zsh.org) command-line, including syntax, paths, files, selected regions, searched patterns and much more. + +![](misc/screenshot.png) How to install -------------- -### Using packages - -* Arch Linux: [community/zsh-syntax-highlighting](https://www.archlinux.org/packages/zsh-syntax-highlighting) / [AUR/zsh-syntax-highlighting-git](https://aur.archlinux.org/packages/zsh-syntax-highlighting-git) -* Gentoo: [mv overlay](http://gpo.zugaina.org/app-shells/zsh-syntax-highlighting) - -### In your ~/.zshrc - * Download the script or clone this repository: - git clone git://github.com/zsh-users/zsh-syntax-highlighting.git + git clone git://github.com/jimmijj/zsh-syntax-highlighting.git * Source the script **at the end** of `~/.zshrc`: @@ -28,23 +25,6 @@ How to install source ~/.zshrc - -### With oh-my-zsh - -* Download the script or clone this repository in [oh-my-zsh](http://github.com/robbyrussell/oh-my-zsh) plugins directory: - - cd ~/.oh-my-zsh/custom/plugins - git clone git://github.com/zsh-users/zsh-syntax-highlighting.git - -* Activate the plugin in `~/.zshrc` (in **last** position): - - plugins=( [plugins...] zsh-syntax-highlighting) - -* Source `~/.zshrc` to take changes into account: - - source ~/.zshrc - - How to tweak ------------ diff --git a/highlighters/main/README.md b/highlighters/main/README.md index df0c195c4..ebb8e8f22 100644 --- a/highlighters/main/README.md +++ b/highlighters/main/README.md @@ -7,6 +7,7 @@ This is the ***main*** highlighter, that highlights: * Options * Arguments * Paths +* Files * Strings How to activate it @@ -28,8 +29,10 @@ This highlighter defines the following styles: * `builtin` - shell builtin commands * `function` - functions * `command` - commands +* `command_prefix` - command prefixes * `precommand` - precommands (i.e. exec, builtin, ...) * `commandseparator` - command separation tokens +* `redirection` - redirection operators * `hashed-command` - hashed commands * `path` - paths * `path_prefix` - path prefixes @@ -44,6 +47,10 @@ This highlighter defines the following styles: * `dollar-double-quoted-argument` - dollar double quoted arguments * `back-double-quoted-argument` - back double quoted arguments * `assign` - variable assignments +* `isearch` - matched string in history-incremental-search* widgets +* `region` - selected region (between the point and the mark) +* `special` - unprintable characters +* `suffix` - suffix characters used in the completion system * `default` - parts of the buffer that do not match anything To override one of those styles, change its entry in `ZSH_HIGHLIGHT_STYLES`, for example in `~/.zshrc`: @@ -58,3 +65,28 @@ To override one of those styles, change its entry in `ZSH_HIGHLIGHT_STYLES`, for ZSH_HIGHLIGHT_STYLES[globbing]='none' The syntax for declaring styles is [documented here](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#SEC135). + + +By default files are colored in the same fashion as `ls` command, namely by comparing file attributes and extension with the content of LS_COLORS environment variable. To override this behaviour change the value of ZSH_HIGHLIGHT_STYLES[file] in ~/.zshrc: + + # To have all files in one color irrespectively of attributes and extensions + ZSH_HIGHLIGHT_STYLES[file]='fg=green' + + # To disable higlighting for all files + ZSH_HIGHLIGHT_STYLES[file]='none' + + # To use LS_COLORS do not set this style at all + # ZSH_HIGHLIGHT_STYLES[file] + +It is also possible to change the color for one single file attribute/extenstion. To achieve this modify ZSH_HIGHLIGHT_FILES in ~/.zshrc: + + # To set color for executables + ZSH_HIGHLIGHT_FILES[ex]='fg=119' + + # To set color for files with sticky bit + ZSH_HIGHLIGHT_FILES[st]='fg=7,bg=4' + + # To set color for files with pdf extenstion + ZSH_HIGHLIGHT_FILES[*.pdf]='fg=34' + +Note that LS_COLORS uses ANSI color codes (not names as 'green') and so does ZSH_HIGHLIGHT_FILES by default, but ZSH_HIGHLIGHT_FILES[*.pdf]='fg=green' is possible too. However if you set color code by hand you must guarantee that your terminal is capable to display that color properly. In above examples 256 color palette is used. In case of doubt it is better not to set ZSH_HIGHLIGHT_STYLES[file] and change LS_COLORS via ~/.dircolors file. If ~/.dircolors files doesn't exist one can generate it by `dircolor` command. diff --git a/highlighters/main/main-highlighter.zsh b/highlighters/main/main-highlighter.zsh index 5b038b4bc..1ebcd4f38 100755 --- a/highlighters/main/main-highlighter.zsh +++ b/highlighters/main/main-highlighter.zsh @@ -37,12 +37,15 @@ : ${ZSH_HIGHLIGHT_STYLES[builtin]:=fg=green} : ${ZSH_HIGHLIGHT_STYLES[function]:=fg=green} : ${ZSH_HIGHLIGHT_STYLES[command]:=fg=green} +: ${ZSH_HIGHLIGHT_STYLES[command_prefix]:=fg=green} : ${ZSH_HIGHLIGHT_STYLES[precommand]:=fg=green,underline} : ${ZSH_HIGHLIGHT_STYLES[commandseparator]:=none} +: ${ZSH_HIGHLIGHT_STYLES[redirection]:=fg=magenta} : ${ZSH_HIGHLIGHT_STYLES[hashed-command]:=fg=green} : ${ZSH_HIGHLIGHT_STYLES[path]:=underline} : ${ZSH_HIGHLIGHT_STYLES[path_prefix]:=underline} : ${ZSH_HIGHLIGHT_STYLES[path_approx]:=fg=yellow,underline} +: ${ZSH_HIGHLIGHT_STYLES[file]:=} : ${ZSH_HIGHLIGHT_STYLES[globbing]:=fg=blue} : ${ZSH_HIGHLIGHT_STYLES[history-expansion]:=fg=blue} : ${ZSH_HIGHLIGHT_STYLES[single-hyphen-option]:=none} @@ -53,6 +56,10 @@ : ${ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]:=fg=cyan} : ${ZSH_HIGHLIGHT_STYLES[back-double-quoted-argument]:=fg=cyan} : ${ZSH_HIGHLIGHT_STYLES[assign]:=none} +: ${ZSH_HIGHLIGHT_STYLES[isearch]:=fg=yellow,bg=red,bold} +: ${ZSH_HIGHLIGHT_STYLES[region]:=bg=blue} +: ${ZSH_HIGHLIGHT_STYLES[special]:=none} +: ${ZSH_HIGHLIGHT_STYLES[suffix]:=none} # Whether the highlighter should be called or not. _zsh_highlight_main_highlighter_predicate() @@ -60,19 +67,48 @@ _zsh_highlight_main_highlighter_predicate() _zsh_highlight_buffer_modified } +## In case we need to highlight in other circumstances then default from highlighter_predicate lets define a switcher +_zsh_highlight_main_highlighter_predicate_switcher() +{ + case $1 in + 'b') # buffer + _zsh_highlight_main_highlighter_predicate() + { + _zsh_highlight_buffer_modified + };; + 'c') # cursor + _zsh_highlight_main_highlighter_predicate() + { + _zsh_highlight_cursor_moved + };; + 'bc') bccounter=0 # buffer and cursor + _zsh_highlight_main_highlighter_predicate() + { + bccounter=$((bccounter+1)) + (( $bccounter > 1 )) && _zsh_highlight_main_highlighter_predicate_switcher b + _zsh_highlight_cursor_moved || _zsh_highlight_buffer_modified + };; + *);; + esac +} + # Main syntax highlighting function. _zsh_highlight_main_highlighter() { emulate -L zsh setopt localoptions extendedglob bareglobqual - local start_pos=0 end_pos highlight_glob=true new_expression=true arg style sudo=false sudo_arg=false + local start_pos=0 end_pos highlight_glob=true new_expression=true arg style lsstyle start_file_pos end_file_pos sudo=false sudo_arg=false typeset -a ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR + typeset -a ZSH_HIGHLIGHT_TOKENS_REDIRECTION typeset -a ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS typeset -a ZSH_HIGHLIGHT_TOKENS_FOLLOWED_BY_COMMANDS region_highlight=() ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR=( - '|' '||' ';' '&' '&&' + '|' '||' ';' '&' '&&' '&|' '|&' '&!' + ) + ZSH_HIGHLIGHT_TOKENS_REDIRECTION=( + '<' '<>' '>' '>|' '>!' '>>' '>>|' '>>!' '<<' '<<-' '<<<' '<&' '>&' '<& -' '>& -' '<& p' '>& p' '&>' '>&|' '>&!' '&>|' '&>!' '>>&' '&>>' '>>&|' '>>&!' '&>>|' '&>>!' ) ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS=( 'builtin' 'command' 'exec' 'nocorrect' 'noglob' @@ -82,12 +118,19 @@ _zsh_highlight_main_highlighter() $ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR $ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS ) + splitbuf1=(${(z)BUFFER}) + splitbuf2=(${(z)BUFFER//$'\n'/ \$\'\\\\n\' }) # ugly hack, but I have no other idea + local argnum=0 for arg in ${(z)BUFFER}; do - local substr_color=0 + argnum=$((argnum+1)) + if [[ $splitbuf1[$argnum] != $splitbuf2[$argnum] ]] && new_expression=true && continue + + local substr_color=0 isfile=false local style_override="" [[ $start_pos -eq 0 && $arg = 'noglob' ]] && highlight_glob=false ((start_pos+=${#BUFFER[$start_pos+1,-1]}-${#${BUFFER[$start_pos+1,-1]##[[:space:]]#}})) ((end_pos=$start_pos+${#arg})) + # Parse the sudo command line if $sudo; then case "$arg" in @@ -126,13 +169,20 @@ _zsh_highlight_main_highlighter() *) if _zsh_highlight_main_highlighter_check_assign; then style=$ZSH_HIGHLIGHT_STYLES[assign] new_expression=true + elif _zsh_highlight_main_highlighter_check_command; then + style=$ZSH_HIGHLIGHT_STYLES[command_prefix] elif _zsh_highlight_main_highlighter_check_path; then style=$ZSH_HIGHLIGHT_STYLES[path] elif [[ $arg[0,1] == $histchars[0,1] || $arg[0,1] == $histchars[2,2] ]]; then style=$ZSH_HIGHLIGHT_STYLES[history-expansion] + elif [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR:#"$arg"} ]]; then + style=$ZSH_HIGHLIGHT_STYLES[commandseparator] + elif [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_REDIRECTION:#"$arg"} ]]; then + style=$ZSH_HIGHLIGHT_STYLES[redirection] else style=$ZSH_HIGHLIGHT_STYLES[unknown-token] fi + _zsh_highlight_main_highlighter_check_file && isfile=true ;; esac fi @@ -154,17 +204,26 @@ _zsh_highlight_main_highlighter() style=$ZSH_HIGHLIGHT_STYLES[history-expansion] elif [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR:#"$arg"} ]]; then style=$ZSH_HIGHLIGHT_STYLES[commandseparator] + elif [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_REDIRECTION:#"$arg"} ]]; then + style=$ZSH_HIGHLIGHT_STYLES[redirection] else style=$ZSH_HIGHLIGHT_STYLES[default] fi + _zsh_highlight_main_highlighter_check_file && isfile=true ;; esac fi # if a style_override was set (eg in _zsh_highlight_main_highlighter_check_path), use it [[ -n $style_override ]] && style=$ZSH_HIGHLIGHT_STYLES[$style_override] + if [[ $isfile == true ]]; then + start_file_pos=$((start_pos+${#arg}-${#arg:t})) + end_file_pos=$end_pos + end_pos=$((end_pos-${#arg:t})) + region_highlight+=("$start_file_pos $end_file_pos $lsstyle") + fi [[ $substr_color = 0 ]] && region_highlight+=("$start_pos $end_pos $style") [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_FOLLOWED_BY_COMMANDS:#"$arg"} ]] && new_expression=true - start_pos=$end_pos + [[ $isfile == true ]] && start_pos=$end_file_pos || start_pos=$end_pos done } @@ -188,14 +247,14 @@ _zsh_highlight_main_highlighter_check_path() [[ -e "$cdpath_dir/$expanded_path" ]] && return 0 done [[ ! -e ${expanded_path:h} ]] && return 1 - if [[ ${BUFFER[1]} != "-" && ${#BUFFER} == $end_pos ]]; then + if [[ ${BUFFER[1]} != "-" && ${#LBUFFER} == $end_pos ]]; then local -a tmp # got a path prefix? tmp=( ${expanded_path}*(N) ) - (( $#tmp > 0 )) && style_override=path_prefix && return 0 + (( $#tmp > 0 )) && style_override=path_prefix && _zsh_highlight_main_highlighter_predicate_switcher bc && return 0 # or maybe an approximate path? tmp=( (#a1)${expanded_path}*(N) ) - (( $#tmp > 0 )) && style_override=path_approx && return 0 + (( $#arg > 3 && $#tmp > 0 )) && style_override=path_approx && return 0 fi return 1 } @@ -238,3 +297,95 @@ _zsh_highlight_main_highlighter_highlight_string() region_highlight+=("$j $k $style") done } + +## Check if command with given prefix exists +_zsh_highlight_main_highlighter_check_command() +{ + setopt localoptions nonomatch + local -a prefixed_command + [[ $arg != $arg:t ]] && return 1 # don't match anything if explicit path is present + for p in $path; do prefixed_command+=( $p/${arg}*(N) ); done + [[ ${BUFFER[1]} != "-" && ${#LBUFFER} == $end_pos && $#prefixed_command > 0 ]] && return 0 || return 1 +} + +## Fill table with colors and file types from $LS_COLORS +_zsh_highlight_files_highlighter_fill_table_of_types() +{ + local group type code ncolors=$(echotc Co) + local -a attrib + + for group in ${(s.:.)LS_COLORS}; do + type=${group%=*} + code=${group#*=} + attrib=() + takeattrib ${(s.;.)code} + ZSH_HIGHLIGHT_FILES+=($type ${(j.,.)attrib}) + done +} + +## Take attributes from unfolded $LS_COLORS code +takeattrib() +{ + while [ "$#" -gt 0 ]; do + [[ $1 == 38 && $2 == 5 ]] && {attrib+=("fg=$3"); shift 3; continue} + [[ $1 == 48 && $2 == 5 ]] && {attrib+=("bg=$3"); shift 3; continue} + case $1 in + 00|0) attrib+=("none"); shift;; + 01|1) attrib+=("bold" ); shift;; + 02|2) attrib+=("faint"); shift;; + 03|3) attrib+=("italic"); shift;; + 04|4) attrib+=("underscore"); shift;; + 05|5) attrib+=("blink"); shift;; + 07|7) attrib+=("standout"); shift;; + 08|8) attrib+=("concealed"); shift;; + 3[0-7]) attrib+=("fg=$(($1-30))"); shift;; + 4[0-7]) attrib+=("bg=$(($1-40))"); shift;; + 9[0-7]) [[ $ncolors == 256 ]] && attrib+=("fg=$(($1-82))") || attrib+=("fg=$(($1-90))" "bold"); shift;; + 10[0-7]) [[ $ncolors == 256 ]] && attrib+=("bg=$(($1-92))") || attrib+=("bg=$(($1-100))" "bold"); shift;; + *) shift;; + esac + done +} + +## Check if the argument is a file, if yes change the style accordingly +_zsh_highlight_main_highlighter_check_file() +{ + setopt localoptions nonomatch + local expanded_arg matched_file + + expanded_arg=${(Q)~arg} + [[ -z $expanded_arg ]] && return 1 + [[ -d $expanded_arg ]] && return 1 + [[ ${BUFFER[1]} != "-" && ${#LBUFFER} == $end_pos ]] && matched_file=(${expanded_arg}*(Noa^/[1])) + [[ -e $expanded_arg || -e $matched_file ]] && lsstyle=none || return 1 + [[ -e $matched_file ]] && _zsh_highlight_main_highlighter_predicate_switcher bc + + [[ ! -z $ZSH_HIGHLIGHT_STYLES[file] ]] && lsstyle=$ZSH_HIGHLIGHT_STYLES[file] && return 0 + + # [[ rs ]] + # [[ -d $expanded_arg || -d $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[di] && return 0 + [[ -h $expanded_arg || -h $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[ln] && return 0 + # [[ mh ]] + [[ -p $expanded_arg || -p $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[pi] && return 0 + [[ -S $expanded_arg || -S $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[so] && return 0 + # [[ do ]] + [[ -b $expanded_arg || -b $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[bd] && return 0 + [[ -c $expanded_arg || -c $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[cd] && return 0 + # [[ or ]] + # [[ mi ]] + [[ -u $expanded_arg || -u $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[su] && return 0 + [[ -g $expanded_arg || -g $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[sg] && return 0 + # [[ ca ]] + # [[ tw ]] + # [[ ow ]] + [[ -k $expanded_arg || -k $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[st] && return 0 + [[ -x $expanded_arg || -x $matched_file ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[ex] && return 0 + + [[ -e $expanded_arg ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[*.$expanded_arg:e] && return 0 + [[ -n $matched_file:e ]] && lsstyle=$ZSH_HIGHLIGHT_FILES[*.$matched_file:e] && return 0 + + return 0 +} + +## Fill table only once, at the initialization process +_zsh_highlight_files_highlighter_fill_table_of_types diff --git a/misc/screenshot.png b/misc/screenshot.png new file mode 100644 index 000000000..e68fadb04 Binary files /dev/null and b/misc/screenshot.png differ diff --git a/zsh-syntax-highlighting.zsh b/zsh-syntax-highlighting.zsh index 937e42645..09edcd319 100644 --- a/zsh-syntax-highlighting.zsh +++ b/zsh-syntax-highlighting.zsh @@ -42,61 +42,68 @@ typeset -ga ZSH_HIGHLIGHT_HIGHLIGHTERS # This function is supposed to be called whenever the ZLE state changes. _zsh_highlight() { - setopt localoptions nowarncreateglobal - - # Store the previous command return code to restore it whatever happens. - local ret=$? - - # Do not highlight if there are more than 300 chars in the buffer. It's most - # likely a pasted command or a huge list of files in that case.. - [[ -n ${ZSH_HIGHLIGHT_MAXLENGTH:-} ]] && [[ $#BUFFER -gt $ZSH_HIGHLIGHT_MAXLENGTH ]] && return $ret - - # Do not highlight if there are pending inputs (copy/paste). - [[ $PENDING -gt 0 ]] && return $ret - - # Reset region highlight to build it from scratch - region_highlight=(); - - { - local cache_place - local -a region_highlight_copy - - # Select which highlighters in ZSH_HIGHLIGHT_HIGHLIGHTERS need to be invoked. - local highlighter; for highlighter in $ZSH_HIGHLIGHT_HIGHLIGHTERS; do - - # eval cache place for current highlighter and prepare it - cache_place="_zsh_highlight_${highlighter}_highlighter_cache" - typeset -ga ${cache_place} - - # If highlighter needs to be invoked - if "_zsh_highlight_${highlighter}_highlighter_predicate"; then - - # save a copy, and cleanup region_highlight - region_highlight_copy=("${region_highlight[@]}") - region_highlight=() - - # Execute highlighter and save result - { - "_zsh_highlight_${highlighter}_highlighter" - } always { - eval "${cache_place}=(\"\${region_highlight[@]}\")" - } - - # Restore saved region_highlight - region_highlight=("${region_highlight_copy[@]}") - - fi - - # Use value form cache if any cached - eval "region_highlight+=(\"\${${cache_place}[@]}\")" - - done - - } always { - _ZSH_HIGHLIGHT_PRIOR_BUFFER=$BUFFER - _ZSH_HIGHLIGHT_PRIOR_CURSOR=$CURSOR - return $ret - } + setopt localoptions nowarncreateglobal + + # Store the previous command return code to restore it whatever happens. + local ret=$? + + # Do not highlight if there are more than 300 chars in the buffer. It's most + # likely a pasted command or a huge list of files in that case.. + [[ -n ${ZSH_HIGHLIGHT_MAXLENGTH:-} ]] && [[ $#BUFFER -gt $ZSH_HIGHLIGHT_MAXLENGTH ]] && return $ret + + # Do not highlight if there are pending inputs (copy/paste). + [[ $PENDING -gt 0 ]] && return $ret + + # Reset region highlight to build it from scratch + region_highlight=(); + + { + local cache_place + local -a region_highlight_copy + + # Select which highlighters in ZSH_HIGHLIGHT_HIGHLIGHTERS need to be invoked. + local highlighter + for highlighter in $ZSH_HIGHLIGHT_HIGHLIGHTERS; do + + # eval cache place for current highlighter and prepare it + cache_place="_zsh_highlight_${highlighter}_highlighter_cache" + typeset -ga ${cache_place} + + # If highlighter needs to be invoked + if "_zsh_highlight_${highlighter}_highlighter_predicate"; then + + # save a copy, and cleanup region_highlight + region_highlight_copy=("${region_highlight[@]}") + region_highlight=() + + # Execute highlighter and save result + { + "_zsh_highlight_${highlighter}_highlighter" + } always { + eval "${cache_place}=(\"\${region_highlight[@]}\")" + } + + # Restore saved region_highlight + region_highlight=("${region_highlight_copy[@]}") + + fi + + # Use value form cache if any cached + eval "region_highlight+=(\"\${${cache_place}[@]}\")" + + done + + # Set zle_highlight according to user definition on this package level + zle_highlight=(default:$ZSH_HIGHLIGHT_STYLES[default] isearch:$ZSH_HIGHLIGHT_STYLES[isearch] region:$ZSH_HIGHLIGHT_STYLES[region] special:$ZSH_HIGHLIGHT_STYLES[special] suffix:$ZSH_HIGHLIGHT_STYLES[suffix]) + + # Bring back region higlighting from zle_highlight array (was overwriten by region_highlight) + ((REGION_ACTIVE)) && region_highlight+=("$((CURSOR < MARK ? CURSOR : MARK)) $((CURSOR > MARK ? CURSOR : MARK)) ${${(M)zle_highlight[@]:#region*}#region:}") + + } always { + _ZSH_HIGHLIGHT_PRIOR_BUFFER=$BUFFER + _ZSH_HIGHLIGHT_PRIOR_CURSOR=$CURSOR + return $ret + } } @@ -104,15 +111,16 @@ _zsh_highlight() # API/utility functions for highlighters # ------------------------------------------------------------------------------------------------- -# Array used by highlighters to declare user overridable styles. +# Arrays used by highlighters to declare user overridable styles. typeset -gA ZSH_HIGHLIGHT_STYLES +typeset -gA ZSH_HIGHLIGHT_FILES # Whether the command line buffer has been modified or not. # # Returns 0 if the buffer has changed since _zsh_highlight was last called. _zsh_highlight_buffer_modified() { - [[ "${_ZSH_HIGHLIGHT_PRIOR_BUFFER:-}" != "$BUFFER" ]] + [[ "${_ZSH_HIGHLIGHT_PRIOR_BUFFER:-}" != "$BUFFER" ]] } # Whether the cursor has moved or not. @@ -120,7 +128,7 @@ _zsh_highlight_buffer_modified() # Returns 0 if the cursor has moved since _zsh_highlight was last called. _zsh_highlight_cursor_moved() { - [[ -n $CURSOR ]] && [[ -n ${_ZSH_HIGHLIGHT_PRIOR_CURSOR-} ]] && (($_ZSH_HIGHLIGHT_PRIOR_CURSOR != $CURSOR)) + [[ -n $CURSOR ]] && [[ -n ${_ZSH_HIGHLIGHT_PRIOR_CURSOR-} ]] && (($_ZSH_HIGHLIGHT_PRIOR_CURSOR != $CURSOR)) } @@ -131,38 +139,38 @@ _zsh_highlight_cursor_moved() # Rebind all ZLE widgets to make them invoke _zsh_highlights. _zsh_highlight_bind_widgets() { - # Load ZSH module zsh/zleparameter, needed to override user defined widgets. - zmodload zsh/zleparameter 2>/dev/null || { - echo 'zsh-syntax-highlighting: failed loading zsh/zleparameter.' >&2 - return 1 - } + # Load ZSH module zsh/zleparameter, needed to override user defined widgets. + zmodload zsh/zleparameter 2>/dev/null || { + echo 'zsh-syntax-highlighting: failed loading zsh/zleparameter.' >&2 + return 1 + } - # Override ZLE widgets to make them invoke _zsh_highlight. - local cur_widget - for cur_widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|run-help|which-command|beep|yank*)}; do - case $widgets[$cur_widget] in + # Override ZLE widgets to make them invoke _zsh_highlight. + local cur_widget + for cur_widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|run-help|beep|auto-*|*-argument|argument-base|clear-screen|describe-key-briefly|kill-buffer|overwrite-mode|push-input|push-line-or-edit|reset-prompt|set-local-history|split-undo|undefined-key|what-cursor-position|where-is)}; do + case $widgets[$cur_widget] in - # Already rebound event: do nothing. - user:$cur_widget|user:_zsh_highlight_widget_*);; + # Already rebound event: do nothing. + user:$cur_widget|user:_zsh_highlight_widget_*);; - # User defined widget: override and rebind old one with prefix "orig-". - user:*) eval "zle -N orig-$cur_widget ${widgets[$cur_widget]#*:}; \ + # User defined widget: override and rebind old one with prefix "orig-". + user:*) eval "zle -N orig-$cur_widget ${widgets[$cur_widget]#*:}; \ _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \ zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; - # Completion widget: override and rebind old one with prefix "orig-". - completion:*) eval "zle -C orig-$cur_widget ${${widgets[$cur_widget]#*:}/:/ }; \ + # Completion widget: override and rebind old one with prefix "orig-". + completion:*) eval "zle -C orig-$cur_widget ${${widgets[$cur_widget]#*:}/:/ }; \ _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \ zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; - # Builtin widget: override and make it call the builtin ".widget". - builtin) eval "_zsh_highlight_widget_$cur_widget() { builtin zle .$cur_widget -- \"\$@\" && _zsh_highlight }; \ + # Builtin widget: override and make it call the builtin ".widget". + builtin) eval "_zsh_highlight_widget_$cur_widget() { builtin zle .$cur_widget -- \"\$@\" && _zsh_highlight }; \ zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; - # Default: unhandled case. - *) echo "zsh-syntax-highlighting: unhandled ZLE widget '$cur_widget'" >&2 ;; - esac - done + # Default: unhandled case. + *) echo "zsh-syntax-highlighting: unhandled ZLE widget '$cur_widget'" >&2 ;; + esac + done } # Load highlighters from directory. @@ -171,24 +179,24 @@ _zsh_highlight_bind_widgets() # 1) Path to the highlighters directory. _zsh_highlight_load_highlighters() { - # Check the directory exists. - [[ -d "$1" ]] || { - echo "zsh-syntax-highlighting: highlighters directory '$1' not found." >&2 - return 1 - } - - # Load highlighters from highlighters directory and check they define required functions. - local highlighter highlighter_dir - for highlighter_dir ($1/*/); do - highlighter="${highlighter_dir:t}" - [[ -f "$highlighter_dir/${highlighter}-highlighter.zsh" ]] && { - . "$highlighter_dir/${highlighter}-highlighter.zsh" - type "_zsh_highlight_${highlighter}_highlighter" &> /dev/null && - type "_zsh_highlight_${highlighter}_highlighter_predicate" &> /dev/null || { - 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 - } + # Check the directory exists. + [[ -d "$1" ]] || { + echo "zsh-syntax-highlighting: highlighters directory '$1' not found." >&2 + return 1 } - done + + # Load highlighters from highlighters directory and check they define required functions. + local highlighter highlighter_dir + for highlighter_dir ($1/*/); do + highlighter="${highlighter_dir:t}" + [[ -f "$highlighter_dir/${highlighter}-highlighter.zsh" ]] && { + . "$highlighter_dir/${highlighter}-highlighter.zsh" + type "_zsh_highlight_${highlighter}_highlighter" &> /dev/null && + type "_zsh_highlight_${highlighter}_highlighter_predicate" &> /dev/null || { + 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 + } + } + done } @@ -198,26 +206,26 @@ _zsh_highlight_load_highlighters() # Try binding widgets. _zsh_highlight_bind_widgets || { - echo 'zsh-syntax-highlighting: failed binding ZLE widgets, exiting.' >&2 - return 1 + echo 'zsh-syntax-highlighting: failed binding ZLE widgets, exiting.' >&2 + return 1 } # Resolve highlighters directory location. _zsh_highlight_load_highlighters "${ZSH_HIGHLIGHT_HIGHLIGHTERS_DIR:-${${0:A}:h}/highlighters}" || { - echo 'zsh-syntax-highlighting: failed loading highlighters, exiting.' >&2 - return 1 + echo 'zsh-syntax-highlighting: failed loading highlighters, exiting.' >&2 + return 1 } # Reset scratch variables when commandline is done. _zsh_highlight_preexec_hook() { - _ZSH_HIGHLIGHT_PRIOR_BUFFER= - _ZSH_HIGHLIGHT_PRIOR_CURSOR= + _ZSH_HIGHLIGHT_PRIOR_BUFFER= + _ZSH_HIGHLIGHT_PRIOR_CURSOR= } autoload -U add-zsh-hook add-zsh-hook preexec _zsh_highlight_preexec_hook 2>/dev/null || { echo 'zsh-syntax-highlighting: failed loading add-zsh-hook.' >&2 - } +} # Initialize the array of active highlighters if needed. [[ $#ZSH_HIGHLIGHT_HIGHLIGHTERS -eq 0 ]] && ZSH_HIGHLIGHT_HIGHLIGHTERS=(main) || true