zsh-users / zsh-syntax-highlighting

Fish shell like syntax highlighting for Zsh.
github.com/zsh-users/zsh-syntax-highlighting
BSD 3-Clause "New" or "Revised" License
20.16k stars 1.33k forks source link

Disable slow highlighting by default? #736

Open danielshahaf opened 4 years ago

danielshahaf commented 4 years ago

Given that editing huge buffers (e.g., fned vcs_info) isn't very performant right now, shall we default ZSH_HIGHLIGHT_MAXLENGTH to some reasonable value if it's unset?

Users will still be able to get the current behaviour by explicitly setting that variable to an empty string.

danielshahaf commented 4 years ago

A bit further outside the box: How about if we time the zsh_highlight run, and if it takes longer than some (possibly configurable) threshold duration, then we disable ourselves until the next time $PREBUFFER and $BUFFER are both empty?

Proof of concept:

diff --git a/zsh-syntax-highlighting.zsh b/zsh-syntax-highlighting.zsh
index 6c95e8c..9b5876f 100644
--- a/zsh-syntax-highlighting.zsh
+++ b/zsh-syntax-highlighting.zsh
@@ -76,6 +76,9 @@ _zsh_highlight()
   # Make it read-only.  Can't combine this with the previous line when POSIX_BUILTINS may be set.
   typeset -r ret

+  typeset -F SECONDS; typeset -F start_timestamp=$SECONDS
+  readonly -F ZSH_HIGHLIGHT_MAX_DELAY_SECONDS=0.2 # set very low since it's per-keystroke
+
   # Remove all highlighting in isearch, so that only the underlining done by zsh itself remains.
   # For details see FAQ entry 'Why does syntax highlighting not work while searching history?'.
   # This disables highlighting during isearch (for reasons explained in README.md) unless zsh is new enough
@@ -85,6 +88,11 @@ _zsh_highlight()
     return $ret
   fi

+  if [[ -n $PREBUFFER || -n $BUFFER ]] && [[ $WIDGET != *clear-screen* ]] && (( _ZSH_HIGHLIGHT_PRIOR_DURATION > ZSH_HIGHLIGHT_MAX_DELAY_SECONDS )); then
+    region_highlight=()
+    return $ret
+  fi
+
   # Before we 'emulate -L', save the user's options
   local -A zsyh_user_options
   if zmodload -e zsh/parameter; then
@@ -197,6 +205,9 @@ _zsh_highlight()

   } always {
+    typeset -gF _ZSH_HIGHLIGHT_PRIOR_DURATION=0
+    (( _ZSH_HIGHLIGHT_PRIOR_DURATION = SECONDS - start_timestamp ))
+    typeset -p _ZSH_HIGHLIGHT_PRIOR_DURATION >/dev/tty
     typeset -g _ZSH_HIGHLIGHT_PRIOR_BUFFER="$BUFFER"
     typeset -gi _ZSH_HIGHLIGHT_PRIOR_CURSOR=$CURSOR
   }

The use of $WIDGET won't coexist with add-zle-hook-widget zle-line-pre-redraw as it stands, but as mentioned there, workers/46004, once merged, will address this in add-zle-hook-widget. (At that point, we'll want to use $LASTWIDGET in the redrawhook codepath and $WIDGET in the legacy codepath. None of the existing uses of $WIDGET seem affected.)