summaryrefslogtreecommitdiff
path: root/dot-oh-my-zsh/custom/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'dot-oh-my-zsh/custom/plugins')
-rw-r--r--dot-oh-my-zsh/custom/plugins/copybuffer/copybuffer.plugin.zsh14
-rw-r--r--dot-oh-my-zsh/custom/plugins/dirhistory/dirhistory.plugin.zsh221
-rw-r--r--dot-oh-my-zsh/custom/plugins/example/example.plugin.zsh2
m---------dot-oh-my-zsh/custom/plugins/fzf-tab0
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.github/FUNDING.yml1
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.github/ISSUE_TEMPLATE.md22
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.github/dependabot.yml10
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/codeql-analysis.yml44
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/linux.yml45
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/macos.yml45
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.gitignore14
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.goreleaser.yml119
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.rubocop.yml28
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/.tool-versions1
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/ADVANCED.md609
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/BUILD.md49
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/CHANGELOG.md1314
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/Dockerfile11
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/LICENSE21
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/Makefile172
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/README-VIM.md486
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/README.md711
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/fzf/bin/fzf-tmux229
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/doc/fzf.txt512
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/go.mod21
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/go.sum32
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/fzf/install377
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/install.ps165
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/main.go14
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/man/man1/fzf-tmux.168
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/man/man1/fzf.11046
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/plugin/fzf.vim1060
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/shell/completion.bash379
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/shell/completion.zsh324
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.bash102
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.fish172
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.zsh120
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/LICENSE21
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/algo/algo.go946
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/algo/algo_test.go198
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/algo/normalize.go492
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/ansi.go433
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/ansi_test.go428
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/cache.go81
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/cache_test.go39
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/chunklist.go89
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/chunklist_test.go80
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/constants.go85
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/core.go333
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/history.go96
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/history_test.go68
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/item.go44
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/item_test.go23
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/matcher.go235
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/merger.go120
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/merger_test.go88
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/options.go1806
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/options_test.go468
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/pattern.go427
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/pattern_test.go209
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/protector/protector.go8
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/protector/protector_openbsd.go10
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/reader.go201
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/reader_test.go63
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/result.go258
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/result_others.go16
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/result_test.go174
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/result_x86.go16
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/terminal.go2937
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/terminal_test.go638
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/terminal_unix.go26
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/terminal_windows.go45
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tokenizer.go253
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tokenizer_test.go112
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/dummy.go45
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/light.go1019
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/light_unix.go110
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/light_windows.go145
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/tcell.go732
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/tcell_test.go392
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/ttyname_unix.go47
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/ttyname_windows.go14
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/tui.go625
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/tui/tui_test.go20
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/atomicbool.go34
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/atomicbool_test.go17
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/chars.go198
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/chars_test.go46
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/eventbox.go96
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/eventbox_test.go61
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/slab.go12
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/util.go155
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/util_test.go66
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/util_unix.go47
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/src/util/util_windows.go83
-rw-r--r--dot-oh-my-zsh/custom/plugins/fzf/test/fzf.vader175
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/fzf/test/test_go.rb2729
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/fzf/uninstall113
-rw-r--r--dot-oh-my-zsh/custom/plugins/sudo/sudo.plugin.zsh25
-rw-r--r--dot-oh-my-zsh/custom/plugins/web-search/web-search.plugin.zsh86
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.clitest/complete-word.post.md86
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/alias-expansion.pngbin0 -> 72230 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/file-search.gifbin0 -> 583016 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-lines.pngbin0 -> 76741 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-menu.pngbin0 -> 188881 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-search.gifbin0 -> 346952 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/multi-select.pngbin0 -> 185032 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/recent-dirs.pngbin0 -> 80919 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/requoted.pngbin0 -> 72674 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/unambiguous.pngbin0 -> 119840 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.vscode/settings.json5
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.zshrc99
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/LICENSE19
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/README.md150
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/.autocomplete.patch6
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/.autocomplete.zle-flags32
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.ancestor_dirs29
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.command7
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.compadd_opts_len10
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.history_lines144
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.is_glob12
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.recent_paths56
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.requoted22
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.unambiguous35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.complete-word.completion-widget27
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.complete-word.post68
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.down-line-or-select.zle-widget7
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.history-search.completion-widget19
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.history-search.zle-widget47
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.list-expand.completion-widget29
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.up-line-or-search.zle-widget7
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/zsh-autocomplete/run-tests.zsh3
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.__init__125
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.async603
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.compinit229
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.config138
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.key-binding130
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.recent-dirs92
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.widget31
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autocomplete/zsh-autocomplete.plugin.zsh19
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.circleci/config.yml15
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.editorconfig18
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.rspec3
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.rubocop.yml30
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.ruby-version1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/CHANGELOG.md117
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/DESCRIPTION1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Dockerfile20
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Gemfile5
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Gemfile.lock41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/INSTALL.md64
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/LICENSE23
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Makefile35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/README.md191
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/URL1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/VERSION1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/ZSH_VERSIONS17
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/zsh-autosuggestions/install_test_zsh.sh26
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/async_spec.rb70
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/auto_cd_spec.rb14
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/bracketed_paste_magic_spec.rb43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/client_zpty_spec.rb14
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/glob_subst_spec.rb12
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/rebound_bracket_spec.rb13
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/vi_mode_spec.rb80
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/wrapped_widget_spec.rb39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/zle_input_stack_spec.rb24
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/kill_ring_spec.rb23
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/line_init_spec.rb17
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/multi_line_spec.rb8
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/buffer_max_size_spec.rb30
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/highlight_style_spec.rb7
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/original_widget_prefix_spec.rb7
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/strategy_spec.rb55
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/widget_lists_spec.rb121
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/spec_helper.rb54
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/completion_spec.rb72
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/history_spec.rb23
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/match_prev_cmd_spec.rb34
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/special_characters_helper.rb75
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/terminal_session.rb99
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/disable_spec.rb19
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/enable_spec.rb42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/fetch_spec.rb24
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/toggle_spec.rb26
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/async.zsh76
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/bind.zsh106
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/config.zsh93
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/fetch.zsh27
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/highlight.zsh26
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/start.zsh33
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/completion.zsh137
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/history.zsh32
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/match_prev_cmd.zsh66
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/util.zsh11
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/widgets.zsh231
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.plugin.zsh1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh864
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-cwd-history/zsh-cwd-history.plugin.zsh150
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/README.md182
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/zsh-history-substring-search.plugin.zsh2
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/zsh-history-substring-search.zsh829
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.editorconfig15
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.revision-hash1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.version1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/COPYING.md23
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/HACKING.md99
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/INSTALL.md137
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/Makefile64
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/README.md97
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/changelog.md884
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters.md134
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/brackets.md31
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/cursor.md24
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/line.md24
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/main.md121
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/pattern.md24
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/regexp.md65
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/root.md25
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/README.md8
l---------dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/README.md1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/brackets-highlighter.zsh107
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/cursor-matchingbracket-line-finish.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/cursor-matchingbracket.zsh47
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/empty-styles.zsh33
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/loop-styles.zsh53
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/mismatch-patentheses.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/near-quotes.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/nested-parentheses.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/only-error.zsh34
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/quoted-patentheses.zsh34
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/simple-parentheses.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/unclosed-patentheses.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/unclosed-patentheses2.zsh40
l---------dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/cursor/README.md1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/cursor/cursor-highlighter.zsh47
l---------dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/line/README.md1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/line/line-highlighter.zsh44
l---------dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/README.md1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/main-highlighter.zsh1846
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position1.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position1b.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position2.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position3.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position3b.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position4.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position5.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-assignment1.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-basic.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-brackets.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-command-substitution.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-comment1.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-comment2.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-complex.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-empty.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-eponymous1.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-eponymous2.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-in-cmdsubst.zsh43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-loop.zsh44
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-loop2.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-nested-precommand.zsh43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-nested.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-parameter.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument1.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument2.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument3.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument4.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-quoted.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-redirect.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse1.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse2.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse3.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse4.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse5.zsh43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-self.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-self2.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-to-dir.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-to-dir1b.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-unknown-token1.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-unknown-token2.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias.zsh53
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always1.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always2.zsh43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always3.zsh43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/anonymous-function.zsh44
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arg0-colon.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith-cmdsubst-mess.zsh46
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith1.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith2.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-command-substitution.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-doubled-parens.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-empty.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-evaluation.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-hist-expn.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-invalid-chars.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-multiplication.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-nested.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-quoted.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-unclosed.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-unfinished.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep1.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep2.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep3.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-append.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-argv.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array2.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array3.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-invalid-command.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-not-array.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-not-array2.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-quoted-cmdsubst.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-semicolon.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-subshell.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-value-quote1.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-value-quote2.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword1.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword2.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword3.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword4.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword5.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-quoted.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/back-quoted-argument.zsh58
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/back-quoted-open.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-continuation.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-continuation2.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-space.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash.zsh34
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-assign-array.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-assign-scalar.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-pipeline.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/block-assignment-no-command.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/braces1.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/braces2.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-matching1.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-matching2.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch1.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch10-if-negative.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch2.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch3.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch4.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch5.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch6.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch7.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch8-if-positive.zsh53
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch8.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch9-if-positive.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-premature-termination.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cdpath-abspath.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cmdpos-elision-partial.zsh44
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-adjacent.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-in-assignment.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-unclosed.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/commandseparator.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-followed.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-leading.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-off.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comments.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/commmand-parameter.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow.zsh57
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow2.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow3.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cthulhu.zsh70
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dinbrack1.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dirs_blacklist.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-dollar.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-noise.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-paren.zsh49
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted2.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted3.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-hyphen-option.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted2.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted3.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted4.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command-newline.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command2.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-line.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals1.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals2.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals3.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals4.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/escaped-single-quote.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/exec-redirection1.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/fd-target-not-filename.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-altsyntax.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-named1.zsh44
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-named2.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/glob.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/global-alias1.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/globs-with-quoting.zsh43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/hashed-command.zsh35
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-escaped.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-followed.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-no.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-unescaped.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-yes.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-expansion.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-expansion2.zsh34
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/inheritance.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/jobsubst-isnt-glob.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/jobsubst-isnt-glob2.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/loop-newline.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/meta-no-eval1.zsh49
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/meta-no-eval2.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-array-assignment1.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-string.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-string2.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multios-negates-globbing.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multios-negates-globbing2.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiple-quotes.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiple-redirections.zsh46
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob-alias.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob-always.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob1.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob2.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob3.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob4.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/null-exec.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/null-exec2-printenv.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/number_range-glob.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/off-by-one.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/opt-shwordsplit1.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/optimized-cmdsubst-input.zsh43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-dollar-quote-isnt-filename.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-path_dirs.zsh44
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-with-quotes.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/order-path-after-dollar.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/order-path-before-globbing.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-positional-in-array-append.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-precommand-option-argument1.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-precommand-option-argument3.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-elision-command-word.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-shwordsplit.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-untokenized1.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-untokenized2.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-star.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-to-global-alias.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-value-contains-command-position1.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-value-contains-command-position2.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/pasted-quotes.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-broken-symlink.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word.zsh45
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word2.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word3.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word3b.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word4.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-mixed-quoting.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-separators.zsh53
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-separators2.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-space.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home2.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home3.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-named.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix2.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix3.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/plain-file-in-command-position.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-killing1.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-killing2.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-then-assignment.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type1.zsh61
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type2.zsh55
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type3.zsh55
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-uninstalled.zsh44
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-unknown-option.zsh43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand2.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand3.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand4.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/prefix-redirection.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution-after-redirection.zsh46
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution-redirection-isnt-globbing.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution.zsh43
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution2.zsh51
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/quoted-command-substitution-empty.zsh44
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/quoted-redirection-in-command-word.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/rc-quotes.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-comment.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-from-param.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-in-cmdsubst.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-inhibits-elision.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-is-not-option.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-special-cases.zsh44
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection2.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection3.zsh42
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/reserved-word.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/simple-command.zsh34
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/simple-redirection.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/subshell.zsh51
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-command.zsh54
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-comment.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-longopt.zsh38
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection.zsh48
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection2.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection3.zsh41
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/tilde-command-word.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/time-and-nocorrect1.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/time-and-nocorrect2.zsh40
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/unbackslash.zsh34
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/unknown-command.zsh34
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/vanilla-newline.zsh39
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/vi-linewise-mode.zsh43
l---------dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/README.md1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/pattern-highlighter.zsh60
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/test-data/rm-rf.zsh36
l---------dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/README.md1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/regexp-highlighter.zsh62
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/complex.zsh37
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/subexpression.zsh36
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/word-boundary.zsh42
l---------dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/root/README.md1
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/root/root-highlighter.zsh44
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1-smaller.pngbin0 -> 2517 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1.pngbin0 -> 5842 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2-smaller.pngbin0 -> 4386 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2.pngbin0 -> 10228 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3-smaller.pngbin0 -> 1673 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3.pngbin0 -> 3427 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after4-smaller.pngbin0 -> 3224 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1-smaller.pngbin0 -> 1589 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1.pngbin0 -> 2636 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2-smaller.pngbin0 -> 2605 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2.pngbin0 -> 2614 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3-smaller.pngbin0 -> 763 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3.pngbin0 -> 1461 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before4-smaller.pngbin0 -> 2987 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview-smaller.pngbin0 -> 5982 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview.pngbin0 -> 14650 bytes
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/release.md21
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/README.md124
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/edit-failed-tests40
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/generate.zsh117
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/tap-colorizer.zsh71
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/tap-filter47
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-highlighting.zsh291
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-perfs.zsh103
-rwxr-xr-xdot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-zprof.zsh78
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.plugin.zsh2
-rw-r--r--dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh600
547 files changed, 50859 insertions, 0 deletions
diff --git a/dot-oh-my-zsh/custom/plugins/copybuffer/copybuffer.plugin.zsh b/dot-oh-my-zsh/custom/plugins/copybuffer/copybuffer.plugin.zsh
new file mode 100644
index 00000000..52c630c4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/copybuffer/copybuffer.plugin.zsh
@@ -0,0 +1,14 @@
+# copy the active line from the command line buffer
+# onto the system clipboard
+
+copybuffer () {
+ if which clipcopy &>/dev/null; then
+ printf "%s" "$BUFFER" | clipcopy
+ else
+ zle -M "clipcopy not found. Please make sure you have Oh My Zsh installed correctly."
+ fi
+}
+
+zle -N copybuffer
+
+bindkey -M emacs "^E" copybuffer
diff --git a/dot-oh-my-zsh/custom/plugins/dirhistory/dirhistory.plugin.zsh b/dot-oh-my-zsh/custom/plugins/dirhistory/dirhistory.plugin.zsh
new file mode 100644
index 00000000..7021fc03
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/dirhistory/dirhistory.plugin.zsh
@@ -0,0 +1,221 @@
+##
+# Navigate directory history using ALT-LEFT and ALT-RIGHT. ALT-LEFT moves back to directories
+# that the user has changed to in the past, and ALT-RIGHT undoes ALT-LEFT.
+#
+# Navigate directory hierarchy using ALT-UP and ALT-DOWN.
+# ALT-UP moves to higher hierarchy (cd ..)
+# ALT-DOWN moves into the first directory found in alphabetical order
+#
+
+dirhistory_past=($PWD)
+dirhistory_future=()
+export dirhistory_past
+export dirhistory_future
+
+export DIRHISTORY_SIZE=30
+
+# Pop the last element of dirhistory_past.
+# Pass the name of the variable to return the result in.
+# Returns the element if the array was not empty,
+# otherwise returns empty string.
+function pop_past() {
+ typeset -g $1="${dirhistory_past[$#dirhistory_past]}"
+ if [[ $#dirhistory_past -gt 0 ]]; then
+ dirhistory_past[$#dirhistory_past]=()
+ fi
+}
+
+function pop_future() {
+ typeset -g $1="${dirhistory_future[$#dirhistory_future]}"
+ if [[ $#dirhistory_future -gt 0 ]]; then
+ dirhistory_future[$#dirhistory_future]=()
+ fi
+}
+
+# Push a new element onto the end of dirhistory_past. If the size of the array
+# is >= DIRHISTORY_SIZE, the array is shifted
+function push_past() {
+ if [[ $#dirhistory_past -ge $DIRHISTORY_SIZE ]]; then
+ shift dirhistory_past
+ fi
+ if [[ $#dirhistory_past -eq 0 || $dirhistory_past[$#dirhistory_past] != "$1" ]]; then
+ dirhistory_past+=($1)
+ fi
+}
+
+function push_future() {
+ if [[ $#dirhistory_future -ge $DIRHISTORY_SIZE ]]; then
+ shift dirhistory_future
+ fi
+ if [[ $#dirhistory_future -eq 0 || $dirhistory_futuret[$#dirhistory_future] != "$1" ]]; then
+ dirhistory_future+=($1)
+ fi
+}
+
+# Called by zsh when directory changes
+autoload -U add-zsh-hook
+add-zsh-hook chpwd chpwd_dirhistory
+function chpwd_dirhistory() {
+ push_past $PWD
+ # If DIRHISTORY_CD is not set...
+ if [[ -z "${DIRHISTORY_CD+x}" ]]; then
+ # ... clear future.
+ dirhistory_future=()
+ fi
+}
+
+function dirhistory_cd(){
+ DIRHISTORY_CD="1"
+ cd $1
+ unset DIRHISTORY_CD
+}
+
+# Move backward in directory history
+function dirhistory_back() {
+ local cw=""
+ local d=""
+ # Last element in dirhistory_past is the cwd.
+
+ pop_past cw
+ if [[ "" == "$cw" ]]; then
+ # Someone overwrote our variable. Recover it.
+ dirhistory_past=($PWD)
+ return
+ fi
+
+ pop_past d
+ if [[ "" != "$d" ]]; then
+ dirhistory_cd $d
+ push_future $cw
+ else
+ push_past $cw
+ fi
+}
+
+
+# Move forward in directory history
+function dirhistory_forward() {
+ local d=""
+
+ pop_future d
+ if [[ "" != "$d" ]]; then
+ dirhistory_cd $d
+ push_past $d
+ fi
+}
+
+
+# Bind keys to history navigation
+function dirhistory_zle_dirhistory_back() {
+ # Erase current line in buffer
+ zle .kill-buffer
+ dirhistory_back
+ zle .accept-line
+}
+
+function dirhistory_zle_dirhistory_future() {
+ # Erase current line in buffer
+ zle .kill-buffer
+ dirhistory_forward
+ zle .accept-line
+}
+
+zle -N dirhistory_zle_dirhistory_back
+zle -N dirhistory_zle_dirhistory_future
+
+for keymap in emacs vicmd viins; do
+ # dirhistory_back
+ bindkey -M $keymap "\e[3D" dirhistory_zle_dirhistory_back # xterm in normal mode
+ bindkey -M $keymap "\e[1;3D" dirhistory_zle_dirhistory_back # xterm in normal mode
+ bindkey -M $keymap "\e\e[D" dirhistory_zle_dirhistory_back # Putty
+ bindkey -M $keymap "\eO3D" dirhistory_zle_dirhistory_back # GNU screen
+
+ case "$TERM_PROGRAM" in
+ Apple_Terminal) bindkey -M $keymap "^[b" dirhistory_zle_dirhistory_back ;; # Terminal.app
+ iTerm.app) bindkey -M $keymap "^[^[[D" dirhistory_zle_dirhistory_back ;; # iTerm2
+ esac
+
+ if (( ${+terminfo[kcub1]} )); then
+ bindkey -M $keymap "^[${terminfo[kcub1]}" dirhistory_zle_dirhistory_back # urxvt
+ fi
+
+ # dirhistory_future
+ bindkey -M $keymap "\e[3C" dirhistory_zle_dirhistory_future # xterm in normal mode
+ bindkey -M $keymap "\e[1;3C" dirhistory_zle_dirhistory_future # xterm in normal mode
+ bindkey -M $keymap "\e\e[C" dirhistory_zle_dirhistory_future # Putty
+ bindkey -M $keymap "\eO3C" dirhistory_zle_dirhistory_future # GNU screen
+
+ case "$TERM_PROGRAM" in
+ Apple_Terminal) bindkey -M $keymap "^[f" dirhistory_zle_dirhistory_future ;; # Terminal.app
+ iTerm.app) bindkey -M $keymap "^[^[[C" dirhistory_zle_dirhistory_future ;; # iTerm2
+ esac
+
+ if (( ${+terminfo[kcuf1]} )); then
+ bindkey -M $keymap "^[${terminfo[kcuf1]}" dirhistory_zle_dirhistory_future # urxvt
+ fi
+done
+
+#
+# HIERARCHY Implemented in this section, in case someone wants to split it to another plugin if it clashes bindings
+#
+
+# Move up in hierarchy
+function dirhistory_up() {
+ cd .. || return 1
+}
+
+# Move down in hierarchy
+function dirhistory_down() {
+ cd "$(find . -mindepth 1 -maxdepth 1 -type d | sort -n | head -n 1)" || return 1
+}
+
+
+# Bind keys to hierarchy navigation
+function dirhistory_zle_dirhistory_up() {
+ zle .kill-buffer # Erase current line in buffer
+ dirhistory_up
+ zle .accept-line
+}
+
+function dirhistory_zle_dirhistory_down() {
+ zle .kill-buffer # Erase current line in buffer
+ dirhistory_down
+ zle .accept-line
+}
+
+zle -N dirhistory_zle_dirhistory_up
+zle -N dirhistory_zle_dirhistory_down
+
+for keymap in emacs vicmd viins; do
+ # dirhistory_up
+ bindkey -M $keymap "\e[3A" dirhistory_zle_dirhistory_up # xterm in normal mode
+ bindkey -M $keymap "\e[1;3A" dirhistory_zle_dirhistory_up # xterm in normal mode
+ bindkey -M $keymap "\e\e[A" dirhistory_zle_dirhistory_up # Putty
+ bindkey -M $keymap "\eO3A" dirhistory_zle_dirhistory_up # GNU screen
+
+ case "$TERM_PROGRAM" in
+ Apple_Terminal) bindkey -M $keymap "^[[A" dirhistory_zle_dirhistory_up ;; # Terminal.app
+ iTerm.app) bindkey -M $keymap "^[^[[A" dirhistory_zle_dirhistory_up ;; # iTerm2
+ esac
+
+ if (( ${+terminfo[kcuu1]} )); then
+ bindkey -M $keymap "^[${terminfo[kcuu1]}" dirhistory_zle_dirhistory_up # urxvt
+ fi
+
+ # dirhistory_down
+ bindkey -M $keymap "\e[3B" dirhistory_zle_dirhistory_down # xterm in normal mode
+ bindkey -M $keymap "\e[1;3B" dirhistory_zle_dirhistory_down # xterm in normal mode
+ bindkey -M $keymap "\e\e[B" dirhistory_zle_dirhistory_down # Putty
+ bindkey -M $keymap "\eO3B" dirhistory_zle_dirhistory_down # GNU screen
+
+ case "$TERM_PROGRAM" in
+ Apple_Terminal) bindkey -M $keymap "^[[B" dirhistory_zle_dirhistory_down ;; # Terminal.app
+ iTerm.app) bindkey -M $keymap "^[^[[B" dirhistory_zle_dirhistory_down ;; # iTerm2
+ esac
+
+ if (( ${+terminfo[kcud1]} )); then
+ bindkey -M $keymap "^[${terminfo[kcud1]}" dirhistory_zle_dirhistory_down # urxvt
+ fi
+done
+
+unset keymap
diff --git a/dot-oh-my-zsh/custom/plugins/example/example.plugin.zsh b/dot-oh-my-zsh/custom/plugins/example/example.plugin.zsh
new file mode 100644
index 00000000..406f2744
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/example/example.plugin.zsh
@@ -0,0 +1,2 @@
+# Add your own custom plugins in the custom/plugins directory. Plugins placed
+# here will override ones with the same name in the main plugins directory.
diff --git a/dot-oh-my-zsh/custom/plugins/fzf-tab b/dot-oh-my-zsh/custom/plugins/fzf-tab
new file mode 160000
+Subproject c7fb028ec0bbc1056c51508602dbd61b0f475ac
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.github/FUNDING.yml b/dot-oh-my-zsh/custom/plugins/fzf/.github/FUNDING.yml
new file mode 100644
index 00000000..f2848951
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: junegunn
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.github/ISSUE_TEMPLATE.md b/dot-oh-my-zsh/custom/plugins/fzf/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000..1ba2978c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,22 @@
+<!-- ISSUES NOT FOLLOWING THIS TEMPLATE WILL BE CLOSED AND DELETED -->
+
+<!-- Check all that apply [x] -->
+
+- [ ] I have read through the manual page (`man fzf`)
+- [ ] I have the latest version of fzf
+- [ ] I have searched through the existing issues
+
+## Info
+
+- OS
+ - [ ] Linux
+ - [ ] Mac OS X
+ - [ ] Windows
+ - [ ] Etc.
+- Shell
+ - [ ] bash
+ - [ ] zsh
+ - [ ] fish
+
+## Problem / Steps to reproduce
+
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.github/dependabot.yml b/dot-oh-my-zsh/custom/plugins/fzf/.github/dependabot.yml
new file mode 100644
index 00000000..a056bba7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.github/dependabot.yml
@@ -0,0 +1,10 @@
+version: 2
+updates:
+ - package-ecosystem: "gomod"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/codeql-analysis.yml b/dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000..291aaf7c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,44 @@
+# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning
+name: CodeQL
+
+on:
+ push:
+ branches: [ master, devel ]
+ pull_request:
+ branches: [ master ]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ analyze:
+ permissions:
+ actions: read # for github/codeql-action/init to get workflow details
+ contents: read # for actions/checkout to fetch code
+ security-events: write # for github/codeql-action/autobuild to send a status report
+ name: Analyze
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: ['go']
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+ with:
+ fetch-depth: 0
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@1ed1437484560351c5be56cf73a48a279d116b78
+ with:
+ languages: ${{ matrix.language }}
+
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@1ed1437484560351c5be56cf73a48a279d116b78
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@1ed1437484560351c5be56cf73a48a279d116b78
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/linux.yml b/dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/linux.yml
new file mode 100644
index 00000000..68a783d4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/linux.yml
@@ -0,0 +1,45 @@
+---
+name: Test fzf on Linux
+
+on:
+ push:
+ branches: [ master, devel ]
+ pull_request:
+ branches: [ master ]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+ with:
+ fetch-depth: 0
+
+ - name: Set up Go
+ uses: actions/setup-go@f6164bd8c8acb4a71fb2791a8b6c4024ff038dab # v2
+ with:
+ go-version: 1.19
+
+ - name: Setup Ruby
+ uses: ruby/setup-ruby@ebaea52cb20fea395b0904125276395e37183dac
+ with:
+ ruby-version: 3.0.0
+
+ - name: Install packages
+ run: sudo apt-get install --yes zsh fish tmux
+
+ - name: Install Ruby gems
+ run: sudo gem install --no-document minitest:5.14.2 rubocop:1.0.0 rubocop-minitest:0.10.1 rubocop-performance:1.8.1
+
+ - name: Rubocop
+ run: rubocop --require rubocop-minitest --require rubocop-performance
+
+ - name: Unit test
+ run: make test
+
+ - name: Integration test
+ run: make install && ./install --all && LC_ALL=C tmux new-session -d && ruby test/test_go.rb --verbose
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/macos.yml b/dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/macos.yml
new file mode 100644
index 00000000..06b63d6b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.github/workflows/macos.yml
@@ -0,0 +1,45 @@
+---
+name: Test fzf on macOS
+
+on:
+ push:
+ branches: [ master, devel ]
+ pull_request:
+ branches: [ master ]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: macos-latest
+ steps:
+ - uses: actions/checkout@629c2de402a417ea7690ca6ce3f33229e27606a5 # v2
+ with:
+ fetch-depth: 0
+
+ - name: Set up Go
+ uses: actions/setup-go@f6164bd8c8acb4a71fb2791a8b6c4024ff038dab # v2
+ with:
+ go-version: 1.18
+
+ - name: Setup Ruby
+ uses: ruby/setup-ruby@ebaea52cb20fea395b0904125276395e37183dac
+ with:
+ ruby-version: 3.0.0
+
+ - name: Install packages
+ run: HOMEBREW_NO_INSTALL_CLEANUP=1 brew install fish zsh tmux
+
+ - name: Install Ruby gems
+ run: gem install --no-document minitest:5.14.2 rubocop:1.0.0 rubocop-minitest:0.10.1 rubocop-performance:1.8.1
+
+ - name: Rubocop
+ run: rubocop --require rubocop-minitest --require rubocop-performance
+
+ - name: Unit test
+ run: make test
+
+ - name: Integration test
+ run: make install && ./install --all && LC_ALL=C tmux new-session -d && ruby test/test_go.rb --verbose
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.gitignore b/dot-oh-my-zsh/custom/plugins/fzf/.gitignore
new file mode 100644
index 00000000..8bde085a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.gitignore
@@ -0,0 +1,14 @@
+bin/fzf
+bin/fzf.exe
+dist
+target
+pkg
+Gemfile.lock
+.DS_Store
+doc/tags
+vendor
+gopath
+*.zwc
+fzf
+tmp
+*.patch
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.goreleaser.yml b/dot-oh-my-zsh/custom/plugins/fzf/.goreleaser.yml
new file mode 100644
index 00000000..4db20f8e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.goreleaser.yml
@@ -0,0 +1,119 @@
+---
+project_name: fzf
+
+before:
+ hooks:
+ - go mod download
+
+builds:
+ - id: fzf-macos
+ binary: fzf
+ goos:
+ - darwin
+ goarch:
+ - amd64
+ ldflags:
+ - "-s -w -X main.version={{ .Version }} -X main.revision={{ .ShortCommit }}"
+ hooks:
+ post: |
+ sh -c '
+ cat > /tmp/fzf-gon-amd64.hcl << EOF
+ source = ["./dist/fzf-macos_darwin_amd64_v1/fzf"]
+ bundle_id = "kr.junegunn.fzf"
+ apple_id {
+ username = "junegunn.c@gmail.com"
+ password = "@env:AC_PASSWORD"
+ }
+ sign {
+ application_identity = "Developer ID Application: Junegunn Choi (Y254DRW44Z)"
+ }
+ zip {
+ output_path = "./dist/fzf-{{ .Version }}-darwin_amd64.zip"
+ }
+ EOF
+ gon /tmp/fzf-gon-amd64.hcl
+ '
+
+ - id: fzf-macos-arm
+ binary: fzf
+ goos:
+ - darwin
+ goarch:
+ - arm64
+ ldflags:
+ - "-s -w -X main.version={{ .Version }} -X main.revision={{ .ShortCommit }}"
+ hooks:
+ post: |
+ sh -c '
+ cat > /tmp/fzf-gon-arm64.hcl << EOF
+ source = ["./dist/fzf-macos-arm_darwin_arm64/fzf"]
+ bundle_id = "kr.junegunn.fzf"
+ apple_id {
+ username = "junegunn.c@gmail.com"
+ password = "@env:AC_PASSWORD"
+ }
+ sign {
+ application_identity = "Developer ID Application: Junegunn Choi (Y254DRW44Z)"
+ }
+ zip {
+ output_path = "./dist/fzf-{{ .Version }}-darwin_arm64.zip"
+ }
+ EOF
+ gon /tmp/fzf-gon-arm64.hcl
+ '
+
+ - id: fzf
+ goos:
+ - linux
+ - windows
+ - freebsd
+ - openbsd
+ goarch:
+ - amd64
+ - arm
+ - arm64
+ goarm:
+ - 5
+ - 6
+ - 7
+ ldflags:
+ - "-s -w -X main.version={{ .Version }} -X main.revision={{ .ShortCommit }}"
+ ignore:
+ - goos: freebsd
+ goarch: arm
+ - goos: openbsd
+ goarch: arm
+ - goos: freebsd
+ goarch: arm64
+ - goos: openbsd
+ goarch: arm64
+
+archives:
+ - name_template: "{{ .ProjectName }}-{{ .Version }}-{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
+ builds:
+ - fzf
+ format: tar.gz
+ format_overrides:
+ - goos: windows
+ format: zip
+ files:
+ - non-existent*
+
+release:
+ github:
+ owner: junegunn
+ name: fzf
+ prerelease: auto
+ name_template: '{{ .Tag }}'
+ extra_files:
+ - glob: ./dist/fzf-*darwin*.zip
+
+snapshot:
+ name_template: "{{ .Tag }}-devel"
+
+changelog:
+ sort: asc
+ filters:
+ exclude:
+ - README
+ - test
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.rubocop.yml b/dot-oh-my-zsh/custom/plugins/fzf/.rubocop.yml
new file mode 100644
index 00000000..c131debb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.rubocop.yml
@@ -0,0 +1,28 @@
+Layout/LineLength:
+ Enabled: false
+Metrics:
+ Enabled: false
+Lint/ShadowingOuterLocalVariable:
+ Enabled: false
+Style/MethodCallWithArgsParentheses:
+ Enabled: true
+ IgnoredMethods:
+ - assert
+ - exit
+ - paste
+ - puts
+ - raise
+ - refute
+ - require
+ - send_keys
+ IgnoredPatterns:
+ - ^assert_
+ - ^refute_
+Style/NumericPredicate:
+ Enabled: false
+Style/StringConcatenation:
+ Enabled: false
+Style/OptionalBooleanParameter:
+ Enabled: false
+Style/WordArray:
+ MinSize: 1
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/.tool-versions b/dot-oh-my-zsh/custom/plugins/fzf/.tool-versions
new file mode 100644
index 00000000..1799f52f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/.tool-versions
@@ -0,0 +1 @@
+golang 1.19
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/ADVANCED.md b/dot-oh-my-zsh/custom/plugins/fzf/ADVANCED.md
new file mode 100644
index 00000000..dcff947c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/ADVANCED.md
@@ -0,0 +1,609 @@
+Advanced fzf examples
+======================
+
+*(Last update: 2022/08/25)*
+
+<!-- vim-markdown-toc GFM -->
+
+* [Introduction](#introduction)
+* [Screen Layout](#screen-layout)
+ * [`--height`](#--height)
+ * [`fzf-tmux`](#fzf-tmux)
+ * [Popup window support](#popup-window-support)
+* [Dynamic reloading of the list](#dynamic-reloading-of-the-list)
+ * [Updating the list of processes by pressing CTRL-R](#updating-the-list-of-processes-by-pressing-ctrl-r)
+ * [Toggling between data sources](#toggling-between-data-sources)
+* [Ripgrep integration](#ripgrep-integration)
+ * [Using fzf as the secondary filter](#using-fzf-as-the-secondary-filter)
+ * [Using fzf as interative Ripgrep launcher](#using-fzf-as-interative-ripgrep-launcher)
+ * [Switching to fzf-only search mode](#switching-to-fzf-only-search-mode)
+ * [Switching between Ripgrep mode and fzf mode](#switching-between-ripgrep-mode-and-fzf-mode)
+* [Log tailing](#log-tailing)
+* [Key bindings for git objects](#key-bindings-for-git-objects)
+ * [Files listed in `git status`](#files-listed-in-git-status)
+ * [Branches](#branches)
+ * [Commit hashes](#commit-hashes)
+* [Color themes](#color-themes)
+ * [Generating fzf color theme from Vim color schemes](#generating-fzf-color-theme-from-vim-color-schemes)
+
+<!-- vim-markdown-toc -->
+
+Introduction
+------------
+
+fzf is an interactive [Unix filter][filter] program that is designed to be
+used with other Unix tools. It reads a list of items from the standard input,
+allows you to select a subset of the items, and prints the selected ones to
+the standard output. You can think of it as an interactive version of *grep*,
+and it's already useful even if you don't know any of its options.
+
+```sh
+# 1. ps: Feed the list of processes to fzf
+# 2. fzf: Interactively select a process using fuzzy matching algorithm
+# 3. awk: Take the PID from the selected line
+# 3. kill: Kill the process with the PID
+ps -ef | fzf | awk '{print $2}' | xargs kill -9
+```
+
+[filter]: https://en.wikipedia.org/wiki/Filter_(software)
+
+While the above example succinctly summarizes the fundamental concept of fzf,
+you can build much more sophisticated interactive workflows using fzf once you
+learn its wide variety of features.
+
+- To see the full list of options and features, see `man fzf`
+- To see the latest additions, see [CHANGELOG.md](CHANGELOG.md)
+
+This document will guide you through some examples that will familiarize you
+with the advanced features of fzf.
+
+Screen Layout
+-------------
+
+### `--height`
+
+fzf by default opens in fullscreen mode, but it's not always desirable.
+Oftentimes, you want to see the current context of the terminal while using
+fzf. `--height` is an option for opening fzf below the cursor in
+non-fullscreen mode so you can still see the previous commands and their
+results above it.
+
+```sh
+fzf --height=40%
+```
+
+![image](https://user-images.githubusercontent.com/700826/113379893-c184c680-93b5-11eb-9676-c7c0a2f01748.png)
+
+You might also want to experiment with other layout options such as
+`--layout=reverse`, `--info=inline`, `--border`, `--margin`, etc.
+
+```sh
+fzf --height=40% --layout=reverse
+fzf --height=40% --layout=reverse --info=inline
+fzf --height=40% --layout=reverse --info=inline --border
+fzf --height=40% --layout=reverse --info=inline --border --margin=1
+fzf --height=40% --layout=reverse --info=inline --border --margin=1 --padding=1
+```
+
+![image](https://user-images.githubusercontent.com/700826/113379932-dfeac200-93b5-11eb-9e28-df1a2ee71f90.png)
+
+*(See `Layout` section of the man page to see the full list of options)*
+
+But you definitely don't want to repeat `--height=40% --layout=reverse
+--info=inline --border --margin=1 --padding=1` every time you use fzf. You
+could write a wrapper script or shell alias, but there is an easier option.
+Define `$FZF_DEFAULT_OPTS` like so:
+
+```sh
+export FZF_DEFAULT_OPTS="--height=40% --layout=reverse --info=inline --border --margin=1 --padding=1"
+```
+
+### `fzf-tmux`
+
+Before fzf had `--height` option, we would open fzf in a tmux split pane not
+to take up the whole screen. This is done using `fzf-tmux` script.
+
+```sh
+# Open fzf on a tmux split pane below the current pane.
+# Takes the same set of options.
+fzf-tmux --layout=reverse
+```
+
+![image](https://user-images.githubusercontent.com/700826/113379973-f1cc6500-93b5-11eb-8860-c9bc4498aadf.png)
+
+The limitation of `fzf-tmux` is that it only works when you're on tmux unlike
+`--height` option. But the advantage of it is that it's more flexible.
+(See `man fzf-tmux` for available options.)
+
+```sh
+# On the right (50%)
+fzf-tmux -r
+
+# On the left (30%)
+fzf-tmux -l30%
+
+# Above the cursor
+fzf-tmux -u30%
+```
+
+![image](https://user-images.githubusercontent.com/700826/113379983-fa24a000-93b5-11eb-93eb-8a3d39b2f163.png)
+
+![image](https://user-images.githubusercontent.com/700826/113380001-0577cb80-93b6-11eb-95d0-2ba453866882.png)
+
+![image](https://user-images.githubusercontent.com/700826/113380040-1d4f4f80-93b6-11eb-9bef-737fb120aafe.png)
+
+#### Popup window support
+
+But here's the really cool part; tmux 3.2 added support for popup windows. So
+you can open fzf in a popup window, which is quite useful if you frequently
+use split panes.
+
+```sh
+# Open tmux in a tmux popup window (default size: 50% of the screen)
+fzf-tmux -p
+
+# 80% width, 60% height
+fzf-tmux -p 80%,60%
+```
+
+![image](https://user-images.githubusercontent.com/700826/113380106-4a9bfd80-93b6-11eb-8cee-aeb1c4ce1a1f.png)
+
+> You might also want to check out my tmux plugins which support this popup
+> window layout.
+>
+> - https://github.com/junegunn/tmux-fzf-url
+> - https://github.com/junegunn/tmux-fzf-maccy
+
+Dynamic reloading of the list
+-----------------------------
+
+fzf can dynamically update the candidate list using an arbitrary program with
+`reload` bindings (The design document for `reload` can be found
+[here][reload]).
+
+[reload]: https://github.com/junegunn/fzf/issues/1750
+
+### Updating the list of processes by pressing CTRL-R
+
+This example shows how you can set up a binding for dynamically updating the
+list without restarting fzf.
+
+```sh
+(date; ps -ef) |
+ fzf --bind='ctrl-r:reload(date; ps -ef)' \
+ --header=$'Press CTRL-R to reload\n\n' --header-lines=2 \
+ --preview='echo {}' --preview-window=down,3,wrap \
+ --layout=reverse --height=80% | awk '{print $2}' | xargs kill -9
+```
+
+![image](https://user-images.githubusercontent.com/700826/113465047-200c7c00-946c-11eb-918c-268f37a900c8.png)
+
+- The initial command is `(date; ps -ef)`. It prints the current date and
+ time, and the list of the processes.
+- With `--header` option, you can show any message as the fixed header.
+- To disallow selecting the first two lines (`date` and `ps` header), we use
+ `--header-lines=2` option.
+- `--bind='ctrl-r:reload(date; ps -ef)'` binds CTRL-R to `reload` action that
+ runs `date; ps -ef`, so we can update the list of the processes by pressing
+ CTRL-R.
+- We use simple `echo {}` preview option, so we can see the entire line on the
+ preview window below even if it's too long
+
+### Toggling between data sources
+
+You're not limited to just one reload binding. Set up multiple bindings so
+you can switch between data sources.
+
+```sh
+find * | fzf --prompt 'All> ' \
+ --header 'CTRL-D: Directories / CTRL-F: Files' \
+ --bind 'ctrl-d:change-prompt(Directories> )+reload(find * -type d)' \
+ --bind 'ctrl-f:change-prompt(Files> )+reload(find * -type f)'
+```
+
+![image](https://user-images.githubusercontent.com/700826/113465073-4af6d000-946c-11eb-858f-2372c0955f67.png)
+
+![image](https://user-images.githubusercontent.com/700826/113465072-46321c00-946c-11eb-9b6f-cda3951df579.png)
+
+Ripgrep integration
+-------------------
+
+### Using fzf as the secondary filter
+
+* Requires [bat][bat]
+* Requires [Ripgrep][rg]
+
+[bat]: https://github.com/sharkdp/bat
+[rg]: https://github.com/BurntSushi/ripgrep
+
+fzf is pretty fast for filtering a list that you will rarely have to think
+about its performance. But it is not the right tool for searching for text
+inside many large files, and in that case you should definitely use something
+like [Ripgrep][rg].
+
+In the next example, Ripgrep is the primary filter that searches for the given
+text in files, and fzf is used as the secondary fuzzy filter that adds
+interactivity to the workflow. And we use [bat][bat] to show the matching line in
+the preview window.
+
+This is a bash script and it will not run as expected on other non-compliant
+shells. To avoid the compatibility issue, let's save this snippet as a script
+file called `rfv`.
+
+```bash
+#!/usr/bin/env bash
+
+# 1. Search for text in files using Ripgrep
+# 2. Interactively narrow down the list using fzf
+# 3. Open the file in Vim
+IFS=: read -ra selected < <(
+ rg --color=always --line-number --no-heading --smart-case "${*:-}" |
+ fzf --ansi \
+ --color "hl:-1:underline,hl+:-1:underline:reverse" \
+ --delimiter : \
+ --preview 'bat --color=always {1} --highlight-line {2}' \
+ --preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
+)
+[ -n "${selected[0]}" ] && vim "${selected[0]}" "+${selected[1]}"
+```
+
+And run it with an initial query string.
+
+```sh
+# Make the script executable
+chmod +x rfv
+
+# Run it with the initial query "algo"
+./rfv algo
+```
+
+> Ripgrep will perform the initial search and list all the lines that contain
+`algo`. Then we further narrow down the list on fzf.
+
+![image](https://user-images.githubusercontent.com/700826/113683873-a42a6200-96ff-11eb-9666-26ce4091b0e4.png)
+
+I know it's a lot to digest, let's try to break down the code.
+
+- Ripgrep prints the matching lines in the following format
+ ```
+ man/man1/fzf.1:54:.BI "--algo=" TYPE
+ man/man1/fzf.1:55:Fuzzy matching algorithm (default: v2)
+ man/man1/fzf.1:58:.BR v2 " Optimal scoring algorithm (quality)"
+ src/pattern_test.go:7: "github.com/junegunn/fzf/src/algo"
+ ```
+ The first token delimited by `:` is the file path, and the second token is
+ the line number of the matching line. They respectively correspond to `{1}`
+ and `{2}` in the preview command.
+ - `--preview 'bat --color=always {1} --highlight-line {2}'`
+- As we run `rg` with `--color=always` option, we should tell fzf to parse
+ ANSI color codes in the input by setting `--ansi`.
+- We customize how fzf colors various text elements using `--color` option.
+ `-1` tells fzf to keep the original color from the input. See `man fzf` for
+ available color options.
+- The value of `--preview-window` option consists of 5 components delimited
+ by `,`
+ 1. `up` — Position of the preview window
+ 1. `60%` — Size of the preview window
+ 1. `border-bottom` — Preview window border only on the bottom side
+ 1. `+{2}+3/3` — Scroll offset of the preview contents
+ 1. `~3` — Fixed header
+- Let's break down the latter two. We want to display the bat output in the
+ preview window with a certain scroll offset so that the matching line is
+ positioned near the center of the preview window.
+ - `+{2}` — The base offset is extracted from the second token
+ - `+3` — We add 3 lines to the base offset to compensate for the header
+ part of `bat` output
+ - ```
+ ───────┬──────────────────────────────────────────────────────────
+ │ File: CHANGELOG.md
+ ───────┼──────────────────────────────────────────────────────────
+ 1 │ CHANGELOG
+ 2 │ =========
+ 3 │
+ 4 │ 0.26.0
+ 5 │ ------
+ ```
+ - `/3` adjusts the offset so that the matching line is shown at a third
+ position in the window
+ - `~3` makes the top three lines fixed header so that they are always
+ visible regardless of the scroll offset
+- Once we selected a line, we open the file with `vim` (`vim
+ "${selected[0]}"`) and move the cursor to the line (`+${selected[1]}`).
+
+### Using fzf as interative Ripgrep launcher
+
+We have learned that we can bind `reload` action to a key (e.g.
+`--bind=ctrl-r:execute(ps -ef)`). In the next example, we are going to **bind
+`reload` action to `change` event** so that whenever the user *changes* the
+query string on fzf, `reload` action is triggered.
+
+Here is a variation of the above `rfv` script. fzf will restart Ripgrep every
+time the user updates the query string on fzf. Searching and filtering is
+completely done by Ripgrep, and fzf merely provides the interactive interface.
+So we lose the "fuzziness", but the performance will be better on larger
+projects, and it will free up memory as you narrow down the results.
+
+```bash
+#!/usr/bin/env bash
+
+# 1. Search for text in files using Ripgrep
+# 2. Interactively restart Ripgrep with reload action
+# 3. Open the file in Vim
+RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
+INITIAL_QUERY="${*:-}"
+IFS=: read -ra selected < <(
+ FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
+ fzf --ansi \
+ --disabled --query "$INITIAL_QUERY" \
+ --bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
+ --delimiter : \
+ --preview 'bat --color=always {1} --highlight-line {2}' \
+ --preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
+)
+[ -n "${selected[0]}" ] && vim "${selected[0]}" "+${selected[1]}"
+```
+
+![image](https://user-images.githubusercontent.com/700826/113684212-f9ff0a00-96ff-11eb-8737-7bb571d320cc.png)
+
+- Instead of starting fzf in `rg ... | fzf` form, we start fzf without an
+ explicit input, but with a custom `FZF_DEFAULT_COMMAND` variable. This way
+ fzf can kill the initial Ripgrep process it starts with the initial query.
+ Otherwise, the initial Ripgrep process will keep consuming system resources
+ even after `reload` is triggered.
+- Filtering is no longer a responsibility of fzf; hence `--disabled`
+- `{q}` in the reload command evaluates to the query string on fzf prompt.
+- `sleep 0.1` in the reload command is for "debouncing". This small delay will
+ reduce the number of intermediate Ripgrep processes while we're typing in
+ a query.
+
+### Switching to fzf-only search mode
+
+*(Requires fzf 0.27.1 or above)*
+
+In the previous example, we lost fuzzy matching capability as we completely
+delegated search functionality to Ripgrep. But we can dynamically switch to
+fzf-only search mode by *"unbinding"* `reload` action from `change` event.
+
+```sh
+#!/usr/bin/env bash
+
+# Two-phase filtering with Ripgrep and fzf
+#
+# 1. Search for text in files using Ripgrep
+# 2. Interactively restart Ripgrep with reload action
+# * Press alt-enter to switch to fzf-only filtering
+# 3. Open the file in Vim
+RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
+INITIAL_QUERY="${*:-}"
+IFS=: read -ra selected < <(
+ FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
+ fzf --ansi \
+ --color "hl:-1:underline,hl+:-1:underline:reverse" \
+ --disabled --query "$INITIAL_QUERY" \
+ --bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
+ --bind "alt-enter:unbind(change,alt-enter)+change-prompt(2. fzf> )+enable-search+clear-query" \
+ --prompt '1. ripgrep> ' \
+ --delimiter : \
+ --preview 'bat --color=always {1} --highlight-line {2}' \
+ --preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
+)
+[ -n "${selected[0]}" ] && vim "${selected[0]}" "+${selected[1]}"
+```
+
+* Phase 1. Filtering with Ripgrep
+![image](https://user-images.githubusercontent.com/700826/119213880-735e8a80-bafd-11eb-8493-123e4be24fbc.png)
+* Phase 2. Filtering with fzf
+![image](https://user-images.githubusercontent.com/700826/119213887-7e191f80-bafd-11eb-98c9-71a1af9d7aab.png)
+
+- We added `--prompt` option to show that fzf is initially running in "Ripgrep
+ launcher mode".
+- We added `alt-enter` binding that
+ 1. unbinds `change` event, so Ripgrep is no longer restarted on key press
+ 2. changes the prompt to `2. fzf>`
+ 3. enables search functionality of fzf
+ 4. clears the current query string that was used to start Ripgrep process
+ 5. and unbinds `alt-enter` itself as this is a one-off event
+- We reverted `--color` option for customizing how the matching chunks are
+ displayed in the second phase
+
+### Switching between Ripgrep mode and fzf mode
+
+*(Requires fzf 0.30.0 or above)*
+
+fzf 0.30.0 added `rebind` action so we can "rebind" the bindings that were
+previously "unbound" via `unbind`.
+
+This is an improved version of the previous example that allows us to switch
+between Ripgrep launcher mode and fzf-only filtering mode via CTRL-R and
+CTRL-F.
+
+```sh
+#!/usr/bin/env bash
+
+# Switch between Ripgrep launcher mode (CTRL-R) and fzf filtering mode (CTRL-F)
+RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
+INITIAL_QUERY="${*:-}"
+IFS=: read -ra selected < <(
+ FZF_DEFAULT_COMMAND="$RG_PREFIX $(printf %q "$INITIAL_QUERY")" \
+ fzf --ansi \
+ --color "hl:-1:underline,hl+:-1:underline:reverse" \
+ --disabled --query "$INITIAL_QUERY" \
+ --bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
+ --bind "ctrl-f:unbind(change,ctrl-f)+change-prompt(2. fzf> )+enable-search+clear-query+rebind(ctrl-r)" \
+ --bind "ctrl-r:unbind(ctrl-r)+change-prompt(1. ripgrep> )+disable-search+reload($RG_PREFIX {q} || true)+rebind(change,ctrl-f)" \
+ --prompt '1. Ripgrep> ' \
+ --delimiter : \
+ --header '╱ CTRL-R (Ripgrep mode) ╱ CTRL-F (fzf mode) ╱' \
+ --preview 'bat --color=always {1} --highlight-line {2}' \
+ --preview-window 'up,60%,border-bottom,+{2}+3/3,~3'
+)
+[ -n "${selected[0]}" ] && vim "${selected[0]}" "+${selected[1]}"
+```
+
+Log tailing
+-----------
+
+fzf can run long-running preview commands and render partial results before
+completion. And when you specify `follow` flag in `--preview-window` option,
+fzf will "`tail -f`" the result, automatically scrolling to the bottom.
+
+```bash
+# With "follow", preview window will automatically scroll to the bottom.
+# "\033[2J" is an ANSI escape sequence for clearing the screen.
+# When fzf reads this code it clears the previous preview contents.
+fzf --preview-window follow --preview 'for i in $(seq 100000); do
+ echo "$i"
+ sleep 0.01
+ (( i % 300 == 0 )) && printf "\033[2J"
+done'
+```
+
+![image](https://user-images.githubusercontent.com/700826/113473303-dd669600-94a3-11eb-88a9-1f61b996bb0e.png)
+
+Admittedly, that was a silly example. Here's a practical one for browsing
+Kubernetes pods.
+
+```bash
+pods() {
+ FZF_DEFAULT_COMMAND="kubectl get pods --all-namespaces" \
+ fzf --info=inline --layout=reverse --header-lines=1 \
+ --prompt "$(kubectl config current-context | sed 's/-context$//')> " \
+ --header $'╱ Enter (kubectl exec) ╱ CTRL-O (open log in editor) ╱ CTRL-R (reload) ╱\n\n' \
+ --bind 'ctrl-/:change-preview-window(80%,border-bottom|hidden|)' \
+ --bind 'enter:execute:kubectl exec -it --namespace {1} {2} -- bash > /dev/tty' \
+ --bind 'ctrl-o:execute:${EDITOR:-vim} <(kubectl logs --all-containers --namespace {1} {2}) > /dev/tty' \
+ --bind 'ctrl-r:reload:$FZF_DEFAULT_COMMAND' \
+ --preview-window up:follow \
+ --preview 'kubectl logs --follow --all-containers --tail=10000 --namespace {1} {2}' "$@"
+}
+```
+
+![image](https://user-images.githubusercontent.com/700826/113473547-1d7a4880-94a5-11eb-98ef-9aa6f0ed215a.png)
+
+- The preview window will *"log tail"* the pod
+ - Holding on to a large amount of log will consume a lot of memory. So we
+ limited the initial log amount with `--tail=10000`.
+- `execute` bindings allow you to run any command without leaving fzf
+ - Press enter key on a pod to `kubectl exec` into it
+ - Press CTRL-O to open the log in your editor
+- Press CTRL-R to reload the pod list
+- Press CTRL-/ repeatedly to to rotate through a different sets of preview
+ window options
+ 1. `80%,border-bottom`
+ 1. `hidden`
+ 1. Empty string after `|` translates to the default options from `--preview-window`
+
+Key bindings for git objects
+----------------------------
+
+Oftentimes, you want to put the identifiers of various Git object to the
+command-line. For example, it is common to write commands like these:
+
+```sh
+git checkout [SOME_COMMIT_HASH or BRANCH or TAG]
+git diff [SOME_COMMIT_HASH or BRANCH or TAG] [SOME_COMMIT_HASH or BRANCH or TAG]
+```
+
+[fzf-git.sh](https://github.com/junegunn/fzf-git.sh) project defines a set of
+fzf-based key bindings for Git objects. I strongly recommend that you check
+them out because they are seriously useful.
+
+### Files listed in `git status`
+
+<kbd>CTRL-G</kbd><kbd>CTRL-F</kbd>
+
+![image](https://user-images.githubusercontent.com/700826/113473779-a9d93b00-94a6-11eb-87b5-f62a8d0a0efc.png)
+
+### Branches
+
+<kbd>CTRL-G</kbd><kbd>CTRL-B</kbd>
+
+![image](https://user-images.githubusercontent.com/700826/113473758-87dfb880-94a6-11eb-82f4-9218103f10bd.png)
+
+### Commit hashes
+
+<kbd>CTRL-G</kbd><kbd>CTRL-H</kbd>
+
+![image](https://user-images.githubusercontent.com/700826/113473765-91692080-94a6-11eb-8d38-ed4d41f27ac1.png)
+
+Color themes
+------------
+
+You can customize how fzf colors the text elements with `--color` option. Here
+are a few color themes. Note that you need a terminal emulator that can
+display 24-bit colors.
+
+```sh
+# junegunn/seoul256.vim (dark)
+export FZF_DEFAULT_OPTS='--color=bg+:#3F3F3F,bg:#4B4B4B,border:#6B6B6B,spinner:#98BC99,hl:#719872,fg:#D9D9D9,header:#719872,info:#BDBB72,pointer:#E12672,marker:#E17899,fg+:#D9D9D9,preview-bg:#3F3F3F,prompt:#98BEDE,hl+:#98BC99'
+```
+
+![seoul256](https://user-images.githubusercontent.com/700826/113475011-2c192d80-94ae-11eb-9d17-1e5867bae01f.png)
+
+```sh
+# junegunn/seoul256.vim (light)
+export FZF_DEFAULT_OPTS='--color=bg+:#D9D9D9,bg:#E1E1E1,border:#C8C8C8,spinner:#719899,hl:#719872,fg:#616161,header:#719872,info:#727100,pointer:#E12672,marker:#E17899,fg+:#616161,preview-bg:#D9D9D9,prompt:#0099BD,hl+:#719899'
+```
+
+![seoul256-light](https://user-images.githubusercontent.com/700826/113475022-389d8600-94ae-11eb-905f-0939dd535837.png)
+
+```sh
+# morhetz/gruvbox
+export FZF_DEFAULT_OPTS='--color=bg+:#3c3836,bg:#32302f,spinner:#fb4934,hl:#928374,fg:#ebdbb2,header:#928374,info:#8ec07c,pointer:#fb4934,marker:#fb4934,fg+:#ebdbb2,prompt:#fb4934,hl+:#fb4934'
+```
+
+![gruvbox](https://user-images.githubusercontent.com/700826/113475042-494dfc00-94ae-11eb-9322-cd03a027305a.png)
+
+```sh
+# arcticicestudio/nord-vim
+export FZF_DEFAULT_OPTS='--color=bg+:#3B4252,bg:#2E3440,spinner:#81A1C1,hl:#616E88,fg:#D8DEE9,header:#616E88,info:#81A1C1,pointer:#81A1C1,marker:#81A1C1,fg+:#D8DEE9,prompt:#81A1C1,hl+:#81A1C1'
+```
+
+![nord](https://user-images.githubusercontent.com/700826/113475063-67b3f780-94ae-11eb-9b24-5f0d22b63399.png)
+
+```sh
+# tomasr/molokai
+export FZF_DEFAULT_OPTS='--color=bg+:#293739,bg:#1B1D1E,border:#808080,spinner:#E6DB74,hl:#7E8E91,fg:#F8F8F2,header:#7E8E91,info:#A6E22E,pointer:#A6E22E,marker:#F92672,fg+:#F8F8F2,prompt:#F92672,hl+:#F92672'
+```
+
+![molokai](https://user-images.githubusercontent.com/700826/113475085-8619f300-94ae-11eb-85e4-2766fc3246bf.png)
+
+### Generating fzf color theme from Vim color schemes
+
+The Vim plugin of fzf can generate `--color` option from the current color
+scheme according to `g:fzf_colors` variable. You can find the detailed
+explanation [here](https://github.com/junegunn/fzf/blob/master/README-VIM.md#explanation-of-gfzf_colors).
+
+Here is an example. Add this to your Vim configuration file.
+
+```vim
+let g:fzf_colors =
+\ { 'fg': ['fg', 'Normal'],
+ \ 'bg': ['bg', 'Normal'],
+ \ 'preview-bg': ['bg', 'NormalFloat'],
+ \ 'hl': ['fg', 'Comment'],
+ \ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
+ \ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
+ \ 'hl+': ['fg', 'Statement'],
+ \ 'info': ['fg', 'PreProc'],
+ \ 'border': ['fg', 'Ignore'],
+ \ 'prompt': ['fg', 'Conditional'],
+ \ 'pointer': ['fg', 'Exception'],
+ \ 'marker': ['fg', 'Keyword'],
+ \ 'spinner': ['fg', 'Label'],
+ \ 'header': ['fg', 'Comment'] }
+```
+
+Then you can see how the `--color` option is generated by printing the result
+of `fzf#wrap()`.
+
+```vim
+:echo fzf#wrap()
+```
+
+Use this command to append `export FZF_DEFAULT_OPTS="..."` line to the end of
+the current file.
+
+```vim
+:call append('$', printf('export FZF_DEFAULT_OPTS="%s"', matchstr(fzf#wrap().options, "--color[^']*")))
+```
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/BUILD.md b/dot-oh-my-zsh/custom/plugins/fzf/BUILD.md
new file mode 100644
index 00000000..bbff0520
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/BUILD.md
@@ -0,0 +1,49 @@
+Building fzf
+============
+
+Build instructions
+------------------
+
+### Prerequisites
+
+- Go 1.17 or above
+
+### Using Makefile
+
+```sh
+# Build fzf binary for your platform in target
+make
+
+# Build fzf binary and copy it to bin directory
+make install
+
+# Build fzf binaries and archives for all platforms using goreleaser
+make build
+
+# Publish GitHub release
+make release
+```
+
+> :warning: Makefile uses git commands to determine the version and the
+> revision information for `fzf --version`. So if you're building fzf from an
+> environment where its git information is not available, you have to manually
+> set `$FZF_VERSION` and `$FZF_REVISION`.
+>
+> e.g. `FZF_VERSION=0.24.0 FZF_REVISION=tarball make`
+
+Third-party libraries used
+--------------------------
+
+- [mattn/go-runewidth](https://github.com/mattn/go-runewidth)
+ - Licensed under [MIT](http://mattn.mit-license.org)
+- [mattn/go-shellwords](https://github.com/mattn/go-shellwords)
+ - Licensed under [MIT](http://mattn.mit-license.org)
+- [mattn/go-isatty](https://github.com/mattn/go-isatty)
+ - Licensed under [MIT](http://mattn.mit-license.org)
+- [tcell](https://github.com/gdamore/tcell)
+ - Licensed under [Apache License 2.0](https://github.com/gdamore/tcell/blob/master/LICENSE)
+
+License
+-------
+
+[MIT](LICENSE)
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/CHANGELOG.md b/dot-oh-my-zsh/custom/plugins/fzf/CHANGELOG.md
new file mode 100644
index 00000000..29323b31
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/CHANGELOG.md
@@ -0,0 +1,1314 @@
+CHANGELOG
+=========
+
+0.33.0
+------
+- Added `--scheme=[default|path|history]` option to choose scoring scheme
+ - (Experimental)
+ - We updated the scoring algorithm in 0.32.0, however we have learned that
+ this new scheme (`default`) is not always giving the optimal result
+ - `path`: Additional bonus point is only given to the characters after
+ path separator. You might want to choose this scheme if you have many
+ files with spaces in their paths.
+ - `history`: No additional bonus points are given so that we give more
+ weight to the chronological ordering. This is equivalent to the scoring
+ scheme before 0.32.0. This also sets `--tiebreak=index`.
+- ANSI color sequences with colon delimiters are now supported.
+ ```sh
+ printf "\e[38;5;208mOption 1\e[m\nOption 2" | fzf --ansi
+ printf "\e[38:5:208mOption 1\e[m\nOption 2" | fzf --ansi
+ ```
+- Support `border-{up,down}` as the synonyms for `border-{top,bottom}` in
+ `--preview-window`
+- Added support for ANSI `strikethrough`
+ ```sh
+ printf "\e[9mdeleted" | fzf --ansi
+ fzf --color fg+:strikethrough
+ ```
+
+0.32.1
+------
+- Fixed incorrect ordering of `--tiebreak=chunk`
+- fzf-tmux will show fzf border instead of tmux popup border (requires tmux 3.3)
+ ```sh
+ fzf-tmux -p70%
+ fzf-tmux -p70% --color=border:bright-red
+ fzf-tmux -p100%,60% --color=border:bright-yellow --border=horizontal --padding 1,5 --margin 1,0
+ fzf-tmux -p70%,100% --color=border:bright-green --border=vertical
+
+ # Key bindings (CTRL-T, CTRL-R, ALT-C) will use these options
+ export FZF_TMUX_OPTS='-p100%,60% --color=border:green --border=horizontal --padding 1,5 --margin 1,0'
+ ```
+
+0.32.0
+------
+- Updated the scoring algorithm
+ - Different bonus points to different categories of word boundaries
+ (listed higher to lower bonus point)
+ - Word after whitespace characters or beginning of the string
+ - Word after common delimiter characters (`/,:;|`)
+ - Word after other non-word characters
+ ```sh
+ # foo/bar.sh` is preferred over `foo-bar.sh` on `bar`
+ fzf --query=bar --height=4 << EOF
+ foo-bar.sh
+ foo/bar.sh
+ EOF
+ ```
+- Added a new tiebreak `chunk`
+ - Favors the line with shorter matched chunk. A chunk is a set of
+ consecutive non-whitespace characters.
+ - Unlike the default `length`, this scheme works well with tabular input
+ ```sh
+ # length prefers item #1, because the whole line is shorter,
+ # chunk prefers item #2, because the matched chunk ("foo") is shorter
+ fzf --height=6 --header-lines=2 --tiebreak=chunk --reverse --query=fo << "EOF"
+ N | Field1 | Field2 | Field3
+ - | ------ | ------ | ------
+ 1 | hello | foobar | baz
+ 2 | world | foo | bazbaz
+ EOF
+ ```
+ - If the input does not contain any spaces, `chunk` is equivalent to
+ `length`. But we're not going to set it as the default because it is
+ computationally more expensive.
+- Bug fixes and improvements
+
+0.31.0
+------
+- Added support for an alternative preview window layout that is activated
+ when the size of the preview window is smaller than a certain threshold.
+ ```sh
+ # If the width of the preview window is smaller than 50 columns,
+ # it will be displayed above the search window.
+ fzf --preview 'cat {}' --preview-window 'right,50%,border-left,<50(up,30%,border-bottom)'
+
+ # Or you can just hide it like so
+ fzf --preview 'cat {}' --preview-window '<50(hidden)'
+ ```
+- fzf now uses SGR mouse mode to properly support mouse on larger terminals
+- You can now use characters that do not satisfy `unicode.IsGraphic` constraint
+ for `--marker`, `--pointer`, and `--ellipsis`. Allows Nerd Fonts and stuff.
+ Use at your own risk.
+- Bug fixes and improvements
+- Shell extension
+ - `kill` completion now requires trigger sequence (`**`) for consistency
+
+0.30.0
+------
+- Fixed cursor flickering over the screen by hiding it during rendering
+- Added `--ellipsis` option. You can take advantage of it to make fzf
+ effectively search non-visible parts of the item.
+ ```sh
+ # Search against hidden line numbers on the far right
+ nl /usr/share/dict/words |
+ awk '{printf "%s%1000s\n", $2, $1}' |
+ fzf --nth=-1 --no-hscroll --ellipsis='' |
+ awk '{print $2}'
+ ```
+- Added `rebind` action for restoring bindings after `unbind`
+- Bug fixes and improvements
+
+0.29.0
+------
+- Added `change-preview(...)` action to change the `--preview` command
+ - cf. `preview(...)` is a one-off action that doesn't change the default
+ preview command
+- Added `change-preview-window(...)` action
+ - You can rotate through the different options separated by `|`
+ ```sh
+ fzf --preview 'cat {}' --preview-window right:40% \
+ --bind 'ctrl-/:change-preview-window(right,70%|down,40%,border-top|hidden|)'
+ ```
+- Fixed rendering of the prompt line when overflow occurs with `--info=inline`
+
+0.28.0
+------
+- Added `--header-first` option to print header before the prompt line
+ ```sh
+ fzf --header $'Welcome to fzf\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔' --reverse --height 30% --border --header-first
+ ```
+- Added `--scroll-off=LINES` option (similar to `scrolloff` option of Vim)
+ - You can set it to a very large number so that the cursor stays in the
+ middle of the screen while scrolling
+ ```sh
+ fzf --scroll-off=5
+ fzf --scroll-off=999
+ ```
+- Fixed bug where preview window is not updated on `reload` (#2644)
+- fzf on Windows will also use `$SHELL` to execute external programs
+ - See #2638 and #2647
+ - Thanks to @rashil2000, @vovcacik, and @janlazo
+
+0.27.3
+------
+- Preview window is `hidden` by default when there are `preview` bindings but
+ `--preview` command is not given
+- Fixed bug where `{n}` is not properly reset on `reload`
+- Fixed bug where spinner is not displayed on `reload`
+- Enhancements in tcell renderer for Windows (#2616)
+- Vim plugin
+ - `sinklist` is added as a synonym to `sink*` so that it's easier to add
+ a function to a spec dictionary
+ ```vim
+ let spec = { 'source': 'ls', 'options': ['--multi', '--preview', 'cat {}'] }
+ function spec.sinklist(matches)
+ echom string(a:matches)
+ endfunction
+
+ call fzf#run(fzf#wrap(spec))
+ ```
+ - Vim 7 compatibility
+
+0.27.2
+------
+- 16 base ANSI colors can be specified by their names
+ ```sh
+ fzf --color fg:3,fg+:11
+ fzf --color fg:yellow,fg+:bright-yellow
+ ```
+- Fix bug where `--read0` not properly displaying long lines
+
+0.27.1
+------
+- Added `unbind` action. In the following Ripgrep launcher example, you can
+ use `unbind(reload)` to switch to fzf-only filtering mode.
+ - See https://github.com/junegunn/fzf/blob/master/ADVANCED.md#switching-to-fzf-only-search-mode
+- Vim plugin
+ - Vim plugin will stop immediately even when the source command hasn't finished
+ ```vim
+ " fzf will read the stream file while allowing other processes to append to it
+ call fzf#run({'source': 'cat /dev/null > /tmp/stream; tail -f /tmp/stream'})
+ ```
+ - It is now possible to open popup window relative to the current window
+ ```vim
+ let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6, 'relative': v:true, 'yoffset': 1.0 } }
+ ```
+
+0.27.0
+------
+- More border options for `--preview-window`
+ ```sh
+ fzf --preview 'cat {}' --preview-window border-left
+ fzf --preview 'cat {}' --preview-window border-left --border horizontal
+ fzf --preview 'cat {}' --preview-window top:border-bottom
+ fzf --preview 'cat {}' --preview-window top:border-horizontal
+ ```
+- Automatically set `/dev/tty` as STDIN on execute action
+ ```sh
+ # Redirect /dev/tty to suppress "Vim: Warning: Input is not from a terminal"
+ # ls | fzf --bind "enter:execute(vim {} < /dev/tty)"
+
+ # "< /dev/tty" part is no longer needed
+ ls | fzf --bind "enter:execute(vim {})"
+ ```
+- Bug fixes and improvements
+- Signed and notarized macOS binaries
+ (Huge thanks to [BACKERS.md](https://github.com/junegunn/junegunn/blob/main/BACKERS.md)!)
+
+0.26.0
+------
+- Added support for fixed header in preview window
+ ```sh
+ # Display top 3 lines as the fixed header
+ fzf --preview 'bat --style=header,grid --color=always {}' --preview-window '~3'
+ ```
+- More advanced preview offset expression to better support the fixed header
+ ```sh
+ # Preview with bat, matching line in the middle of the window below
+ # the fixed header of the top 3 lines
+ #
+ # ~3 Top 3 lines as the fixed header
+ # +{2} Base scroll offset extracted from the second field
+ # +3 Extra offset to compensate for the 3-line header
+ # /2 Put in the middle of the preview area
+ #
+ git grep --line-number '' |
+ fzf --delimiter : \
+ --preview 'bat --style=full --color=always --highlight-line {2} {1}' \
+ --preview-window '~3:+{2}+3/2'
+ ```
+- Added `select` and `deselect` action for unconditionally selecting or
+ deselecting a single item in `--multi` mode. Complements `toggle` action.
+- Significant performance improvement in ANSI code processing
+- Bug fixes and improvements
+- Built with Go 1.16
+
+0.25.1
+------
+- Added `close` action
+ - Close preview window if open, abort fzf otherwise
+- Bug fixes and improvements
+
+0.25.0
+------
+- Text attributes set in `--color` are not reset when fzf sees another
+ `--color` option for the same element. This allows you to put custom text
+ attributes in your `$FZF_DEFAULT_OPTS` and still have those attributes
+ even when you override the colors.
+
+ ```sh
+ # Default colors and attributes
+ fzf
+
+ # Apply custom text attributes
+ export FZF_DEFAULT_OPTS='--color fg+:italic,hl:-1:underline,hl+:-1:reverse:underline'
+
+ fzf
+
+ # Different colors but you still have the attributes
+ fzf --color hl:176,hl+:177
+
+ # Write "regular" if you want to clear the attributes
+ fzf --color hl:176:regular,hl+:177:regular
+ ```
+- Renamed `--phony` to `--disabled`
+- You can dynamically enable and disable the search functionality using the
+ new `enable-search`, `disable-search`, and `toggle-search` actions
+- You can assign a different color to the query string for when search is disabled
+ ```sh
+ fzf --color query:#ffffff,disabled:#999999 --bind space:toggle-search
+ ```
+- Added `last` action to move the cursor to the last match
+ - The opposite action `top` is renamed to `first`, but `top` is still
+ recognized as a synonym for backward compatibility
+- Added `preview-top` and `preview-bottom` actions
+- Extended support for alt key chords: alt with any case-sensitive single character
+ ```sh
+ fzf --bind alt-,:first,alt-.:last
+ ```
+
+0.24.4
+------
+- Added `--preview-window` option `follow`
+ ```sh
+ # Preview window will automatically scroll to the bottom
+ fzf --preview-window follow --preview 'for i in $(seq 100000); do
+ echo "$i"
+ sleep 0.01
+ (( i % 300 == 0 )) && printf "\033[2J"
+ done'
+ ```
+- Added `change-prompt` action
+ ```sh
+ fzf --prompt 'foo> ' --bind $'a:change-prompt:\x1b[31mbar> '
+ ```
+- Bug fixes and improvements
+
+0.24.3
+------
+- Added `--padding` option
+ ```sh
+ fzf --margin 5% --padding 5% --border --preview 'cat {}' \
+ --color bg:#222222,preview-bg:#333333
+ ```
+
+0.24.2
+------
+- Bug fixes and improvements
+
+0.24.1
+------
+- Fixed broken `--color=[bw|no]` option
+
+0.24.0
+------
+- Real-time rendering of preview window
+ ```sh
+ # fzf can render preview window before the command completes
+ fzf --preview 'sleep 1; for i in $(seq 100); do echo $i; sleep 0.01; done'
+
+ # Preview window can process ANSI escape sequence (CSI 2 J) for clearing the display
+ fzf --preview 'for i in $(seq 100000); do
+ (( i % 200 == 0 )) && printf "\033[2J"
+ echo "$i"
+ sleep 0.01
+ done'
+ ```
+- Updated `--color` option to support text styles
+ - `regular` / `bold` / `dim` / `underline` / `italic` / `reverse` / `blink`
+ ```sh
+ # * Set -1 to keep the original color
+ # * Multiple style attributes can be combined
+ # * Italic style may not be supported by some terminals
+ rg --line-number --no-heading --color=always "" |
+ fzf --ansi --prompt "Rg: " \
+ --color fg+:italic,hl:underline:-1,hl+:italic:underline:reverse:-1 \
+ --color pointer:reverse,prompt:reverse,input:159 \
+ --pointer ' '
+ ```
+- More `--border` options
+ - `vertical`, `top`, `bottom`, `left`, `right`
+ - Updated Vim plugin to use these new `--border` options
+ ```vim
+ " Floating popup window in the center of the screen
+ let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
+
+ " Popup with 100% width
+ let g:fzf_layout = { 'window': { 'width': 1.0, 'height': 0.5, 'border': 'horizontal' } }
+
+ " Popup with 100% height
+ let g:fzf_layout = { 'window': { 'width': 0.5, 'height': 1.0, 'border': 'vertical' } }
+
+ " Similar to 'down' layout, but it uses a popup window and doesn't affect the window layout
+ let g:fzf_layout = { 'window': { 'width': 1.0, 'height': 0.5, 'yoffset': 1.0, 'border': 'top' } }
+
+ " Opens on the right;
+ " 'highlight' option is still supported but it will only take the foreground color of the group
+ let g:fzf_layout = { 'window': { 'width': 0.5, 'height': 1.0, 'xoffset': 1.0, 'border': 'left', 'highlight': 'Comment' } }
+ ```
+- To indicate if `--multi` mode is enabled, fzf will print the number of
+ selected items even when no item is selected
+ ```sh
+ seq 100 | fzf
+ # 100/100
+ seq 100 | fzf --multi
+ # 100/100 (0)
+ seq 100 | fzf --multi 5
+ # 100/100 (0/5)
+ ```
+- Since 0.24.0, release binaries will be uploaded to https://github.com/junegunn/fzf/releases
+
+0.23.1
+------
+- Added `--preview-window` options for disabling flags
+ - `nocycle`
+ - `nohidden`
+ - `nowrap`
+ - `default`
+- Built with Go 1.14.9 due to performance regression
+ - https://github.com/golang/go/issues/40727
+
+0.23.0
+------
+- Support preview scroll offset relative to window height
+ ```sh
+ git grep --line-number '' |
+ fzf --delimiter : \
+ --preview 'bat --style=numbers --color=always --highlight-line {2} {1}' \
+ --preview-window +{2}-/2
+ ```
+- Added `--preview-window` option for sharp edges (`--preview-window sharp`)
+- Added `--preview-window` option for cyclic scrolling (`--preview-window cycle`)
+- Reduced vertical padding around the preview window when `--preview-window
+ noborder` is used
+- Added actions for preview window
+ - `preview-half-page-up`
+ - `preview-half-page-down`
+- Vim
+ - Popup width and height can be given in absolute integer values
+ - Added `fzf#exec()` function for getting the path of fzf executable
+ - It also downloads the latest binary if it's not available by running
+ `./install --bin`
+- Built with Go 1.15.2
+ - We no longer provide 32-bit binaries
+
+0.22.0
+------
+- Added more options for `--bind`
+ - `backward-eof` event
+ ```sh
+ # Aborts when you delete backward when the query prompt is already empty
+ fzf --bind backward-eof:abort
+ ```
+ - `refresh-preview` action
+ ```sh
+ # Rerun preview command when you hit '?'
+ fzf --preview 'echo $RANDOM' --bind '?:refresh-preview'
+ ```
+ - `preview` action
+ ```sh
+ # Default preview command with an extra preview binding
+ fzf --preview 'file {}' --bind '?:preview:cat {}'
+
+ # A preview binding with no default preview command
+ # (Preview window is initially empty)
+ fzf --bind '?:preview:cat {}'
+
+ # Preview window hidden by default, it appears when you first hit '?'
+ fzf --bind '?:preview:cat {}' --preview-window hidden
+ ```
+- Added preview window option for setting the initial scroll offset
+ ```sh
+ # Initial scroll offset is set to the line number of each line of
+ # git grep output *minus* 5 lines
+ git grep --line-number '' |
+ fzf --delimiter : --preview 'nl {1}' --preview-window +{2}-5
+ ```
+- Added support for ANSI colors in `--prompt` string
+- Smart match of accented characters
+ - An unaccented character in the query string will match both accented and
+ unaccented characters, while an accented character will only match
+ accented characters. This is similar to how "smart-case" match works.
+- Vim plugin
+ - `tmux` layout option for using fzf-tmux
+ ```vim
+ let g:fzf_layout = { 'tmux': '-p90%,60%' }
+ ```
+
+0.21.1
+------
+- Shell extension
+ - CTRL-R will remove duplicate commands
+- fzf-tmux
+ - Supports tmux popup window (require tmux 3.2 or above)
+ - ```sh
+ # 50% width and height
+ fzf-tmux -p
+
+ # 80% width and height
+ fzf-tmux -p 80%
+
+ # 80% width and 40% height
+ fzf-tmux -p 80%,40%
+ fzf-tmux -w 80% -h 40%
+
+ # Window position
+ fzf-tmux -w 80% -h 40% -x 0 -y 0
+ fzf-tmux -w 80% -h 40% -y 1000
+
+ # Write ordinary fzf options after --
+ fzf-tmux -p -- --reverse --info=inline --margin 2,4 --border
+ ```
+ - On macOS, you can build the latest tmux from the source with
+ `brew install tmux --HEAD`
+- Bug fixes
+ - Fixed Windows file traversal not to include directories
+ - Fixed ANSI colors with `--keep-right`
+ - Fixed _fzf_complete for zsh
+- Built with Go 1.14.1
+
+0.21.0
+------
+- `--height` option is now available on Windows as well (@kelleyma49)
+- Added `--pointer` and `--marker` options
+- Added `--keep-right` option that keeps the right end of the line visible
+ when it's too long
+- Style changes
+ - `--border` will now print border with rounded corners around the
+ finder instead of printing horizontal lines above and below it.
+ The previous style is available via `--border=horizontal`
+ - Unicode spinner
+- More keys and actions for `--bind`
+- Added PowerShell script for downloading Windows binary
+- Vim plugin: Built-in floating windows support
+ ```vim
+ let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
+ ```
+- bash: Various improvements in key bindings (CTRL-T, CTRL-R, ALT-C)
+ - CTRL-R will start with the current command-line as the initial query
+ - CTRL-R properly supports multi-line commands
+- Fuzzy completion API changed
+ ```sh
+ # Previous: fzf arguments given as a single string argument
+ # - This style is still supported, but it's deprecated
+ _fzf_complete "--multi --reverse --prompt=\"doge> \"" "$@" < <(
+ echo foo
+ )
+
+ # New API: multiple fzf arguments before "--"
+ # - Easier to write multiple options
+ _fzf_complete --multi --reverse --prompt="doge> " -- "$@" < <(
+ echo foo
+ )
+ ```
+- Bug fixes and improvements
+
+0.20.0
+------
+- Customizable preview window color (`preview-fg` and `preview-bg` for `--color`)
+ ```sh
+ fzf --preview 'cat {}' \
+ --color 'fg:#bbccdd,fg+:#ddeeff,bg:#334455,preview-bg:#223344,border:#778899' \
+ --border --height 20 --layout reverse --info inline
+ ```
+- Removed the immediate flicking of the screen on `reload` action.
+ ```sh
+ : | fzf --bind 'change:reload:seq {q}' --phony
+ ```
+- Added `clear-query` and `clear-selection` actions for `--bind`
+- It is now possible to split a composite bind action over multiple `--bind`
+ expressions by prefixing the later ones with `+`.
+ ```sh
+ fzf --bind 'ctrl-a:up+up'
+
+ # Can be now written as
+ fzf --bind 'ctrl-a:up' --bind 'ctrl-a:+up'
+
+ # This is useful when you need to write special execute/reload form (i.e. `execute:...`)
+ # to avoid parse errors and add more actions to the same key
+ fzf --multi --bind 'ctrl-l:select-all+execute:less {+f}' --bind 'ctrl-l:+deselect-all'
+ ```
+- Fixed parse error of `--bind` expression where concatenated execute/reload
+ action contains `+` character.
+ ```sh
+ fzf --multi --bind 'ctrl-l:select-all+execute(less {+f})+deselect-all'
+ ```
+- Fixed bugs of reload action
+ - Not triggered when there's no match even when the command doesn't have
+ any placeholder expressions
+ - Screen not properly cleared when `--header-lines` not filled on reload
+
+0.19.0
+------
+
+- Added `--phony` option which completely disables search functionality.
+ Useful when you want to use fzf only as a selector interface. See below.
+- Added "reload" action for dynamically updating the input list without
+ restarting fzf. See https://github.com/junegunn/fzf/issues/1750 to learn
+ more about it.
+ ```sh
+ # Using fzf as the selector interface for ripgrep
+ RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
+ INITIAL_QUERY="foo"
+ FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY' || true" \
+ fzf --bind "change:reload:$RG_PREFIX {q} || true" \
+ --ansi --phony --query "$INITIAL_QUERY"
+ ```
+- `--multi` now takes an optional integer argument which indicates the maximum
+ number of items that can be selected
+ ```sh
+ seq 100 | fzf --multi 3 --reverse --height 50%
+ ```
+- If a placeholder expression for `--preview` and `execute` action (and the
+ new `reload` action) contains `f` flag, it is replaced to the
+ path of a temporary file that holds the evaluated list. This is useful
+ when you multi-select a large number of items and the length of the
+ evaluated string may exceed [`ARG_MAX`][argmax].
+ ```sh
+ # Press CTRL-A to select 100K items and see the sum of all the numbers
+ seq 100000 | fzf --multi --bind ctrl-a:select-all \
+ --preview "awk '{sum+=\$1} END {print sum}' {+f}"
+ ```
+- `deselect-all` no longer deselects unmatched items. It is now consistent
+ with `select-all` and `toggle-all` in that it only affects matched items.
+- Due to the limitation of bash, fuzzy completion is enabled by default for
+ a fixed set of commands. A helper function for easily setting up fuzzy
+ completion for any command is now provided.
+ ```sh
+ # usage: _fzf_setup_completion path|dir COMMANDS...
+ _fzf_setup_completion path git kubectl
+ ```
+- Info line style can be changed by `--info=STYLE`
+ - `--info=default`
+ - `--info=inline` (same as old `--inline-info`)
+ - `--info=hidden`
+- Preview window border can be disabled by adding `noborder` to
+ `--preview-window`.
+- When you transform the input with `--with-nth`, the trailing white spaces
+ are removed.
+- `ctrl-\`, `ctrl-]`, `ctrl-^`, and `ctrl-/` can now be used with `--bind`
+- See https://github.com/junegunn/fzf/milestone/15?closed=1 for more details
+
+[argmax]: https://unix.stackexchange.com/questions/120642/what-defines-the-maximum-size-for-a-command-single-argument
+
+0.18.0
+------
+
+- Added placeholder expression for zero-based item index: `{n}` and `{+n}`
+ - `fzf --preview 'echo {n}: {}'`
+- Added color option for the gutter: `--color gutter:-1`
+- Added `--no-unicode` option for drawing borders in non-Unicode, ASCII
+ characters
+- `FZF_PREVIEW_LINES` and `FZF_PREVIEW_COLUMNS` are exported to preview process
+ - fzf still overrides `LINES` and `COLUMNS` as before, but they may be
+ reset by the default shell.
+- Bug fixes and improvements
+ - See https://github.com/junegunn/fzf/milestone/14?closed=1
+- Built with Go 1.12.1
+
+0.17.5
+------
+
+- Bug fixes and improvements
+ - See https://github.com/junegunn/fzf/milestone/13?closed=1
+- Search query longer than the screen width is allowed (up to 300 chars)
+- Built with Go 1.11.1
+
+0.17.4
+------
+
+- Added `--layout` option with a new layout called `reverse-list`.
+ - `--layout=reverse` is a synonym for `--reverse`
+ - `--layout=default` is a synonym for `--no-reverse`
+- Preview window will be updated even when there is no match for the query
+ if any of the placeholder expressions (e.g. `{q}`, `{+}`) evaluates to
+ a non-empty string.
+- More keys for binding: `shift-{up,down}`, `alt-{up,down,left,right}`
+- fzf can now start even when `/dev/tty` is not available by making an
+ educated guess.
+- Updated the default command for Windows.
+- Fixes and improvements on bash/zsh completion
+- install and uninstall scripts now supports generating files under
+ `XDG_CONFIG_HOME` on `--xdg` flag.
+
+See https://github.com/junegunn/fzf/milestone/12?closed=1 for the full list of
+changes.
+
+0.17.3
+------
+- `$LINES` and `$COLUMNS` are exported to preview command so that the command
+ knows the exact size of the preview window.
+- Better error messages when the default command or `$FZF_DEFAULT_COMMAND`
+ fails.
+- Reverted #1061 to avoid having duplicate entries in the list when find
+ command detected a file system loop (#1120). The default command now
+ requires that find supports `-fstype` option.
+- fzf now distinguishes mouse left click and right click (#1130)
+ - Right click is now bound to `toggle` action by default
+ - `--bind` understands `left-click` and `right-click`
+- Added `replace-query` action (#1137)
+ - Replaces query string with the current selection
+- Added `accept-non-empty` action (#1162)
+ - Same as accept, except that it prevents fzf from exiting without any
+ selection
+
+0.17.1
+------
+
+- Fixed custom background color of preview window (#1046)
+- Fixed background color issues of Windows binary
+- Fixed Windows binary to execute command using cmd.exe with no parsing and
+ escaping (#1072)
+- Added support for `window` layout on Vim 8 using Vim 8 terminal (#1055)
+
+0.17.0-2
+--------
+
+A maintenance release for auxiliary scripts. fzf binaries are not updated.
+
+- Experimental support for the builtin terminal of Vim 8
+ - fzf can now run inside GVim
+- Updated Vim plugin to better handle `&shell` issue on fish
+- Fixed a bug of fzf-tmux where invalid output is generated
+- Fixed fzf-tmux to work even when `tput` does not work
+
+0.17.0
+------
+- Performance optimization
+- One can match literal spaces in extended-search mode with a space prepended
+ by a backslash.
+- `--expect` is now additive and can be specified multiple times.
+
+0.16.11
+-------
+- Performance optimization
+- Fixed missing preview update
+
+0.16.10
+-------
+- Fixed invalid handling of ANSI colors in preview window
+- Further improved `--ansi` performance
+
+0.16.9
+------
+- Memory and performance optimization
+ - Around 20% performance improvement for general use cases
+ - Up to 5x faster processing of `--ansi`
+ - Up to 50% reduction of memory usage
+- Bug fixes and usability improvements
+ - Fixed handling of bracketed paste mode
+ - [ERROR] on info line when the default command failed
+ - More efficient rendering of preview window
+ - `--no-clear` updated for repetitive relaunching scenarios
+
+0.16.8
+------
+- New `change` event and `top` action for `--bind`
+ - `fzf --bind change:top`
+ - Move cursor to the top result whenever the query string is changed
+ - `fzf --bind 'ctrl-w:unix-word-rubout+top,ctrl-u:unix-line-discard+top'`
+ - `top` combined with `unix-word-rubout` and `unix-line-discard`
+- Fixed inconsistent tiebreak scores when `--nth` is used
+- Proper display of tab characters in `--prompt`
+- Fixed not to `--cycle` on page-up/page-down to prevent overshoot
+- Git revision in `--version` output
+- Basic support for Cygwin environment
+- Many fixes in Vim plugin on Windows/Cygwin (thanks to @janlazo)
+
+0.16.7
+------
+- Added support for `ctrl-alt-[a-z]` key chords
+- CTRL-Z (SIGSTOP) now works with fzf
+- fzf will export `$FZF_PREVIEW_WINDOW` so that the scripts can use it
+- Bug fixes and improvements in Vim plugin and shell extensions
+
+0.16.6
+------
+- Minor bug fixes and improvements
+- Added `--no-clear` option for scripting purposes
+
+0.16.5
+------
+- Minor bug fixes
+- Added `toggle-preview-wrap` action
+- Built with Go 1.8
+
+0.16.4
+------
+- Added `--border` option to draw border above and below the finder
+- Bug fixes and improvements
+
+0.16.3
+------
+- Fixed a bug where fzf incorrectly display the lines when straddling tab
+ characters are trimmed
+- Placeholder expression used in `--preview` and `execute` action can
+ optionally take `+` flag to be used with multiple selections
+ - e.g. `git log --oneline | fzf --multi --preview 'git show {+1}'`
+- Added `execute-silent` action for executing a command silently without
+ switching to the alternate screen. This is useful when the process is
+ short-lived and you're not interested in its output.
+ - e.g. `fzf --bind 'ctrl-y:execute!(echo -n {} | pbcopy)'`
+- `ctrl-space` is allowed in `--bind`
+
+0.16.2
+------
+- Dropped ncurses dependency
+- Binaries for freebsd, openbsd, arm5, arm6, arm7, and arm8
+- Official 24-bit color support
+- Added support for composite actions in `--bind`. Multiple actions can be
+ chained using `+` separator.
+ - e.g. `fzf --bind 'ctrl-y:execute(echo -n {} | pbcopy)+abort'`
+- `--preview-window` with size 0 is allowed. This is used to make fzf execute
+ preview command in the background without displaying the result.
+- Minor bug fixes and improvements
+
+0.16.1
+------
+- Fixed `--height` option to properly fill the window with the background
+ color
+- Added `half-page-up` and `half-page-down` actions
+- Added `-L` flag to the default find command
+
+0.16.0
+------
+- *Added `--height HEIGHT[%]` option*
+ - fzf can now display finder without occupying the full screen
+- Preview window will truncate long lines by default. Line wrap can be enabled
+ by `:wrap` flag in `--preview-window`.
+- Latin script letters will be normalized before matching so that it's easier
+ to match against accented letters. e.g. `sodanco` can match `Só Danço Samba`.
+ - Normalization can be disabled via `--literal`
+- Added `--filepath-word` to make word-wise movements/actions (`alt-b`,
+ `alt-f`, `alt-bs`, `alt-d`) respect path separators
+
+0.15.9
+------
+- Fixed rendering glitches introduced in 0.15.8
+- The default escape delay is reduced to 50ms and is configurable via
+ `$ESCDELAY`
+- Scroll indicator at the top-right corner of the preview window is always
+ displayed when there's overflow
+- Can now be built with ncurses 6 or tcell to support extra features
+ - *ncurses 6*
+ - Supports more than 256 color pairs
+ - Supports italics
+ - *tcell*
+ - 24-bit color support
+ - See https://github.com/junegunn/fzf/blob/master/BUILD.md
+
+0.15.8
+------
+- Updated ANSI processor to handle more VT-100 escape sequences
+- Added `--no-bold` (and `--bold`) option
+- Improved escape sequence processing for WSL
+- Added support for `alt-[0-9]`, `f11`, and `f12` for `--bind` and `--expect`
+
+0.15.7
+------
+- Fixed panic when color is disabled and header lines contain ANSI colors
+
+0.15.6
+------
+- Windows binaries! (@kelleyma49)
+- Fixed the bug where header lines are cleared when preview window is toggled
+- Fixed not to display ^N and ^O on screen
+- Fixed cursor keys (or any key sequence that starts with ESC) on WSL by
+ making fzf wait for additional keystrokes after ESC for up to 100ms
+
+0.15.5
+------
+- Setting foreground color will no longer set background color to black
+ - e.g. `fzf --color fg:153`
+- `--tiebreak=end` will consider relative position instead of absolute distance
+- Updated `fzf#wrap` function to respect `g:fzf_colors`
+
+0.15.4
+------
+- Added support for range expression in preview and execute action
+ - e.g. `ls -l | fzf --preview="echo user={3} when={-4..-2}; cat {-1}" --header-lines=1`
+ - `{q}` will be replaced to the single-quoted string of the current query
+- Fixed to properly handle unicode whitespace characters
+- Display scroll indicator in preview window
+- Inverse search term will use exact matcher by default
+ - This is a breaking change, but I believe it makes much more sense. It is
+ almost impossible to predict which entries will be filtered out due to
+ a fuzzy inverse term. You can still perform inverse-fuzzy-match by
+ prepending `!'` to the term.
+
+0.15.3
+------
+- Added support for more ANSI attributes: dim, underline, blink, and reverse
+- Fixed race condition in `toggle-preview`
+
+0.15.2
+------
+- Preview window is now scrollable
+ - With mouse scroll or with bindable actions
+ - `preview-up`
+ - `preview-down`
+ - `preview-page-up`
+ - `preview-page-down`
+- Updated ANSI processor to support high intensity colors and ignore
+ some VT100-related escape sequences
+
+0.15.1
+------
+- Fixed panic when the pattern occurs after 2^15-th column
+- Fixed rendering delay when displaying extremely long lines
+
+0.15.0
+------
+- Improved fuzzy search algorithm
+ - Added `--algo=[v1|v2]` option so one can still choose the old algorithm
+ which values the search performance over the quality of the result
+- Advanced scoring criteria
+- `--read0` to read input delimited by ASCII NUL character
+- `--print0` to print output delimited by ASCII NUL character
+
+0.13.5
+------
+- Memory and performance optimization
+ - Up to 2x performance with half the amount of memory
+
+0.13.4
+------
+- Performance optimization
+ - Memory footprint for ascii string is reduced by 60%
+ - 15 to 20% improvement of query performance
+ - Up to 45% better performance of `--nth` with non-regex delimiters
+- Fixed invalid handling of `hidden` property of `--preview-window`
+
+0.13.3
+------
+- Fixed duplicate rendering of the last line in preview window
+
+0.13.2
+------
+- Fixed race condition where preview window is not properly cleared
+
+0.13.1
+------
+- Fixed UI issue with large `--preview` output with many ANSI codes
+
+0.13.0
+------
+- Added preview feature
+ - `--preview CMD`
+ - `--preview-window POS[:SIZE][:hidden]`
+- `{}` in execute action is now replaced to the single-quoted (instead of
+ double-quoted) string of the current line
+- Fixed to ignore control characters for bracketed paste mode
+
+0.12.2
+------
+
+- 256-color capability detection does not require `256` in `$TERM`
+- Added `print-query` action
+- More named keys for binding; <kbd>F1</kbd> ~ <kbd>F10</kbd>,
+ <kbd>ALT-/</kbd>, <kbd>ALT-space</kbd>, and <kbd>ALT-enter</kbd>
+- Added `jump` and `jump-accept` actions that implement [EasyMotion][em]-like
+ movement
+ ![][jump]
+
+[em]: https://github.com/easymotion/vim-easymotion
+[jump]: https://cloud.githubusercontent.com/assets/700826/15367574/b3999dc4-1d64-11e6-85da-28ceeb1a9bc2.png
+
+0.12.1
+------
+
+- Ranking algorithm introduced in 0.12.0 is now universally applied
+- Fixed invalid cache reference in exact mode
+- Fixes and improvements in Vim plugin and shell extensions
+
+0.12.0
+------
+
+- Enhanced ranking algorithm
+- Minor bug fixes
+
+0.11.4
+------
+
+- Added `--hscroll-off=COL` option (default: 10) (#513)
+- Some fixes in Vim plugin and shell extensions
+
+0.11.3
+------
+
+- Graceful exit on SIGTERM (#482)
+- `$SHELL` instead of `sh` for `execute` action and `$FZF_DEFAULT_COMMAND` (#481)
+- Changes in fuzzy completion API
+ - [`_fzf_compgen_{path,dir}`](https://github.com/junegunn/fzf/commit/9617647)
+ - [`_fzf_complete_COMMAND_post`](https://github.com/junegunn/fzf/commit/8206746)
+ for post-processing
+
+0.11.2
+------
+
+- `--tiebreak` now accepts comma-separated list of sort criteria
+ - Each criterion should appear only once in the list
+ - `index` is only allowed at the end of the list
+ - `index` is implicitly appended to the list when not specified
+ - Default is `length` (or equivalently `length,index`)
+- `begin` criterion will ignore leading whitespaces when calculating the index
+- Added `toggle-in` and `toggle-out` actions
+ - Switch direction depending on `--reverse`-ness
+ - `export FZF_DEFAULT_OPTS="--bind tab:toggle-out,shift-tab:toggle-in"`
+- Reduced the initial delay when `--tac` is not given
+ - fzf defers the initial rendering of the screen up to 100ms if the input
+ stream is ongoing to prevent unnecessary redraw during the initial
+ phase. However, 100ms delay is quite noticeable and might give the
+ impression that fzf is not snappy enough. This commit reduces the
+ maximum delay down to 20ms when `--tac` is not specified, in which case
+ the input list quickly fills the entire screen.
+
+0.11.1
+------
+
+- Added `--tabstop=SPACES` option
+
+0.11.0
+------
+
+- Added OR operator for extended-search mode
+- Added `--execute-multi` action
+- Fixed incorrect cursor position when unicode wide characters are used in
+ `--prompt`
+- Fixes and improvements in shell extensions
+
+0.10.9
+------
+
+- Extended-search mode is now enabled by default
+ - `--extended-exact` is deprecated and instead we have `--exact` for
+ orthogonally controlling "exactness" of search
+- Fixed not to display non-printable characters
+- Added `double-click` for `--bind` option
+- More robust handling of SIGWINCH
+
+0.10.8
+------
+
+- Fixed panic when trying to set colors after colors are disabled (#370)
+
+0.10.7
+------
+
+- Fixed unserialized interrupt handling during execute action which often
+ caused invalid memory access and crash
+- Changed `--tiebreak=length` (default) to use trimmed length when `--nth` is
+ used
+
+0.10.6
+------
+
+- Replaced `--header-file` with `--header` option
+- `--header` and `--header-lines` can be used together
+- Changed exit status
+ - 0: Okay
+ - 1: No match
+ - 2: Error
+ - 130: Interrupted
+- 64-bit linux binary is statically-linked with ncurses to avoid
+ compatibility issues.
+
+0.10.5
+------
+
+- `'`-prefix to unquote the term in `--extended-exact` mode
+- Backward scan when `--tiebreak=end` is set
+
+0.10.4
+------
+
+- Fixed to remove ANSI code from output when `--with-nth` is set
+
+0.10.3
+------
+
+- Fixed slow performance of `--with-nth` when used with `--delimiter`
+ - Regular expression engine of Golang as of now is very slow, so the fixed
+ version will treat the given delimiter pattern as a plain string instead
+ of a regular expression unless it contains special characters and is
+ a valid regular expression.
+ - Simpler regular expression for delimiter for better performance
+
+0.10.2
+------
+
+### Fixes and improvements
+
+- Improvement in perceived response time of queries
+ - Eager, efficient rune array conversion
+- Graceful exit when failed to initialize ncurses (invalid $TERM)
+- Improved ranking algorithm when `--nth` option is set
+- Changed the default command not to fail when there are files whose names
+ start with dash
+
+0.10.1
+------
+
+### New features
+
+- Added `--margin` option
+- Added options for sticky header
+ - `--header-file`
+ - `--header-lines`
+- Added `cancel` action which clears the input or closes the finder when the
+ input is already empty
+ - e.g. `export FZF_DEFAULT_OPTS="--bind esc:cancel"`
+- Added `delete-char/eof` action to differentiate `CTRL-D` and `DEL`
+
+### Minor improvements/fixes
+
+- Fixed to allow binding colon and comma keys
+- Fixed ANSI processor to handle color regions spanning multiple lines
+
+0.10.0
+------
+
+### New features
+
+- More actions for `--bind`
+ - `select-all`
+ - `deselect-all`
+ - `toggle-all`
+ - `ignore`
+- `execute(...)` action for running arbitrary command without leaving fzf
+ - `fzf --bind "ctrl-m:execute(less {})"`
+ - `fzf --bind "ctrl-t:execute(tmux new-window -d 'vim {}')"`
+ - If the command contains parentheses, use any of the follows alternative
+ notations to avoid parse errors
+ - `execute[...]`
+ - `execute~...~`
+ - `execute!...!`
+ - `execute@...@`
+ - `execute#...#`
+ - `execute$...$`
+ - `execute%...%`
+ - `execute^...^`
+ - `execute&...&`
+ - `execute*...*`
+ - `execute;...;`
+ - `execute/.../`
+ - `execute|...|`
+ - `execute:...`
+ - This is the special form that frees you from parse errors as it
+ does not expect the closing character
+ - The catch is that it should be the last one in the
+ comma-separated list
+- Added support for optional search history
+ - `--history HISTORY_FILE`
+ - When used, `CTRL-N` and `CTRL-P` are automatically remapped to
+ `next-history` and `previous-history`
+ - `--history-size MAX_ENTRIES` (default: 1000)
+- Cyclic scrolling can be enabled with `--cycle`
+- Fixed the bug where the spinner was not spinning on idle input stream
+ - e.g. `sleep 100 | fzf`
+
+### Minor improvements/fixes
+
+- Added synonyms for key names that can be specified for `--bind`,
+ `--toggle-sort`, and `--expect`
+- Fixed the color of multi-select marker on the current line
+- Fixed to allow `^pattern$` in extended-search mode
+
+
+0.9.13
+------
+
+### New features
+
+- Color customization with the extended `--color` option
+
+### Bug fixes
+
+- Fixed premature termination of Reader in the presence of a long line which
+ is longer than 64KB
+
+0.9.12
+------
+
+### New features
+
+- Added `--bind` option for custom key bindings
+
+### Bug fixes
+
+- Fixed to update "inline-info" immediately after terminal resize
+- Fixed ANSI code offset calculation
+
+0.9.11
+------
+
+### New features
+
+- Added `--inline-info` option for saving screen estate (#202)
+ - Useful inside Neovim
+ - e.g. `let $FZF_DEFAULT_OPTS = $FZF_DEFAULT_OPTS.' --inline-info'`
+
+### Bug fixes
+
+- Invalid mutation of input on case conversion (#209)
+- Smart-case for each term in extended-search mode (#208)
+- Fixed double-click result when scroll offset is positive
+
+0.9.10
+------
+
+### Improvements
+
+- Performance optimization
+- Less aggressive memoization to limit memory usage
+
+### New features
+
+- Added color scheme for light background: `--color=light`
+
+0.9.9
+-----
+
+### New features
+
+- Added `--tiebreak` option (#191)
+- Added `--no-hscroll` option (#193)
+- Visual indication of `--toggle-sort` (#194)
+
+0.9.8
+-----
+
+### Bug fixes
+
+- Fixed Unicode case handling (#186)
+- Fixed to terminate on RuneError (#185)
+
+0.9.7
+-----
+
+### New features
+
+- Added `--toggle-sort` option (#173)
+ - `--toggle-sort=ctrl-r` is applied to `CTRL-R` shell extension
+
+### Bug fixes
+
+- Fixed to print empty line if `--expect` is set and fzf is completed by
+ `--select-1` or `--exit-0` (#172)
+- Fixed to allow comma character as an argument to `--expect` option
+
+0.9.6
+-----
+
+### New features
+
+#### Added `--expect` option (#163)
+
+If you provide a comma-separated list of keys with `--expect` option, fzf will
+allow you to select the match and complete the finder when any of the keys is
+pressed. Additionally, fzf will print the name of the key pressed as the first
+line of the output so that your script can decide what to do next based on the
+information.
+
+```sh
+fzf --expect=ctrl-v,ctrl-t,alt-s,f1,f2,~,@
+```
+
+The updated vim plugin uses this option to implement
+[ctrlp](https://github.com/kien/ctrlp.vim)-compatible key bindings.
+
+### Bug fixes
+
+- Fixed to ignore ANSI escape code `\e[K` (#162)
+
+0.9.5
+-----
+
+### New features
+
+#### Added `--ansi` option (#150)
+
+If you give `--ansi` option to fzf, fzf will interpret ANSI color codes from
+the input, display the item with the ANSI colors (true colors are not
+supported), and strips the codes from the output. This option is off by
+default as it entails some overhead.
+
+### Improvements
+
+#### Reduced initial memory footprint (#151)
+
+By removing unnecessary copy of pointers, fzf will use significantly smaller
+amount of memory when it's started. The difference is hugely noticeable when
+the input is extremely large. (e.g. `locate / | fzf`)
+
+### Bug fixes
+
+- Fixed panic on `--no-sort --filter ''` (#149)
+
+0.9.4
+-----
+
+### New features
+
+#### Added `--tac` option to reverse the order of the input.
+
+One might argue that this option is unnecessary since we can already put `tac`
+or `tail -r` in the command pipeline to achieve the same result. However, the
+advantage of `--tac` is that it does not block until the input is complete.
+
+### *Backward incompatible changes*
+
+#### Changed behavior on `--no-sort`
+
+`--no-sort` option will no longer reverse the display order within finder. You
+may want to use the new `--tac` option with `--no-sort`.
+
+```
+history | fzf +s --tac
+```
+
+### Improvements
+
+#### `--filter` will not block when sort is disabled
+
+When fzf works in filtering mode (`--filter`) and sort is disabled
+(`--no-sort`), there's no need to block until input is complete. The new
+version of fzf will print the matches on-the-fly when the following condition
+is met:
+
+ --filter TERM --no-sort [--no-tac --no-sync]
+
+or simply:
+
+ -f TERM +s
+
+This change removes unnecessary delay in the use cases like the following:
+
+ fzf -f xxx +s | head -5
+
+However, in this case, fzf processes the lines sequentially, so it cannot
+utilize multiple cores, and fzf will run slightly slower than the previous
+mode of execution where filtering is done in parallel after the entire input
+is loaded. If the user is concerned about this performance problem, one can
+add `--sync` option to re-enable buffering.
+
+0.9.3
+-----
+
+### New features
+- Added `--sync` option for multi-staged filtering
+
+### Improvements
+- `--select-1` and `--exit-0` will start finder immediately when the condition
+ cannot be met
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/Dockerfile b/dot-oh-my-zsh/custom/plugins/fzf/Dockerfile
new file mode 100644
index 00000000..9cccaaa5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/Dockerfile
@@ -0,0 +1,11 @@
+FROM archlinux
+RUN pacman -Sy && pacman --noconfirm -S awk git tmux zsh fish ruby procps go make gcc
+RUN gem install --no-document -v 5.14.2 minitest
+RUN echo '. /usr/share/bash-completion/completions/git' >> ~/.bashrc
+RUN echo '. ~/.bashrc' >> ~/.bash_profile
+
+# Do not set default PS1
+RUN rm -f /etc/bash.bashrc
+COPY . /fzf
+RUN cd /fzf && make install && ./install --all
+CMD tmux new 'set -o pipefail; ruby /fzf/test/test_go.rb | tee out && touch ok' && cat out && [ -e ok ]
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/LICENSE b/dot-oh-my-zsh/custom/plugins/fzf/LICENSE
new file mode 100644
index 00000000..533a79de
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2022 Junegunn Choi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/Makefile b/dot-oh-my-zsh/custom/plugins/fzf/Makefile
new file mode 100644
index 00000000..435c9ca8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/Makefile
@@ -0,0 +1,172 @@
+SHELL := bash
+GO ?= go
+GOOS ?= $(word 1, $(subst /, " ", $(word 4, $(shell go version))))
+
+MAKEFILE := $(realpath $(lastword $(MAKEFILE_LIST)))
+ROOT_DIR := $(shell dirname $(MAKEFILE))
+SOURCES := $(wildcard *.go src/*.go src/*/*.go) $(MAKEFILE)
+
+ifdef FZF_VERSION
+VERSION := $(FZF_VERSION)
+else
+VERSION := $(shell git describe --abbrev=0 2> /dev/null)
+endif
+ifeq ($(VERSION),)
+$(error Not on git repository; cannot determine $$FZF_VERSION)
+endif
+VERSION_TRIM := $(shell sed "s/-.*//" <<< $(VERSION))
+VERSION_REGEX := $(subst .,\.,$(VERSION_TRIM))
+
+ifdef FZF_REVISION
+REVISION := $(FZF_REVISION)
+else
+REVISION := $(shell git log -n 1 --pretty=format:%h -- $(SOURCES) 2> /dev/null)
+endif
+ifeq ($(REVISION),)
+$(error Not on git repository; cannot determine $$FZF_REVISION)
+endif
+BUILD_FLAGS := -a -ldflags "-s -w -X main.version=$(VERSION) -X main.revision=$(REVISION)" -tags "$(TAGS)"
+
+BINARY32 := fzf-$(GOOS)_386
+BINARY64 := fzf-$(GOOS)_amd64
+BINARYARM5 := fzf-$(GOOS)_arm5
+BINARYARM6 := fzf-$(GOOS)_arm6
+BINARYARM7 := fzf-$(GOOS)_arm7
+BINARYARM8 := fzf-$(GOOS)_arm8
+BINARYPPC64LE := fzf-$(GOOS)_ppc64le
+BINARYRISCV64 := fzf-$(GOOS)_riscv64
+BINARYLOONG64 := fzf-$(GOOS)_loong64
+
+# https://en.wikipedia.org/wiki/Uname
+UNAME_M := $(shell uname -m)
+ifeq ($(UNAME_M),x86_64)
+ BINARY := $(BINARY64)
+else ifeq ($(UNAME_M),amd64)
+ BINARY := $(BINARY64)
+else ifeq ($(UNAME_M),i686)
+ BINARY := $(BINARY32)
+else ifeq ($(UNAME_M),i386)
+ BINARY := $(BINARY32)
+else ifeq ($(UNAME_M),armv5l)
+ BINARY := $(BINARYARM5)
+else ifeq ($(UNAME_M),armv6l)
+ BINARY := $(BINARYARM6)
+else ifeq ($(UNAME_M),armv7l)
+ BINARY := $(BINARYARM7)
+else ifeq ($(UNAME_M),armv8l)
+ BINARY := $(BINARYARM8)
+else ifeq ($(UNAME_M),arm64)
+ BINARY := $(BINARYARM8)
+else ifeq ($(UNAME_M),aarch64)
+ BINARY := $(BINARYARM8)
+else ifeq ($(UNAME_M),ppc64le)
+ BINARY := $(BINARYPPC64LE)
+else ifeq ($(UNAME_M),riscv64)
+ BINARY := $(BINARYRISCV64)
+else ifeq ($(UNAME_M),loongarch64)
+ BINARY := $(BINARYLOONG64)
+else
+$(error Build on $(UNAME_M) is not supported, yet.)
+endif
+
+all: target/$(BINARY)
+
+test: $(SOURCES)
+ [ -z "$$(gofmt -s -d src)" ] || (gofmt -s -d src; exit 1)
+ SHELL=/bin/sh GOOS= $(GO) test -v -tags "$(TAGS)" \
+ github.com/junegunn/fzf/src \
+ github.com/junegunn/fzf/src/algo \
+ github.com/junegunn/fzf/src/tui \
+ github.com/junegunn/fzf/src/util
+
+bench:
+ cd src && SHELL=/bin/sh GOOS= $(GO) test -v -tags "$(TAGS)" -run=Bench -bench=. -benchmem
+
+install: bin/fzf
+
+build:
+ goreleaser --rm-dist --snapshot
+
+release:
+ifndef GITHUB_TOKEN
+ $(error GITHUB_TOKEN is not defined)
+endif
+
+ # Check if we are on master branch
+ifneq ($(shell git symbolic-ref --short HEAD),master)
+ $(error Not on master branch)
+endif
+
+ # Check if version numbers are properly updated
+ grep -q ^$(VERSION_REGEX)$$ CHANGELOG.md
+ grep -qF '"fzf $(VERSION_TRIM)"' man/man1/fzf.1
+ grep -qF '"fzf $(VERSION_TRIM)"' man/man1/fzf-tmux.1
+ grep -qF $(VERSION) install
+ grep -qF $(VERSION) install.ps1
+
+ # Make release note out of CHANGELOG.md
+ mkdir -p tmp
+ sed -n '/^$(VERSION_REGEX)$$/,/^[0-9]/p' CHANGELOG.md | tail -r | \
+ sed '1,/^ *$$/d' | tail -r | sed 1,2d | tee tmp/release-note
+
+ # Push to temp branch first so that install scripts always works on master branch
+ git checkout -B temp master
+ git push origin temp --follow-tags --force
+
+ # Make a GitHub release
+ goreleaser --rm-dist --release-notes tmp/release-note
+
+ # Push to master
+ git checkout master
+ git push origin master
+
+ # Delete temp branch
+ git push origin --delete temp
+
+clean:
+ $(RM) -r dist target
+
+target/$(BINARY32): $(SOURCES)
+ GOARCH=386 $(GO) build $(BUILD_FLAGS) -o $@
+
+target/$(BINARY64): $(SOURCES)
+ GOARCH=amd64 $(GO) build $(BUILD_FLAGS) -o $@
+
+# https://github.com/golang/go/wiki/GoArm
+target/$(BINARYARM5): $(SOURCES)
+ GOARCH=arm GOARM=5 $(GO) build $(BUILD_FLAGS) -o $@
+
+target/$(BINARYARM6): $(SOURCES)
+ GOARCH=arm GOARM=6 $(GO) build $(BUILD_FLAGS) -o $@
+
+target/$(BINARYARM7): $(SOURCES)
+ GOARCH=arm GOARM=7 $(GO) build $(BUILD_FLAGS) -o $@
+
+target/$(BINARYARM8): $(SOURCES)
+ GOARCH=arm64 $(GO) build $(BUILD_FLAGS) -o $@
+
+target/$(BINARYPPC64LE): $(SOURCES)
+ GOARCH=ppc64le $(GO) build $(BUILD_FLAGS) -o $@
+
+target/$(BINARYRISCV64): $(SOURCES)
+ GOARCH=riscv64 $(GO) build $(BUILD_FLAGS) -o $@
+
+target/$(BINARYLOONG64): $(SOURCES)
+ GOARCH=loong64 $(GO) build $(BUILD_FLAGS) -o $@
+
+bin/fzf: target/$(BINARY) | bin
+ cp -f target/$(BINARY) bin/fzf
+
+docker:
+ docker build -t fzf-arch .
+ docker run -it fzf-arch tmux
+
+docker-test:
+ docker build -t fzf-arch .
+ docker run -it fzf-arch
+
+update:
+ $(GO) get -u
+ $(GO) mod tidy
+
+.PHONY: all build release test bench install clean docker docker-test update
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/README-VIM.md b/dot-oh-my-zsh/custom/plugins/fzf/README-VIM.md
new file mode 100644
index 00000000..425bf672
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/README-VIM.md
@@ -0,0 +1,486 @@
+FZF Vim integration
+===================
+
+Installation
+------------
+
+Once you have fzf installed, you can enable it inside Vim simply by adding the
+directory to `&runtimepath` in your Vim configuration file. The path may
+differ depending on the package manager.
+
+```vim
+" If installed using Homebrew
+set rtp+=/usr/local/opt/fzf
+
+" If installed using git
+set rtp+=~/.fzf
+```
+
+If you use [vim-plug](https://github.com/junegunn/vim-plug), the same can be
+written as:
+
+```vim
+" If installed using Homebrew
+Plug '/usr/local/opt/fzf'
+
+" If installed using git
+Plug '~/.fzf'
+```
+
+But if you want the latest Vim plugin file from GitHub rather than the one
+included in the package, write:
+
+```vim
+Plug 'junegunn/fzf'
+```
+
+The Vim plugin will pick up fzf binary available on the system. If fzf is not
+found on `$PATH`, it will ask you if it should download the latest binary for
+you.
+
+To make sure that you have the latest version of the binary, set up
+post-update hook like so:
+
+```vim
+Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
+```
+
+Summary
+-------
+
+The Vim plugin of fzf provides two core functions, and `:FZF` command which is
+the basic file selector command built on top of them.
+
+1. **`fzf#run([spec dict])`**
+ - Starts fzf inside Vim with the given spec
+ - `:call fzf#run({'source': 'ls'})`
+2. **`fzf#wrap([spec dict]) -> (dict)`**
+ - Takes a spec for `fzf#run` and returns an extended version of it with
+ additional options for addressing global preferences (`g:fzf_xxx`)
+ - `:echo fzf#wrap({'source': 'ls'})`
+ - We usually *wrap* a spec with `fzf#wrap` before passing it to `fzf#run`
+ - `:call fzf#run(fzf#wrap({'source': 'ls'}))`
+3. **`:FZF [fzf_options string] [path string]`**
+ - Basic fuzzy file selector
+ - A reference implementation for those who don't want to write VimScript
+ to implement custom commands
+ - If you're looking for more such commands, check out [fzf.vim](https://github.com/junegunn/fzf.vim) project.
+
+The most important of all is `fzf#run`, but it would be easier to understand
+the whole if we start off with `:FZF` command.
+
+`:FZF[!]`
+---------
+
+```vim
+" Look for files under current directory
+:FZF
+
+" Look for files under your home directory
+:FZF ~
+
+" With fzf command-line options
+:FZF --reverse --info=inline /tmp
+
+" Bang version starts fzf in fullscreen mode
+:FZF!
+```
+
+Similarly to [ctrlp.vim](https://github.com/kien/ctrlp.vim), use enter key,
+`CTRL-T`, `CTRL-X` or `CTRL-V` to open selected files in the current window,
+in new tabs, in horizontal splits, or in vertical splits respectively.
+
+Note that the environment variables `FZF_DEFAULT_COMMAND` and
+`FZF_DEFAULT_OPTS` also apply here.
+
+### Configuration
+
+- `g:fzf_action`
+ - Customizable extra key bindings for opening selected files in different ways
+- `g:fzf_layout`
+ - Determines the size and position of fzf window
+- `g:fzf_colors`
+ - Customizes fzf colors to match the current color scheme
+- `g:fzf_history_dir`
+ - Enables history feature
+
+#### Examples
+
+```vim
+" This is the default extra key bindings
+let g:fzf_action = {
+ \ 'ctrl-t': 'tab split',
+ \ 'ctrl-x': 'split',
+ \ 'ctrl-v': 'vsplit' }
+
+" An action can be a reference to a function that processes selected lines
+function! s:build_quickfix_list(lines)
+ call setqflist(map(copy(a:lines), '{ "filename": v:val }'))
+ copen
+ cc
+endfunction
+
+let g:fzf_action = {
+ \ 'ctrl-q': function('s:build_quickfix_list'),
+ \ 'ctrl-t': 'tab split',
+ \ 'ctrl-x': 'split',
+ \ 'ctrl-v': 'vsplit' }
+
+" Default fzf layout
+" - Popup window (center of the screen)
+let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
+
+" - Popup window (center of the current window)
+let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6, 'relative': v:true } }
+
+" - Popup window (anchored to the bottom of the current window)
+let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6, 'relative': v:true, 'yoffset': 1.0 } }
+
+" - down / up / left / right
+let g:fzf_layout = { 'down': '40%' }
+
+" - Window using a Vim command
+let g:fzf_layout = { 'window': 'enew' }
+let g:fzf_layout = { 'window': '-tabnew' }
+let g:fzf_layout = { 'window': '10new' }
+
+" Customize fzf colors to match your color scheme
+" - fzf#wrap translates this to a set of `--color` options
+let g:fzf_colors =
+\ { 'fg': ['fg', 'Normal'],
+ \ 'bg': ['bg', 'Normal'],
+ \ 'hl': ['fg', 'Comment'],
+ \ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
+ \ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
+ \ 'hl+': ['fg', 'Statement'],
+ \ 'info': ['fg', 'PreProc'],
+ \ 'border': ['fg', 'Ignore'],
+ \ 'prompt': ['fg', 'Conditional'],
+ \ 'pointer': ['fg', 'Exception'],
+ \ 'marker': ['fg', 'Keyword'],
+ \ 'spinner': ['fg', 'Label'],
+ \ 'header': ['fg', 'Comment'] }
+
+" Enable per-command history
+" - History files will be stored in the specified directory
+" - When set, CTRL-N and CTRL-P will be bound to 'next-history' and
+" 'previous-history' instead of 'down' and 'up'.
+let g:fzf_history_dir = '~/.local/share/fzf-history'
+```
+
+##### Explanation of `g:fzf_colors`
+
+`g:fzf_colors` is a dictionary mapping fzf elements to a color specification
+list:
+
+ element: [ component, group1 [, group2, ...] ]
+
+- `element` is an fzf element to apply a color to:
+
+ | Element | Description |
+ | --- | --- |
+ | `fg` / `bg` / `hl` | Item (foreground / background / highlight) |
+ | `fg+` / `bg+` / `hl+` | Current item (foreground / background / highlight) |
+ | `preview-fg` / `preview-bg` | Preview window text and background |
+ | `hl` / `hl+` | Highlighted substrings (normal / current) |
+ | `gutter` | Background of the gutter on the left |
+ | `pointer` | Pointer to the current line (`>`) |
+ | `marker` | Multi-select marker (`>`) |
+ | `border` | Border around the window (`--border` and `--preview`) |
+ | `header` | Header (`--header` or `--header-lines`) |
+ | `info` | Info line (match counters) |
+ | `spinner` | Streaming input indicator |
+ | `query` | Query string |
+ | `disabled` | Query string when search is disabled |
+ | `prompt` | Prompt before query (`> `) |
+ | `pointer` | Pointer to the current line (`>`) |
+
+- `component` specifies the component (`fg` / `bg`) from which to extract the
+ color when considering each of the following highlight groups
+
+- `group1 [, group2, ...]` is a list of highlight groups that are searched (in
+ order) for a matching color definition
+
+For example, consider the following specification:
+
+```vim
+ 'prompt': ['fg', 'Conditional', 'Comment'],
+```
+
+This means we color the **prompt**
+- using the `fg` attribute of the `Conditional` if it exists,
+- otherwise use the `fg` attribute of the `Comment` highlight group if it exists,
+- otherwise fall back to the default color settings for the **prompt**.
+
+You can examine the color option generated according the setting by printing
+the result of `fzf#wrap()` function like so:
+
+```vim
+:echo fzf#wrap()
+```
+
+`fzf#run`
+---------
+
+`fzf#run()` function is the core of Vim integration. It takes a single
+dictionary argument, *a spec*, and starts fzf process accordingly. At the very
+least, specify `sink` option to tell what it should do with the selected
+entry.
+
+```vim
+call fzf#run({'sink': 'e'})
+```
+
+We haven't specified the `source`, so this is equivalent to starting fzf on
+command line without standard input pipe; fzf will use find command (or
+`$FZF_DEFAULT_COMMAND` if defined) to list the files under the current
+directory. When you select one, it will open it with the sink, `:e` command.
+If you want to open it in a new tab, you can pass `:tabedit` command instead
+as the sink.
+
+```vim
+call fzf#run({'sink': 'tabedit'})
+```
+
+Instead of using the default find command, you can use any shell command as
+the source. The following example will list the files managed by git. It's
+equivalent to running `git ls-files | fzf` on shell.
+
+```vim
+call fzf#run({'source': 'git ls-files', 'sink': 'e'})
+```
+
+fzf options can be specified as `options` entry in spec dictionary.
+
+```vim
+call fzf#run({'sink': 'tabedit', 'options': '--multi --reverse'})
+```
+
+You can also pass a layout option if you don't want fzf window to take up the
+entire screen.
+
+```vim
+" up / down / left / right / window are allowed
+call fzf#run({'source': 'git ls-files', 'sink': 'e', 'left': '40%'})
+call fzf#run({'source': 'git ls-files', 'sink': 'e', 'window': '30vnew'})
+```
+
+`source` doesn't have to be an external shell command, you can pass a Vim
+array as the source. In the next example, we pass the names of color
+schemes as the source to implement a color scheme selector.
+
+```vim
+call fzf#run({'source': map(split(globpath(&rtp, 'colors/*.vim')),
+ \ 'fnamemodify(v:val, ":t:r")'),
+ \ 'sink': 'colo', 'left': '25%'})
+```
+
+The following table summarizes the available options.
+
+| Option name | Type | Description |
+| -------------------------- | ------------- | ---------------------------------------------------------------- |
+| `source` | string | External command to generate input to fzf (e.g. `find .`) |
+| `source` | list | Vim list as input to fzf |
+| `sink` | string | Vim command to handle the selected item (e.g. `e`, `tabe`) |
+| `sink` | funcref | Reference to function to process each selected item |
+| `sinklist` (or `sink*`) | funcref | Similar to `sink`, but takes the list of output lines at once |
+| `options` | string/list | Options to fzf |
+| `dir` | string | Working directory |
+| `up`/`down`/`left`/`right` | number/string | (Layout) Window position and size (e.g. `20`, `50%`) |
+| `tmux` | string | (Layout) fzf-tmux options (e.g. `-p90%,60%`) |
+| `window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `vertical aboveleft 30new`) |
+| `window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}`) |
+
+`options` entry can be either a string or a list. For simple cases, string
+should suffice, but prefer to use list type to avoid escaping issues.
+
+```vim
+call fzf#run({'options': '--reverse --prompt "C:\\Program Files\\"'})
+call fzf#run({'options': ['--reverse', '--prompt', 'C:\Program Files\']})
+```
+
+When `window` entry is a dictionary, fzf will start in a popup window. The
+following options are allowed:
+
+- Required:
+ - `width` [float range [0 ~ 1]] or [integer range [8 ~ ]]
+ - `height` [float range [0 ~ 1]] or [integer range [4 ~ ]]
+- Optional:
+ - `yoffset` [float default 0.5 range [0 ~ 1]]
+ - `xoffset` [float default 0.5 range [0 ~ 1]]
+ - `relative` [boolean default v:false]
+ - `border` [string default `rounded`]: Border style
+ - `rounded` / `sharp` / `horizontal` / `vertical` / `top` / `bottom` / `left` / `right` / `no[ne]`
+
+`fzf#wrap`
+----------
+
+We have seen that several aspects of `:FZF` command can be configured with
+a set of global option variables; different ways to open files
+(`g:fzf_action`), window position and size (`g:fzf_layout`), color palette
+(`g:fzf_colors`), etc.
+
+So how can we make our custom `fzf#run` calls also respect those variables?
+Simply by *"wrapping"* the spec dictionary with `fzf#wrap` before passing it
+to `fzf#run`.
+
+- **`fzf#wrap([name string], [spec dict], [fullscreen bool]) -> (dict)`**
+ - All arguments are optional. Usually we only need to pass a spec dictionary.
+ - `name` is for managing history files. It is ignored if
+ `g:fzf_history_dir` is not defined.
+ - `fullscreen` can be either `0` or `1` (default: 0).
+
+`fzf#wrap` takes a spec and returns an extended version of it (also
+a dictionary) with additional options for addressing global preferences. You
+can examine the return value of it like so:
+
+```vim
+echo fzf#wrap({'source': 'ls'})
+```
+
+After we *"wrap"* our spec, we pass it to `fzf#run`.
+
+```vim
+call fzf#run(fzf#wrap({'source': 'ls'}))
+```
+
+Now it supports `CTRL-T`, `CTRL-V`, and `CTRL-X` key bindings (configurable
+via `g:fzf_action`) and it opens fzf window according to `g:fzf_layout`
+setting.
+
+To make it easier to use, let's define `LS` command.
+
+```vim
+command! LS call fzf#run(fzf#wrap({'source': 'ls'}))
+```
+
+Type `:LS` and see how it works.
+
+We would like to make `:LS!` (bang version) open fzf in fullscreen, just like
+`:FZF!`. Add `-bang` to command definition, and use `<bang>` value to set
+the last `fullscreen` argument of `fzf#wrap` (see `:help <bang>`).
+
+```vim
+" On :LS!, <bang> evaluates to '!', and '!0' becomes 1
+command! -bang LS call fzf#run(fzf#wrap({'source': 'ls'}, <bang>0))
+```
+
+Our `:LS` command will be much more useful if we can pass a directory argument
+to it, so that something like `:LS /tmp` is possible.
+
+```vim
+command! -bang -complete=dir -nargs=? LS
+ \ call fzf#run(fzf#wrap({'source': 'ls', 'dir': <q-args>}, <bang>0))
+```
+
+Lastly, if you have enabled `g:fzf_history_dir`, you might want to assign
+a unique name to our command and pass it as the first argument to `fzf#wrap`.
+
+```vim
+" The query history for this command will be stored as 'ls' inside g:fzf_history_dir.
+" The name is ignored if g:fzf_history_dir is not defined.
+command! -bang -complete=dir -nargs=? LS
+ \ call fzf#run(fzf#wrap('ls', {'source': 'ls', 'dir': <q-args>}, <bang>0))
+```
+
+### Global options supported by `fzf#wrap`
+
+- `g:fzf_layout`
+- `g:fzf_action`
+ - **Works only when no custom `sink` (or `sinklist`) is provided**
+ - Having custom sink usually means that each entry is not an ordinary
+ file path (e.g. name of color scheme), so we can't blindly apply the
+ same strategy (i.e. `tabedit some-color-scheme` doesn't make sense)
+- `g:fzf_colors`
+- `g:fzf_history_dir`
+
+Tips
+----
+
+### fzf inside terminal buffer
+
+On the latest versions of Vim and Neovim, fzf will start in a terminal buffer.
+If you find the default ANSI colors to be different, consider configuring the
+colors using `g:terminal_ansi_colors` in regular Vim or `g:terminal_color_x`
+in Neovim.
+
+```vim
+" Terminal colors for seoul256 color scheme
+if has('nvim')
+ let g:terminal_color_0 = '#4e4e4e'
+ let g:terminal_color_1 = '#d68787'
+ let g:terminal_color_2 = '#5f865f'
+ let g:terminal_color_3 = '#d8af5f'
+ let g:terminal_color_4 = '#85add4'
+ let g:terminal_color_5 = '#d7afaf'
+ let g:terminal_color_6 = '#87afaf'
+ let g:terminal_color_7 = '#d0d0d0'
+ let g:terminal_color_8 = '#626262'
+ let g:terminal_color_9 = '#d75f87'
+ let g:terminal_color_10 = '#87af87'
+ let g:terminal_color_11 = '#ffd787'
+ let g:terminal_color_12 = '#add4fb'
+ let g:terminal_color_13 = '#ffafaf'
+ let g:terminal_color_14 = '#87d7d7'
+ let g:terminal_color_15 = '#e4e4e4'
+else
+ let g:terminal_ansi_colors = [
+ \ '#4e4e4e', '#d68787', '#5f865f', '#d8af5f',
+ \ '#85add4', '#d7afaf', '#87afaf', '#d0d0d0',
+ \ '#626262', '#d75f87', '#87af87', '#ffd787',
+ \ '#add4fb', '#ffafaf', '#87d7d7', '#e4e4e4'
+ \ ]
+endif
+```
+
+### Starting fzf in a popup window
+
+```vim
+" Required:
+" - width [float range [0 ~ 1]] or [integer range [8 ~ ]]
+" - height [float range [0 ~ 1]] or [integer range [4 ~ ]]
+"
+" Optional:
+" - xoffset [float default 0.5 range [0 ~ 1]]
+" - yoffset [float default 0.5 range [0 ~ 1]]
+" - relative [boolean default v:false]
+" - border [string default 'rounded']: Border style
+" - 'rounded' / 'sharp' / 'horizontal' / 'vertical' / 'top' / 'bottom' / 'left' / 'right'
+let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
+```
+
+Alternatively, you can make fzf open in a tmux popup window (requires tmux 3.2
+or above) by putting fzf-tmux options in `tmux` key.
+
+```vim
+" See `man fzf-tmux` for available options
+if exists('$TMUX')
+ let g:fzf_layout = { 'tmux': '-p90%,60%' }
+else
+ let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
+endif
+```
+
+### Hide statusline
+
+When fzf starts in a terminal buffer, the file type of the buffer is set to
+`fzf`. So you can set up `FileType fzf` autocmd to customize the settings of
+the window.
+
+For example, if you open fzf on the bottom on the screen (e.g. `{'down':
+'40%'}`), you might want to temporarily disable the statusline for a cleaner
+look.
+
+```vim
+let g:fzf_layout = { 'down': '30%' }
+autocmd! FileType fzf
+autocmd FileType fzf set laststatus=0 noshowmode noruler
+ \| autocmd BufLeave <buffer> set laststatus=2 showmode ruler
+```
+
+[License](LICENSE)
+------------------
+
+The MIT License (MIT)
+
+Copyright (c) 2013-2021 Junegunn Choi
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/README.md b/dot-oh-my-zsh/custom/plugins/fzf/README.md
new file mode 100644
index 00000000..ebd83e29
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/README.md
@@ -0,0 +1,711 @@
+<img src="https://raw.githubusercontent.com/junegunn/i/master/fzf.png" height="170" alt="fzf - a command-line fuzzy finder"> [![github-actions](https://github.com/junegunn/fzf/workflows/Test%20fzf%20on%20Linux/badge.svg)](https://github.com/junegunn/fzf/actions)
+===
+
+fzf is a general-purpose command-line fuzzy finder.
+
+<img src="https://raw.githubusercontent.com/junegunn/i/master/fzf-preview.png" width=640>
+
+It's an interactive Unix filter for command-line that can be used with any
+list; files, command history, processes, hostnames, bookmarks, git commits,
+etc.
+
+Pros
+----
+
+- Portable, no dependencies
+- Blazingly fast
+- The most comprehensive feature set
+- Flexible layout
+- Batteries included
+ - Vim/Neovim plugin, key bindings, and fuzzy auto-completion
+
+Table of Contents
+-----------------
+
+<!-- vim-markdown-toc GFM -->
+
+* [Installation](#installation)
+ * [Using Homebrew](#using-homebrew)
+ * [Using git](#using-git)
+ * [Using Linux package managers](#using-linux-package-managers)
+ * [Windows](#windows)
+ * [As Vim plugin](#as-vim-plugin)
+* [Upgrading fzf](#upgrading-fzf)
+* [Building fzf](#building-fzf)
+* [Usage](#usage)
+ * [Using the finder](#using-the-finder)
+ * [Layout](#layout)
+ * [Search syntax](#search-syntax)
+ * [Environment variables](#environment-variables)
+ * [Options](#options)
+ * [Demo](#demo)
+* [Examples](#examples)
+* [`fzf-tmux` script](#fzf-tmux-script)
+* [Key bindings for command-line](#key-bindings-for-command-line)
+* [Fuzzy completion for bash and zsh](#fuzzy-completion-for-bash-and-zsh)
+ * [Files and directories](#files-and-directories)
+ * [Process IDs](#process-ids)
+ * [Host names](#host-names)
+ * [Environment variables / Aliases](#environment-variables--aliases)
+ * [Settings](#settings)
+ * [Supported commands](#supported-commands)
+ * [Custom fuzzy completion](#custom-fuzzy-completion)
+* [Vim plugin](#vim-plugin)
+* [Advanced topics](#advanced-topics)
+ * [Performance](#performance)
+ * [Executing external programs](#executing-external-programs)
+ * [Reloading the candidate list](#reloading-the-candidate-list)
+ * [1. Update the list of processes by pressing CTRL-R](#1-update-the-list-of-processes-by-pressing-ctrl-r)
+ * [2. Switch between sources by pressing CTRL-D or CTRL-F](#2-switch-between-sources-by-pressing-ctrl-d-or-ctrl-f)
+ * [3. Interactive ripgrep integration](#3-interactive-ripgrep-integration)
+ * [Preview window](#preview-window)
+* [Tips](#tips)
+ * [Respecting `.gitignore`](#respecting-gitignore)
+ * [Fish shell](#fish-shell)
+* [Related projects](#related-projects)
+* [License](#license)
+
+<!-- vim-markdown-toc -->
+
+Installation
+------------
+
+fzf project consists of the following components:
+
+- `fzf` executable
+- `fzf-tmux` script for launching fzf in a tmux pane
+- Shell extensions
+ - Key bindings (`CTRL-T`, `CTRL-R`, and `ALT-C`) (bash, zsh, fish)
+ - Fuzzy auto-completion (bash, zsh)
+- Vim/Neovim plugin
+
+You can [download fzf executable][bin] alone if you don't need the extra
+stuff.
+
+[bin]: https://github.com/junegunn/fzf/releases
+
+### Using Homebrew
+
+You can use [Homebrew](https://brew.sh/) (on macOS or Linux)
+to install fzf.
+
+```sh
+brew install fzf
+
+# To install useful key bindings and fuzzy completion:
+$(brew --prefix)/opt/fzf/install
+```
+
+fzf is also available [via MacPorts][portfile]: `sudo port install fzf`
+
+[portfile]: https://github.com/macports/macports-ports/blob/master/sysutils/fzf/Portfile
+
+### Using git
+
+Alternatively, you can "git clone" this repository to any directory and run
+[install](https://github.com/junegunn/fzf/blob/master/install) script.
+
+```sh
+git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
+~/.fzf/install
+```
+
+### Using Linux package managers
+
+| Package Manager | Linux Distribution | Command |
+| --- | --- | --- |
+| APK | Alpine Linux | `sudo apk add fzf` |
+| APT | Debian 9+/Ubuntu 19.10+ | `sudo apt-get install fzf` |
+| Conda | | `conda install -c conda-forge fzf` |
+| DNF | Fedora | `sudo dnf install fzf` |
+| Nix | NixOS, etc. | `nix-env -iA nixpkgs.fzf` |
+| Pacman | Arch Linux | `sudo pacman -S fzf` |
+| pkg | FreeBSD | `pkg install fzf` |
+| pkgin | NetBSD | `pkgin install fzf` |
+| pkg_add | OpenBSD | `pkg_add fzf` |
+| XBPS | Void Linux | `sudo xbps-install -S fzf` |
+| Zypper | openSUSE | `sudo zypper install fzf` |
+
+> :warning: **Key bindings (CTRL-T / CTRL-R / ALT-C) and fuzzy auto-completion
+> may not be enabled by default.**
+>
+> Refer to the package documentation for more information. (e.g. `apt-cache show fzf`)
+
+[![Packaging status](https://repology.org/badge/vertical-allrepos/fzf.svg)](https://repology.org/project/fzf/versions)
+
+### Windows
+
+Pre-built binaries for Windows can be downloaded [here][bin]. fzf is also
+available via [Chocolatey][choco] and [Scoop][scoop]:
+
+| Package manager | Command |
+| --- | --- |
+| Chocolatey | `choco install fzf` |
+| Scoop | `scoop install fzf` |
+
+[choco]: https://chocolatey.org/packages/fzf
+[scoop]: https://github.com/ScoopInstaller/Main/blob/master/bucket/fzf.json
+
+Known issues and limitations on Windows can be found on [the wiki
+page][windows-wiki].
+
+[windows-wiki]: https://github.com/junegunn/fzf/wiki/Windows
+
+### As Vim plugin
+
+If you use
+[vim-plug](https://github.com/junegunn/vim-plug), add this line to your Vim
+configuration file:
+
+```vim
+Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
+```
+
+`fzf#install()` makes sure that you have the latest binary, but it's optional,
+so you can omit it if you use a plugin manager that doesn't support hooks.
+
+For more installation options, see [README-VIM.md](README-VIM.md).
+
+Upgrading fzf
+-------------
+
+fzf is being actively developed, and you might want to upgrade it once in a
+while. Please follow the instruction below depending on the installation
+method used.
+
+- git: `cd ~/.fzf && git pull && ./install`
+- brew: `brew update; brew upgrade fzf`
+- macports: `sudo port upgrade fzf`
+- chocolatey: `choco upgrade fzf`
+- vim-plug: `:PlugUpdate fzf`
+
+Building fzf
+------------
+
+See [BUILD.md](BUILD.md).
+
+Usage
+-----
+
+fzf will launch interactive finder, read the list from STDIN, and write the
+selected item to STDOUT.
+
+```sh
+find * -type f | fzf > selected
+```
+
+Without STDIN pipe, fzf will use find command to fetch the list of
+files excluding hidden ones. (You can override the default command with
+`FZF_DEFAULT_COMMAND`)
+
+```sh
+vim $(fzf)
+```
+
+#### Using the finder
+
+- `CTRL-K` / `CTRL-J` (or `CTRL-P` / `CTRL-N`) to move cursor up and down
+- `Enter` key to select the item, `CTRL-C` / `CTRL-G` / `ESC` to exit
+- On multi-select mode (`-m`), `TAB` and `Shift-TAB` to mark multiple items
+- Emacs style key bindings
+- Mouse: scroll, click, double-click; shift-click and shift-scroll on
+ multi-select mode
+
+#### Layout
+
+fzf by default starts in fullscreen mode, but you can make it start below the
+cursor with `--height` option.
+
+```sh
+vim $(fzf --height 40%)
+```
+
+Also, check out `--reverse` and `--layout` options if you prefer
+"top-down" layout instead of the default "bottom-up" layout.
+
+```sh
+vim $(fzf --height 40% --reverse)
+```
+
+You can add these options to `$FZF_DEFAULT_OPTS` so that they're applied by
+default. For example,
+
+```sh
+export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border'
+```
+
+#### Search syntax
+
+Unless otherwise specified, fzf starts in "extended-search mode" where you can
+type in multiple search terms delimited by spaces. e.g. `^music .mp3$ sbtrkt
+!fire`
+
+| Token | Match type | Description |
+| --------- | -------------------------- | ------------------------------------ |
+| `sbtrkt` | fuzzy-match | Items that match `sbtrkt` |
+| `'wild` | exact-match (quoted) | Items that include `wild` |
+| `^music` | prefix-exact-match | Items that start with `music` |
+| `.mp3$` | suffix-exact-match | Items that end with `.mp3` |
+| `!fire` | inverse-exact-match | Items that do not include `fire` |
+| `!^music` | inverse-prefix-exact-match | Items that do not start with `music` |
+| `!.mp3$` | inverse-suffix-exact-match | Items that do not end with `.mp3` |
+
+If you don't prefer fuzzy matching and do not wish to "quote" every word,
+start fzf with `-e` or `--exact` option. Note that when `--exact` is set,
+`'`-prefix "unquotes" the term.
+
+A single bar character term acts as an OR operator. For example, the following
+query matches entries that start with `core` and end with either `go`, `rb`,
+or `py`.
+
+```
+^core go$ | rb$ | py$
+```
+
+#### Environment variables
+
+- `FZF_DEFAULT_COMMAND`
+ - Default command to use when input is tty
+ - e.g. `export FZF_DEFAULT_COMMAND='fd --type f'`
+ - > :warning: This variable is not used by shell extensions due to the
+ > slight difference in requirements.
+ >
+ > (e.g. `CTRL-T` runs `$FZF_CTRL_T_COMMAND` instead, `vim **<tab>` runs
+ > `_fzf_compgen_path()`, and `cd **<tab>` runs `_fzf_compgen_dir()`)
+ >
+ > The available options are described later in this document.
+- `FZF_DEFAULT_OPTS`
+ - Default options
+ - e.g. `export FZF_DEFAULT_OPTS="--layout=reverse --inline-info"`
+
+#### Options
+
+See the man page (`man fzf`) for the full list of options.
+
+#### Demo
+If you learn by watching videos, check out this screencast by [@samoshkin](https://github.com/samoshkin) to explore `fzf` features.
+
+<a title="fzf - command-line fuzzy finder" href="https://www.youtube.com/watch?v=qgG5Jhi_Els">
+ <img src="https://i.imgur.com/vtG8olE.png" width="640">
+</a>
+
+Examples
+--------
+
+* [Wiki page of examples](https://github.com/junegunn/fzf/wiki/examples)
+ * *Disclaimer: The examples on this page are maintained by the community
+ and are not thoroughly tested*
+* [Advanced fzf examples](https://github.com/junegunn/fzf/blob/master/ADVANCED.md)
+
+`fzf-tmux` script
+-----------------
+
+[fzf-tmux](bin/fzf-tmux) is a bash script that opens fzf in a tmux pane.
+
+```sh
+# usage: fzf-tmux [LAYOUT OPTIONS] [--] [FZF OPTIONS]
+
+# See available options
+fzf-tmux --help
+
+# select git branches in horizontal split below (15 lines)
+git branch | fzf-tmux -d 15
+
+# select multiple words in vertical split on the left (20% of screen width)
+cat /usr/share/dict/words | fzf-tmux -l 20% --multi --reverse
+```
+
+It will still work even when you're not on tmux, silently ignoring `-[pudlr]`
+options, so you can invariably use `fzf-tmux` in your scripts.
+
+Alternatively, you can use `--height HEIGHT[%]` option not to start fzf in
+fullscreen mode.
+
+```sh
+fzf --height 40%
+```
+
+Key bindings for command-line
+-----------------------------
+
+The install script will setup the following key bindings for bash, zsh, and
+fish.
+
+- `CTRL-T` - Paste the selected files and directories onto the command-line
+ - Set `FZF_CTRL_T_COMMAND` to override the default command
+ - Set `FZF_CTRL_T_OPTS` to pass additional options
+- `CTRL-R` - Paste the selected command from history onto the command-line
+ - If you want to see the commands in chronological order, press `CTRL-R`
+ again which toggles sorting by relevance
+ - Set `FZF_CTRL_R_OPTS` to pass additional options
+- `ALT-C` - cd into the selected directory
+ - Set `FZF_ALT_C_COMMAND` to override the default command
+ - Set `FZF_ALT_C_OPTS` to pass additional options
+
+If you're on a tmux session, you can start fzf in a tmux split-pane or in
+a tmux popup window by setting `FZF_TMUX_OPTS` (e.g. `-d 40%`).
+See `fzf-tmux --help` for available options.
+
+More tips can be found on [the wiki page](https://github.com/junegunn/fzf/wiki/Configuring-shell-key-bindings).
+
+Fuzzy completion for bash and zsh
+---------------------------------
+
+#### Files and directories
+
+Fuzzy completion for files and directories can be triggered if the word before
+the cursor ends with the trigger sequence, which is by default `**`.
+
+- `COMMAND [DIRECTORY/][FUZZY_PATTERN]**<TAB>`
+
+```sh
+# Files under the current directory
+# - You can select multiple items with TAB key
+vim **<TAB>
+
+# Files under parent directory
+vim ../**<TAB>
+
+# Files under parent directory that match `fzf`
+vim ../fzf**<TAB>
+
+# Files under your home directory
+vim ~/**<TAB>
+
+
+# Directories under current directory (single-selection)
+cd **<TAB>
+
+# Directories under ~/github that match `fzf`
+cd ~/github/fzf**<TAB>
+```
+
+#### Process IDs
+
+Fuzzy completion for PIDs is provided for kill command.
+
+```sh
+# Can select multiple processes with <TAB> or <Shift-TAB> keys
+kill -9 **<TAB>
+```
+
+#### Host names
+
+For ssh and telnet commands, fuzzy completion for hostnames is provided. The
+names are extracted from /etc/hosts and ~/.ssh/config.
+
+```sh
+ssh **<TAB>
+telnet **<TAB>
+```
+
+#### Environment variables / Aliases
+
+```sh
+unset **<TAB>
+export **<TAB>
+unalias **<TAB>
+```
+
+#### Settings
+
+```sh
+# Use ~~ as the trigger sequence instead of the default **
+export FZF_COMPLETION_TRIGGER='~~'
+
+# Options to fzf command
+export FZF_COMPLETION_OPTS='--border --info=inline'
+
+# Use fd (https://github.com/sharkdp/fd) instead of the default find
+# command for listing path candidates.
+# - The first argument to the function ($1) is the base path to start traversal
+# - See the source code (completion.{bash,zsh}) for the details.
+_fzf_compgen_path() {
+ fd --hidden --follow --exclude ".git" . "$1"
+}
+
+# Use fd to generate the list for directory completion
+_fzf_compgen_dir() {
+ fd --type d --hidden --follow --exclude ".git" . "$1"
+}
+
+# (EXPERIMENTAL) Advanced customization of fzf options via _fzf_comprun function
+# - The first argument to the function is the name of the command.
+# - You should make sure to pass the rest of the arguments to fzf.
+_fzf_comprun() {
+ local command=$1
+ shift
+
+ case "$command" in
+ cd) fzf "$@" --preview 'tree -C {} | head -200' ;;
+ export|unset) fzf "$@" --preview "eval 'echo \$'{}" ;;
+ ssh) fzf "$@" --preview 'dig {}' ;;
+ *) fzf "$@" ;;
+ esac
+}
+```
+
+#### Supported commands
+
+On bash, fuzzy completion is enabled only for a predefined set of commands
+(`complete | grep _fzf` to see the list). But you can enable it for other
+commands as well by using `_fzf_setup_completion` helper function.
+
+```sh
+# usage: _fzf_setup_completion path|dir|var|alias|host COMMANDS...
+_fzf_setup_completion path ag git kubectl
+_fzf_setup_completion dir tree
+```
+
+#### Custom fuzzy completion
+
+_**(Custom completion API is experimental and subject to change)**_
+
+For a command named _"COMMAND"_, define `_fzf_complete_COMMAND` function using
+`_fzf_complete` helper.
+
+```sh
+# Custom fuzzy completion for "doge" command
+# e.g. doge **<TAB>
+_fzf_complete_doge() {
+ _fzf_complete --multi --reverse --prompt="doge> " -- "$@" < <(
+ echo very
+ echo wow
+ echo such
+ echo doge
+ )
+}
+```
+
+- The arguments before `--` are the options to fzf.
+- After `--`, simply pass the original completion arguments unchanged (`"$@"`).
+- Then, write a set of commands that generates the completion candidates and
+ feed its output to the function using process substitution (`< <(...)`).
+
+zsh will automatically pick up the function using the naming convention but in
+bash you have to manually associate the function with the command using the
+`complete` command.
+
+```sh
+[ -n "$BASH" ] && complete -F _fzf_complete_doge -o default -o bashdefault doge
+```
+
+If you need to post-process the output from fzf, define
+`_fzf_complete_COMMAND_post` as follows.
+
+```sh
+_fzf_complete_foo() {
+ _fzf_complete --multi --reverse --header-lines=3 -- "$@" < <(
+ ls -al
+ )
+}
+
+_fzf_complete_foo_post() {
+ awk '{print $NF}'
+}
+
+[ -n "$BASH" ] && complete -F _fzf_complete_foo -o default -o bashdefault foo
+```
+
+Vim plugin
+----------
+
+See [README-VIM.md](README-VIM.md).
+
+Advanced topics
+---------------
+
+### Performance
+
+fzf is fast and is [getting even faster][perf]. Performance should not be
+a problem in most use cases. However, you might want to be aware of the
+options that affect performance.
+
+- `--ansi` tells fzf to extract and parse ANSI color codes in the input, and it
+ makes the initial scanning slower. So it's not recommended that you add it
+ to your `$FZF_DEFAULT_OPTS`.
+- `--nth` makes fzf slower because it has to tokenize each line.
+- `--with-nth` makes fzf slower as fzf has to tokenize and reassemble each
+ line.
+- If you absolutely need better performance, you can consider using
+ `--algo=v1` (the default being `v2`) to make fzf use a faster greedy
+ algorithm. However, this algorithm is not guaranteed to find the optimal
+ ordering of the matches and is not recommended.
+
+[perf]: https://junegunn.kr/images/fzf-0.17.0.png
+
+### Executing external programs
+
+You can set up key bindings for starting external processes without leaving
+fzf (`execute`, `execute-silent`).
+
+```bash
+# Press F1 to open the file with less without leaving fzf
+# Press CTRL-Y to copy the line to clipboard and aborts fzf (requires pbcopy)
+fzf --bind 'f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort'
+```
+
+See *KEY BINDINGS* section of the man page for details.
+
+### Reloading the candidate list
+
+By binding `reload` action to a key or an event, you can make fzf dynamically
+reload the candidate list. See https://github.com/junegunn/fzf/issues/1750 for
+more details.
+
+#### 1. Update the list of processes by pressing CTRL-R
+
+```sh
+FZF_DEFAULT_COMMAND='ps -ef' \
+ fzf --bind 'ctrl-r:reload(eval "$FZF_DEFAULT_COMMAND")' \
+ --header 'Press CTRL-R to reload' --header-lines=1 \
+ --height=50% --layout=reverse
+```
+
+#### 2. Switch between sources by pressing CTRL-D or CTRL-F
+
+```sh
+FZF_DEFAULT_COMMAND='find . -type f' \
+ fzf --bind 'ctrl-d:reload(find . -type d),ctrl-f:reload(eval "$FZF_DEFAULT_COMMAND")' \
+ --height=50% --layout=reverse
+```
+
+#### 3. Interactive ripgrep integration
+
+The following example uses fzf as the selector interface for ripgrep. We bound
+`reload` action to `change` event, so every time you type on fzf, the ripgrep
+process will restart with the updated query string denoted by the placeholder
+expression `{q}`. Also, note that we used `--disabled` option so that fzf
+doesn't perform any secondary filtering.
+
+```sh
+INITIAL_QUERY=""
+RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
+FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY'" \
+ fzf --bind "change:reload:$RG_PREFIX {q} || true" \
+ --ansi --disabled --query "$INITIAL_QUERY" \
+ --height=50% --layout=reverse
+```
+
+If ripgrep doesn't find any matches, it will exit with a non-zero exit status,
+and fzf will warn you about it. To suppress the warning message, we added
+`|| true` to the command, so that it always exits with 0.
+
+See ["Using fzf as interative Ripgrep launcher"](https://github.com/junegunn/fzf/blob/master/ADVANCED.md#using-fzf-as-interative-ripgrep-launcher)
+for a fuller example with preview window options.
+
+### Preview window
+
+When the `--preview` option is set, fzf automatically starts an external process
+with the current line as the argument and shows the result in the split window.
+Your `$SHELL` is used to execute the command with `$SHELL -c COMMAND`.
+The window can be scrolled using the mouse or custom key bindings.
+
+```bash
+# {} is replaced with the single-quoted string of the focused line
+fzf --preview 'cat {}'
+```
+
+Preview window supports ANSI colors, so you can use any program that
+syntax-highlights the content of a file, such as
+[Bat](https://github.com/sharkdp/bat) or
+[Highlight](http://www.andre-simon.de/doku/highlight/en/highlight.php):
+
+```bash
+fzf --preview 'bat --style=numbers --color=always --line-range :500 {}'
+```
+
+You can customize the size, position, and border of the preview window using
+`--preview-window` option, and the foreground and background color of it with
+`--color` option. For example,
+
+```bash
+fzf --height 40% --layout reverse --info inline --border \
+ --preview 'file {}' --preview-window up,1,border-horizontal \
+ --color 'fg:#bbccdd,fg+:#ddeeff,bg:#334455,preview-bg:#223344,border:#778899'
+```
+
+See the man page (`man fzf`) for the full list of options.
+
+More advanced examples can be found [here](https://github.com/junegunn/fzf/blob/master/ADVANCED.md).
+
+----
+
+Since fzf is a general-purpose text filter rather than a file finder, **it is
+not a good idea to add `--preview` option to your `$FZF_DEFAULT_OPTS`**.
+
+```sh
+# *********************
+# ** DO NOT DO THIS! **
+# *********************
+export FZF_DEFAULT_OPTS='--preview "bat --style=numbers --color=always --line-range :500 {}"'
+
+# bat doesn't work with any input other than the list of files
+ps -ef | fzf
+seq 100 | fzf
+history | fzf
+```
+
+Tips
+----
+
+#### Respecting `.gitignore`
+
+You can use [fd](https://github.com/sharkdp/fd),
+[ripgrep](https://github.com/BurntSushi/ripgrep), or [the silver
+searcher](https://github.com/ggreer/the_silver_searcher) instead of the
+default find command to traverse the file system while respecting
+`.gitignore`.
+
+```sh
+# Feed the output of fd into fzf
+fd --type f --strip-cwd-prefix | fzf
+
+# Setting fd as the default source for fzf
+export FZF_DEFAULT_COMMAND='fd --type f --strip-cwd-prefix'
+
+# Now fzf (w/o pipe) will use fd instead of find
+fzf
+
+# To apply the command to CTRL-T as well
+export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
+```
+
+If you want the command to follow symbolic links and don't want it to exclude
+hidden files, use the following command:
+
+```sh
+export FZF_DEFAULT_COMMAND='fd --type f --strip-cwd-prefix --hidden --follow --exclude .git'
+```
+
+#### Fish shell
+
+`CTRL-T` key binding of fish, unlike those of bash and zsh, will use the last
+token on the command-line as the root directory for the recursive search. For
+instance, hitting `CTRL-T` at the end of the following command-line
+
+```sh
+ls /var/
+```
+
+will list all files and directories under `/var/`.
+
+When using a custom `FZF_CTRL_T_COMMAND`, use the unexpanded `$dir` variable to
+make use of this feature. `$dir` defaults to `.` when the last token is not a
+valid directory. Example:
+
+```sh
+set -g FZF_CTRL_T_COMMAND "command find -L \$dir -type f 2> /dev/null | sed '1d; s#^\./##'"
+```
+
+Related projects
+----------------
+
+https://github.com/junegunn/fzf/wiki/Related-projects
+
+[License](LICENSE)
+------------------
+
+The MIT License (MIT)
+
+Copyright (c) 2013-2021 Junegunn Choi
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/bin/fzf-tmux b/dot-oh-my-zsh/custom/plugins/fzf/bin/fzf-tmux
new file mode 100755
index 00000000..e461fd77
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/bin/fzf-tmux
@@ -0,0 +1,229 @@
+#!/usr/bin/env bash
+# fzf-tmux: starts fzf in a tmux pane
+# usage: fzf-tmux [LAYOUT OPTIONS] [--] [FZF OPTIONS]
+
+fail() {
+ >&2 echo "$1"
+ exit 2
+}
+
+fzf="$(command -v fzf 2> /dev/null)" || fzf="$(dirname "$0")/fzf"
+[[ -x "$fzf" ]] || fail 'fzf executable not found'
+
+args=()
+opt=""
+skip=""
+swap=""
+close=""
+term=""
+[[ -n "$LINES" ]] && lines=$LINES || lines=$(tput lines) || lines=$(tmux display-message -p "#{pane_height}")
+[[ -n "$COLUMNS" ]] && columns=$COLUMNS || columns=$(tput cols) || columns=$(tmux display-message -p "#{pane_width}")
+
+help() {
+ >&2 echo 'usage: fzf-tmux [LAYOUT OPTIONS] [--] [FZF OPTIONS]
+
+ LAYOUT OPTIONS:
+ (default layout: -d 50%)
+
+ Popup window (requires tmux 3.2 or above):
+ -p [WIDTH[%][,HEIGHT[%]]] (default: 50%)
+ -w WIDTH[%]
+ -h HEIGHT[%]
+ -x COL
+ -y ROW
+
+ Split pane:
+ -u [HEIGHT[%]] Split above (up)
+ -d [HEIGHT[%]] Split below (down)
+ -l [WIDTH[%]] Split left
+ -r [WIDTH[%]] Split right
+'
+ exit
+}
+
+while [[ $# -gt 0 ]]; do
+ arg="$1"
+ shift
+ [[ -z "$skip" ]] && case "$arg" in
+ -)
+ term=1
+ ;;
+ --help)
+ help
+ ;;
+ --version)
+ echo "fzf-tmux (with fzf $("$fzf" --version))"
+ exit
+ ;;
+ -p*|-w*|-h*|-x*|-y*|-d*|-u*|-r*|-l*)
+ if [[ "$arg" =~ ^-[pwhxy] ]]; then
+ [[ "$opt" =~ "-E" ]] || opt="-E"
+ elif [[ "$arg" =~ ^.[lr] ]]; then
+ opt="-h"
+ if [[ "$arg" =~ ^.l ]]; then
+ opt="$opt -d"
+ swap="; swap-pane -D ; select-pane -L"
+ close="; tmux swap-pane -D"
+ fi
+ else
+ opt=""
+ if [[ "$arg" =~ ^.u ]]; then
+ opt="$opt -d"
+ swap="; swap-pane -D ; select-pane -U"
+ close="; tmux swap-pane -D"
+ fi
+ fi
+ if [[ ${#arg} -gt 2 ]]; then
+ size="${arg:2}"
+ else
+ if [[ "$1" =~ ^[0-9%,]+$ ]] || [[ "$1" =~ ^[A-Z]$ ]]; then
+ size="$1"
+ shift
+ else
+ continue
+ fi
+ fi
+
+ if [[ "$arg" =~ ^-p ]]; then
+ if [[ -n "$size" ]]; then
+ w=${size%%,*}
+ h=${size##*,}
+ opt="$opt -w$w -h$h"
+ fi
+ elif [[ "$arg" =~ ^-[whxy] ]]; then
+ opt="$opt ${arg:0:2}$size"
+ elif [[ "$size" =~ %$ ]]; then
+ size=${size:0:((${#size}-1))}
+ if [[ -n "$swap" ]]; then
+ opt="$opt -p $(( 100 - size ))"
+ else
+ opt="$opt -p $size"
+ fi
+ else
+ if [[ -n "$swap" ]]; then
+ if [[ "$arg" =~ ^.l ]]; then
+ max=$columns
+ else
+ max=$lines
+ fi
+ size=$(( max - size ))
+ [[ $size -lt 0 ]] && size=0
+ opt="$opt -l $size"
+ else
+ opt="$opt -l $size"
+ fi
+ fi
+ ;;
+ --)
+ # "--" can be used to separate fzf-tmux options from fzf options to
+ # avoid conflicts
+ skip=1
+ continue
+ ;;
+ *)
+ args+=("$arg")
+ ;;
+ esac
+ [[ -n "$skip" ]] && args+=("$arg")
+done
+
+if [[ -z "$TMUX" ]]; then
+ "$fzf" "${args[@]}"
+ exit $?
+fi
+
+# --height option is not allowed. CTRL-Z is also disabled.
+args=("${args[@]}" "--no-height" "--bind=ctrl-z:ignore")
+
+# Handle zoomed tmux pane without popup options by moving it to a temp window
+if [[ ! "$opt" =~ "-E" ]] && tmux list-panes -F '#F' | grep -q Z; then
+ zoomed_without_popup=1
+ original_window=$(tmux display-message -p "#{window_id}")
+ tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
+ tmux swap-pane -t $tmp_window \; select-window -t $tmp_window
+fi
+
+set -e
+
+# Clean up named pipes on exit
+id=$RANDOM
+argsf="${TMPDIR:-/tmp}/fzf-args-$id"
+fifo1="${TMPDIR:-/tmp}/fzf-fifo1-$id"
+fifo2="${TMPDIR:-/tmp}/fzf-fifo2-$id"
+fifo3="${TMPDIR:-/tmp}/fzf-fifo3-$id"
+tmux_win_opts=( $(tmux show-window-options remain-on-exit \; show-window-options synchronize-panes | sed '/ off/d; s/^/set-window-option /; s/$/ \\;/') )
+cleanup() {
+ \rm -f $argsf $fifo1 $fifo2 $fifo3
+
+ # Restore tmux window options
+ if [[ "${#tmux_win_opts[@]}" -gt 0 ]]; then
+ eval "tmux ${tmux_win_opts[*]}"
+ fi
+
+ # Remove temp window if we were zoomed without popup options
+ if [[ -n "$zoomed_without_popup" ]]; then
+ tmux display-message -p "#{window_id}" > /dev/null
+ tmux swap-pane -t $original_window \; \
+ select-window -t $original_window \; \
+ kill-window -t $tmp_window \; \
+ resize-pane -Z
+ fi
+
+ if [[ $# -gt 0 ]]; then
+ trap - EXIT
+ exit 130
+ fi
+}
+trap 'cleanup 1' SIGUSR1
+trap 'cleanup' EXIT
+
+envs="export TERM=$TERM "
+if [[ "$opt" =~ "-E" ]]; then
+ FZF_DEFAULT_OPTS="--margin 0,1 $FZF_DEFAULT_OPTS"
+ tmux_verson=$(tmux -V)
+ if [[ ! $tmux_verson =~ 3\.2 ]]; then
+ FZF_DEFAULT_OPTS="--border $FZF_DEFAULT_OPTS"
+ opt="-B $opt"
+ fi
+fi
+[[ -n "$FZF_DEFAULT_OPTS" ]] && envs="$envs FZF_DEFAULT_OPTS=$(printf %q "$FZF_DEFAULT_OPTS")"
+[[ -n "$FZF_DEFAULT_COMMAND" ]] && envs="$envs FZF_DEFAULT_COMMAND=$(printf %q "$FZF_DEFAULT_COMMAND")"
+echo "$envs;" > "$argsf"
+
+# Build arguments to fzf
+opts=$(printf "%q " "${args[@]}")
+
+pppid=$$
+echo -n "trap 'kill -SIGUSR1 -$pppid' EXIT SIGINT SIGTERM;" >> $argsf
+close="; trap - EXIT SIGINT SIGTERM $close"
+
+export TMUX=$(cut -d , -f 1,2 <<< "$TMUX")
+mkfifo -m o+w $fifo2
+if [[ "$opt" =~ "-E" ]]; then
+ cat $fifo2 &
+ if [[ -n "$term" ]] || [[ -t 0 ]]; then
+ cat <<< "\"$fzf\" $opts > $fifo2; out=\$? $close; exit \$out" >> $argsf
+ else
+ mkfifo $fifo1
+ cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; out=\$? $close; exit \$out" >> $argsf
+ cat <&0 > $fifo1 &
+ fi
+
+ tmux popup -d "$PWD" $opt "bash $argsf" > /dev/null 2>&1
+ exit $?
+fi
+
+mkfifo -m o+w $fifo3
+if [[ -n "$term" ]] || [[ -t 0 ]]; then
+ cat <<< "\"$fzf\" $opts > $fifo2; echo \$? > $fifo3 $close" >> $argsf
+else
+ mkfifo $fifo1
+ cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; echo \$? > $fifo3 $close" >> $argsf
+ cat <&0 > $fifo1 &
+fi
+tmux set-window-option synchronize-panes off \;\
+ set-window-option remain-on-exit off \;\
+ split-window -c "$PWD" $opt "bash -c 'exec -a fzf bash $argsf'" $swap \
+ > /dev/null 2>&1 || { "$fzf" "${args[@]}"; exit $?; }
+cat $fifo2
+exit "$(cat $fifo3)"
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/doc/fzf.txt b/dot-oh-my-zsh/custom/plugins/fzf/doc/fzf.txt
new file mode 100644
index 00000000..94857232
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/doc/fzf.txt
@@ -0,0 +1,512 @@
+fzf.txt fzf Last change: May 19 2021
+FZF - TABLE OF CONTENTS *fzf* *fzf-toc*
+==============================================================================
+
+ FZF Vim integration |fzf-vim-integration|
+ Installation |fzf-installation|
+ Summary |fzf-summary|
+ :FZF[!] |:FZF|
+ Configuration |fzf-configuration|
+ Examples |fzf-examples|
+ Explanation of g:fzf_colors |fzf-explanation-of-gfzfcolors|
+ fzf#run |fzf#run|
+ fzf#wrap |fzf#wrap|
+ Global options supported by fzf#wrap |fzf-global-options-supported-by-fzf#wrap|
+ Tips |fzf-tips|
+ fzf inside terminal buffer |fzf-inside-terminal-buffer|
+ Starting fzf in a popup window |fzf-starting-fzf-in-a-popup-window|
+ Hide statusline |fzf-hide-statusline|
+ License |fzf-license|
+
+FZF VIM INTEGRATION *fzf-vim-integration*
+==============================================================================
+
+
+INSTALLATION *fzf-installation*
+==============================================================================
+
+Once you have fzf installed, you can enable it inside Vim simply by adding the
+directory to 'runtimepath' in your Vim configuration file. The path may differ
+depending on the package manager.
+>
+ " If installed using Homebrew
+ set rtp+=/usr/local/opt/fzf
+
+ " If installed using git
+ set rtp+=~/.fzf
+<
+If you use {vim-plug}{1}, the same can be written as:
+>
+ " If installed using Homebrew
+ Plug '/usr/local/opt/fzf'
+
+ " If installed using git
+ Plug '~/.fzf'
+<
+But if you want the latest Vim plugin file from GitHub rather than the one
+included in the package, write:
+>
+ Plug 'junegunn/fzf'
+<
+The Vim plugin will pick up fzf binary available on the system. If fzf is not
+found on `$PATH`, it will ask you if it should download the latest binary for
+you.
+
+To make sure that you have the latest version of the binary, set up
+post-update hook like so:
+
+ *fzf#install*
+>
+ Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
+<
+ {1} https://github.com/junegunn/vim-plug
+
+
+SUMMARY *fzf-summary*
+==============================================================================
+
+The Vim plugin of fzf provides two core functions, and `:FZF` command which is
+the basic file selector command built on top of them.
+
+ 1. `fzf#run([spec dict])`
+ - Starts fzf inside Vim with the given spec
+ - `:call fzf#run({'source': 'ls'})`
+ 2. `fzf#wrap([spec dict]) -> (dict)`
+ - Takes a spec for `fzf#run` and returns an extended version of it with
+ additional options for addressing global preferences (`g:fzf_xxx`)
+ - `:echo fzf#wrap({'source': 'ls'})`
+ - We usually wrap a spec with `fzf#wrap` before passing it to `fzf#run`
+ - `:call fzf#run(fzf#wrap({'source': 'ls'}))`
+ 3. `:FZF [fzf_options string] [path string]`
+ - Basic fuzzy file selector
+ - A reference implementation for those who don't want to write VimScript to
+ implement custom commands
+ - If you're looking for more such commands, check out {fzf.vim}{2} project.
+
+The most important of all is `fzf#run`, but it would be easier to understand
+the whole if we start off with `:FZF` command.
+
+ {2} https://github.com/junegunn/fzf.vim
+
+
+:FZF[!]
+==============================================================================
+
+ *:FZF*
+>
+ " Look for files under current directory
+ :FZF
+
+ " Look for files under your home directory
+ :FZF ~
+
+ " With fzf command-line options
+ :FZF --reverse --info=inline /tmp
+
+ " Bang version starts fzf in fullscreen mode
+ :FZF!
+<
+Similarly to {ctrlp.vim}{3}, use enter key, CTRL-T, CTRL-X or CTRL-V to open
+selected files in the current window, in new tabs, in horizontal splits, or in
+vertical splits respectively.
+
+Note that the environment variables `FZF_DEFAULT_COMMAND` and
+`FZF_DEFAULT_OPTS` also apply here.
+
+ {3} https://github.com/kien/ctrlp.vim
+
+
+< Configuration >_____________________________________________________________~
+ *fzf-configuration*
+
+ *g:fzf_action* *g:fzf_layout* *g:fzf_colors* *g:fzf_history_dir*
+
+ - `g:fzf_action`
+ - Customizable extra key bindings for opening selected files in different
+ ways
+ - `g:fzf_layout`
+ - Determines the size and position of fzf window
+ - `g:fzf_colors`
+ - Customizes fzf colors to match the current color scheme
+ - `g:fzf_history_dir`
+ - Enables history feature
+
+
+Examples~
+ *fzf-examples*
+>
+ " This is the default extra key bindings
+ let g:fzf_action = {
+ \ 'ctrl-t': 'tab split',
+ \ 'ctrl-x': 'split',
+ \ 'ctrl-v': 'vsplit' }
+
+ " An action can be a reference to a function that processes selected lines
+ function! s:build_quickfix_list(lines)
+ call setqflist(map(copy(a:lines), '{ "filename": v:val }'))
+ copen
+ cc
+ endfunction
+
+ let g:fzf_action = {
+ \ 'ctrl-q': function('s:build_quickfix_list'),
+ \ 'ctrl-t': 'tab split',
+ \ 'ctrl-x': 'split',
+ \ 'ctrl-v': 'vsplit' }
+
+ " Default fzf layout
+ " - Popup window (center of the screen)
+ let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
+
+ " - Popup window (center of the current window)
+ let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6, 'relative': v:true } }
+
+ " - Popup window (anchored to the bottom of the current window)
+ let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6, 'relative': v:true, 'yoffset': 1.0 } }
+
+ " - down / up / left / right
+ let g:fzf_layout = { 'down': '40%' }
+
+ " - Window using a Vim command
+ let g:fzf_layout = { 'window': 'enew' }
+ let g:fzf_layout = { 'window': '-tabnew' }
+ let g:fzf_layout = { 'window': '10new' }
+
+ " Customize fzf colors to match your color scheme
+ " - fzf#wrap translates this to a set of `--color` options
+ let g:fzf_colors =
+ \ { 'fg': ['fg', 'Normal'],
+ \ 'bg': ['bg', 'Normal'],
+ \ 'hl': ['fg', 'Comment'],
+ \ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
+ \ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
+ \ 'hl+': ['fg', 'Statement'],
+ \ 'info': ['fg', 'PreProc'],
+ \ 'border': ['fg', 'Ignore'],
+ \ 'prompt': ['fg', 'Conditional'],
+ \ 'pointer': ['fg', 'Exception'],
+ \ 'marker': ['fg', 'Keyword'],
+ \ 'spinner': ['fg', 'Label'],
+ \ 'header': ['fg', 'Comment'] }
+
+ " Enable per-command history
+ " - History files will be stored in the specified directory
+ " - When set, CTRL-N and CTRL-P will be bound to 'next-history' and
+ " 'previous-history' instead of 'down' and 'up'.
+ let g:fzf_history_dir = '~/.local/share/fzf-history'
+<
+
+Explanation of g:fzf_colors~
+ *fzf-explanation-of-gfzfcolors*
+
+`g:fzf_colors` is a dictionary mapping fzf elements to a color specification
+list:
+>
+ element: [ component, group1 [, group2, ...] ]
+<
+ - `element` is an fzf element to apply a color to:
+
+ ----------------------------+------------------------------------------------------
+ Element | Description ~
+ ----------------------------+------------------------------------------------------
+ `fg` / `bg` / `hl` | Item (foreground / background / highlight)
+ `fg+` / `bg+` / `hl+` | Current item (foreground / background / highlight)
+ `preview-fg` / `preview-bg` | Preview window text and background
+ `hl` / `hl+` | Highlighted substrings (normal / current)
+ `gutter` | Background of the gutter on the left
+ `pointer` | Pointer to the current line ( `>` )
+ `marker` | Multi-select marker ( `>` )
+ `border` | Border around the window ( `--border` and `--preview` )
+ `header` | Header ( `--header` or `--header-lines` )
+ `info` | Info line (match counters)
+ `spinner` | Streaming input indicator
+ `query` | Query string
+ `disabled` | Query string when search is disabled
+ `prompt` | Prompt before query ( `> ` )
+ `pointer` | Pointer to the current line ( `>` )
+ ----------------------------+------------------------------------------------------
+ - `component` specifies the component (`fg` / `bg`) from which to extract the
+ color when considering each of the following highlight groups
+ - `group1 [, group2, ...]` is a list of highlight groups that are searched (in
+ order) for a matching color definition
+
+For example, consider the following specification:
+>
+ 'prompt': ['fg', 'Conditional', 'Comment'],
+<
+This means we color the prompt - using the `fg` attribute of the `Conditional`
+if it exists, - otherwise use the `fg` attribute of the `Comment` highlight
+group if it exists, - otherwise fall back to the default color settings for
+the prompt.
+
+You can examine the color option generated according the setting by printing
+the result of `fzf#wrap()` function like so:
+>
+ :echo fzf#wrap()
+<
+
+FZF#RUN
+==============================================================================
+
+ *fzf#run*
+
+`fzf#run()` function is the core of Vim integration. It takes a single
+dictionary argument, a spec, and starts fzf process accordingly. At the very
+least, specify `sink` option to tell what it should do with the selected
+entry.
+>
+ call fzf#run({'sink': 'e'})
+<
+We haven't specified the `source`, so this is equivalent to starting fzf on
+command line without standard input pipe; fzf will use find command (or
+`$FZF_DEFAULT_COMMAND` if defined) to list the files under the current
+directory. When you select one, it will open it with the sink, `:e` command.
+If you want to open it in a new tab, you can pass `:tabedit` command instead
+as the sink.
+>
+ call fzf#run({'sink': 'tabedit'})
+<
+Instead of using the default find command, you can use any shell command as
+the source. The following example will list the files managed by git. It's
+equivalent to running `git ls-files | fzf` on shell.
+>
+ call fzf#run({'source': 'git ls-files', 'sink': 'e'})
+<
+fzf options can be specified as `options` entry in spec dictionary.
+>
+ call fzf#run({'sink': 'tabedit', 'options': '--multi --reverse'})
+<
+You can also pass a layout option if you don't want fzf window to take up the
+entire screen.
+>
+ " up / down / left / right / window are allowed
+ call fzf#run({'source': 'git ls-files', 'sink': 'e', 'left': '40%'})
+ call fzf#run({'source': 'git ls-files', 'sink': 'e', 'window': '30vnew'})
+<
+`source` doesn't have to be an external shell command, you can pass a Vim
+array as the source. In the next example, we pass the names of color schemes
+as the source to implement a color scheme selector.
+>
+ call fzf#run({'source': map(split(globpath(&rtp, 'colors/*.vim')),
+ \ 'fnamemodify(v:val, ":t:r")'),
+ \ 'sink': 'colo', 'left': '25%'})
+<
+The following table summarizes the available options.
+
+ ---------------------------+---------------+----------------------------------------------------------------------
+ Option name | Type | Description ~
+ ---------------------------+---------------+----------------------------------------------------------------------
+ `source` | string | External command to generate input to fzf (e.g. `find .` )
+ `source` | list | Vim list as input to fzf
+ `sink` | string | Vim command to handle the selected item (e.g. `e` , `tabe` )
+ `sink` | funcref | Reference to function to process each selected item
+ `sinklist` (or `sink*` ) | funcref | Similar to `sink` , but takes the list of output lines at once
+ `options` | string/list | Options to fzf
+ `dir` | string | Working directory
+ `up` / `down` / `left` / `right` | number/string | (Layout) Window position and size (e.g. `20` , `50%` )
+ `tmux` | string | (Layout) fzf-tmux options (e.g. `-p90%,60%` )
+ `window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `vertical aboveleft 30new` )
+ `window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}` )
+ ---------------------------+---------------+----------------------------------------------------------------------
+
+`options` entry can be either a string or a list. For simple cases, string
+should suffice, but prefer to use list type to avoid escaping issues.
+>
+ call fzf#run({'options': '--reverse --prompt "C:\\Program Files\\"'})
+ call fzf#run({'options': ['--reverse', '--prompt', 'C:\Program Files\']})
+<
+When `window` entry is a dictionary, fzf will start in a popup window. The
+following options are allowed:
+
+ - Required:
+ - `width` [float range [0 ~ 1]] or [integer range [8 ~ ]]
+ - `height` [float range [0 ~ 1]] or [integer range [4 ~ ]]
+ - Optional:
+ - `yoffset` [float default 0.5 range [0 ~ 1]]
+ - `xoffset` [float default 0.5 range [0 ~ 1]]
+ - `relative` [boolean default v:false]
+ - `border` [string default `rounded`]: Border style
+ - `rounded` / `sharp` / `horizontal` / `vertical` / `top` / `bottom` / `left` / `right` / `no[ne]`
+
+
+FZF#WRAP
+==============================================================================
+
+ *fzf#wrap*
+
+We have seen that several aspects of `:FZF` command can be configured with a
+set of global option variables; different ways to open files (`g:fzf_action`),
+window position and size (`g:fzf_layout`), color palette (`g:fzf_colors`),
+etc.
+
+So how can we make our custom `fzf#run` calls also respect those variables?
+Simply by "wrapping" the spec dictionary with `fzf#wrap` before passing it to
+`fzf#run`.
+
+ - `fzf#wrap([name string], [spec dict], [fullscreen bool]) -> (dict)`
+ - All arguments are optional. Usually we only need to pass a spec
+ dictionary.
+ - `name` is for managing history files. It is ignored if `g:fzf_history_dir`
+ is not defined.
+ - `fullscreen` can be either `0` or `1` (default: 0).
+
+`fzf#wrap` takes a spec and returns an extended version of it (also a
+dictionary) with additional options for addressing global preferences. You can
+examine the return value of it like so:
+>
+ echo fzf#wrap({'source': 'ls'})
+<
+After we "wrap" our spec, we pass it to `fzf#run`.
+>
+ call fzf#run(fzf#wrap({'source': 'ls'}))
+<
+Now it supports CTRL-T, CTRL-V, and CTRL-X key bindings (configurable via
+`g:fzf_action`) and it opens fzf window according to `g:fzf_layout` setting.
+
+To make it easier to use, let's define `LS` command.
+>
+ command! LS call fzf#run(fzf#wrap({'source': 'ls'}))
+<
+Type `:LS` and see how it works.
+
+We would like to make `:LS!` (bang version) open fzf in fullscreen, just like
+`:FZF!`. Add `-bang` to command definition, and use <bang> value to set the
+last `fullscreen` argument of `fzf#wrap` (see :help <bang>).
+>
+ " On :LS!, <bang> evaluates to '!', and '!0' becomes 1
+ command! -bang LS call fzf#run(fzf#wrap({'source': 'ls'}, <bang>0))
+<
+Our `:LS` command will be much more useful if we can pass a directory argument
+to it, so that something like `:LS /tmp` is possible.
+>
+ command! -bang -complete=dir -nargs=? LS
+ \ call fzf#run(fzf#wrap({'source': 'ls', 'dir': <q-args>}, <bang>0))
+<
+Lastly, if you have enabled `g:fzf_history_dir`, you might want to assign a
+unique name to our command and pass it as the first argument to `fzf#wrap`.
+>
+ " The query history for this command will be stored as 'ls' inside g:fzf_history_dir.
+ " The name is ignored if g:fzf_history_dir is not defined.
+ command! -bang -complete=dir -nargs=? LS
+ \ call fzf#run(fzf#wrap('ls', {'source': 'ls', 'dir': <q-args>}, <bang>0))
+<
+
+< Global options supported by fzf#wrap >______________________________________~
+ *fzf-global-options-supported-by-fzf#wrap*
+
+ - `g:fzf_layout`
+ - `g:fzf_action`
+ - Works only when no custom `sink` (or `sink*`) is provided
+ - Having custom sink usually means that each entry is not an ordinary
+ file path (e.g. name of color scheme), so we can't blindly apply the
+ same strategy (i.e. `tabedit some-color-scheme` doesn't make sense)
+ - `g:fzf_colors`
+ - `g:fzf_history_dir`
+
+
+TIPS *fzf-tips*
+==============================================================================
+
+
+< fzf inside terminal buffer >________________________________________________~
+ *fzf-inside-terminal-buffer*
+
+The latest versions of Vim and Neovim include builtin terminal emulator
+(`:terminal`) and fzf will start in a terminal buffer in the following cases:
+
+ - On Neovim
+ - On GVim
+ - On Terminal Vim with a non-default layout
+ - `call fzf#run({'left': '30%'})` or `let g:fzf_layout = {'left': '30%'}`
+
+On the latest versions of Vim and Neovim, fzf will start in a terminal buffer.
+If you find the default ANSI colors to be different, consider configuring the
+colors using `g:terminal_ansi_colors` in regular Vim or `g:terminal_color_x`
+in Neovim.
+
+ *g:terminal_color_15* *g:terminal_color_14* *g:terminal_color_13*
+*g:terminal_color_12* *g:terminal_color_11* *g:terminal_color_10* *g:terminal_color_9*
+ *g:terminal_color_8* *g:terminal_color_7* *g:terminal_color_6* *g:terminal_color_5*
+ *g:terminal_color_4* *g:terminal_color_3* *g:terminal_color_2* *g:terminal_color_1*
+ *g:terminal_color_0*
+>
+ " Terminal colors for seoul256 color scheme
+ if has('nvim')
+ let g:terminal_color_0 = '#4e4e4e'
+ let g:terminal_color_1 = '#d68787'
+ let g:terminal_color_2 = '#5f865f'
+ let g:terminal_color_3 = '#d8af5f'
+ let g:terminal_color_4 = '#85add4'
+ let g:terminal_color_5 = '#d7afaf'
+ let g:terminal_color_6 = '#87afaf'
+ let g:terminal_color_7 = '#d0d0d0'
+ let g:terminal_color_8 = '#626262'
+ let g:terminal_color_9 = '#d75f87'
+ let g:terminal_color_10 = '#87af87'
+ let g:terminal_color_11 = '#ffd787'
+ let g:terminal_color_12 = '#add4fb'
+ let g:terminal_color_13 = '#ffafaf'
+ let g:terminal_color_14 = '#87d7d7'
+ let g:terminal_color_15 = '#e4e4e4'
+ else
+ let g:terminal_ansi_colors = [
+ \ '#4e4e4e', '#d68787', '#5f865f', '#d8af5f',
+ \ '#85add4', '#d7afaf', '#87afaf', '#d0d0d0',
+ \ '#626262', '#d75f87', '#87af87', '#ffd787',
+ \ '#add4fb', '#ffafaf', '#87d7d7', '#e4e4e4'
+ \ ]
+ endif
+<
+
+< Starting fzf in a popup window >____________________________________________~
+ *fzf-starting-fzf-in-a-popup-window*
+>
+ " Required:
+ " - width [float range [0 ~ 1]] or [integer range [8 ~ ]]
+ " - height [float range [0 ~ 1]] or [integer range [4 ~ ]]
+ "
+ " Optional:
+ " - xoffset [float default 0.5 range [0 ~ 1]]
+ " - yoffset [float default 0.5 range [0 ~ 1]]
+ " - relative [boolean default v:false]
+ " - border [string default 'rounded']: Border style
+ " - 'rounded' / 'sharp' / 'horizontal' / 'vertical' / 'top' / 'bottom' / 'left' / 'right'
+ let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
+<
+Alternatively, you can make fzf open in a tmux popup window (requires tmux 3.2
+or above) by putting fzf-tmux options in `tmux` key.
+>
+ " See `man fzf-tmux` for available options
+ if exists('$TMUX')
+ let g:fzf_layout = { 'tmux': '-p90%,60%' }
+ else
+ let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
+ endif
+<
+
+< Hide statusline >___________________________________________________________~
+ *fzf-hide-statusline*
+
+When fzf starts in a terminal buffer, the file type of the buffer is set to
+`fzf`. So you can set up `FileType fzf` autocmd to customize the settings of
+the window.
+
+For example, if you open fzf on the bottom on the screen (e.g. `{'down':
+'40%'}`), you might want to temporarily disable the statusline for a cleaner
+look.
+>
+ let g:fzf_layout = { 'down': '30%' }
+ autocmd! FileType fzf
+ autocmd FileType fzf set laststatus=0 noshowmode noruler
+ \| autocmd BufLeave <buffer> set laststatus=2 showmode ruler
+<
+
+LICENSE *fzf-license*
+==============================================================================
+
+The MIT License (MIT)
+
+Copyright (c) 2013-2021 Junegunn Choi
+
+==============================================================================
+vim:tw=78:sw=2:ts=2:ft=help:norl:nowrap:
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/go.mod b/dot-oh-my-zsh/custom/plugins/fzf/go.mod
new file mode 100644
index 00000000..41b40ad0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/go.mod
@@ -0,0 +1,21 @@
+module github.com/junegunn/fzf
+
+require (
+ github.com/gdamore/tcell/v2 v2.5.3
+ github.com/mattn/go-isatty v0.0.14
+ github.com/mattn/go-runewidth v0.0.13
+ github.com/mattn/go-shellwords v1.0.12
+ github.com/rivo/uniseg v0.2.0
+ github.com/saracen/walker v0.1.2
+ golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12
+ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
+)
+
+require (
+ github.com/gdamore/encoding v1.0.0 // indirect
+ github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
+ golang.org/x/text v0.3.7 // indirect
+)
+
+go 1.17
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/go.sum b/dot-oh-my-zsh/custom/plugins/fzf/go.sum
new file mode 100644
index 00000000..8a875d5d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/go.sum
@@ -0,0 +1,32 @@
+github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
+github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
+github.com/gdamore/tcell/v2 v2.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0=
+github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
+github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/saracen/walker v0.1.2 h1:/o1TxP82n8thLvmL4GpJXduYaRmJ7qXp8u9dSlV0zmo=
+github.com/saracen/walker v0.1.2/go.mod h1:0oKYMsKVhSJ+ful4p/XbjvXbMgLEkLITZaxozsl4CGE=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM=
+golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/install b/dot-oh-my-zsh/custom/plugins/fzf/install
new file mode 100755
index 00000000..75f4de39
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/install
@@ -0,0 +1,377 @@
+#!/usr/bin/env bash
+
+set -u
+
+version=0.33.0
+auto_completion=
+key_bindings=
+update_config=2
+shells="bash zsh fish"
+prefix='~/.fzf'
+prefix_expand=~/.fzf
+fish_dir=${XDG_CONFIG_HOME:-$HOME/.config}/fish
+
+help() {
+ cat << EOF
+usage: $0 [OPTIONS]
+
+ --help Show this message
+ --bin Download fzf binary only; Do not generate ~/.fzf.{bash,zsh}
+ --all Download fzf binary and update configuration files
+ to enable key bindings and fuzzy completion
+ --xdg Generate files under \$XDG_CONFIG_HOME/fzf
+ --[no-]key-bindings Enable/disable key bindings (CTRL-T, CTRL-R, ALT-C)
+ --[no-]completion Enable/disable fuzzy completion (bash & zsh)
+ --[no-]update-rc Whether or not to update shell configuration files
+
+ --no-bash Do not set up bash configuration
+ --no-zsh Do not set up zsh configuration
+ --no-fish Do not set up fish configuration
+EOF
+}
+
+for opt in "$@"; do
+ case $opt in
+ --help)
+ help
+ exit 0
+ ;;
+ --all)
+ auto_completion=1
+ key_bindings=1
+ update_config=1
+ ;;
+ --xdg)
+ prefix='"${XDG_CONFIG_HOME:-$HOME/.config}"/fzf/fzf'
+ prefix_expand=${XDG_CONFIG_HOME:-$HOME/.config}/fzf/fzf
+ mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/fzf"
+ ;;
+ --key-bindings) key_bindings=1 ;;
+ --no-key-bindings) key_bindings=0 ;;
+ --completion) auto_completion=1 ;;
+ --no-completion) auto_completion=0 ;;
+ --update-rc) update_config=1 ;;
+ --no-update-rc) update_config=0 ;;
+ --bin) ;;
+ --no-bash) shells=${shells/bash/} ;;
+ --no-zsh) shells=${shells/zsh/} ;;
+ --no-fish) shells=${shells/fish/} ;;
+ *)
+ echo "unknown option: $opt"
+ help
+ exit 1
+ ;;
+ esac
+done
+
+cd "$(dirname "${BASH_SOURCE[0]}")"
+fzf_base=$(pwd)
+fzf_base_esc=$(printf %q "$fzf_base")
+
+ask() {
+ while true; do
+ read -p "$1 ([y]/n) " -r
+ REPLY=${REPLY:-"y"}
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ return 1
+ elif [[ $REPLY =~ ^[Nn]$ ]]; then
+ return 0
+ fi
+ done
+}
+
+check_binary() {
+ echo -n " - Checking fzf executable ... "
+ local output
+ output=$("$fzf_base"/bin/fzf --version 2>&1)
+ if [ $? -ne 0 ]; then
+ echo "Error: $output"
+ binary_error="Invalid binary"
+ else
+ output=${output/ */}
+ if [ "$version" != "$output" ]; then
+ echo "$output != $version"
+ binary_error="Invalid version"
+ else
+ echo "$output"
+ binary_error=""
+ return 0
+ fi
+ fi
+ rm -f "$fzf_base"/bin/fzf
+ return 1
+}
+
+link_fzf_in_path() {
+ if which_fzf="$(command -v fzf)"; then
+ echo " - Found in \$PATH"
+ echo " - Creating symlink: bin/fzf -> $which_fzf"
+ (cd "$fzf_base"/bin && rm -f fzf && ln -sf "$which_fzf" fzf)
+ check_binary && return
+ fi
+ return 1
+}
+
+try_curl() {
+ command -v curl > /dev/null &&
+ if [[ $1 =~ tar.gz$ ]]; then
+ curl -fL $1 | tar -xzf -
+ else
+ local temp=${TMPDIR:-/tmp}/fzf.zip
+ curl -fLo "$temp" $1 && unzip -o "$temp" && rm -f "$temp"
+ fi
+}
+
+try_wget() {
+ command -v wget > /dev/null &&
+ if [[ $1 =~ tar.gz$ ]]; then
+ wget -O - $1 | tar -xzf -
+ else
+ local temp=${TMPDIR:-/tmp}/fzf.zip
+ wget -O "$temp" $1 && unzip -o "$temp" && rm -f "$temp"
+ fi
+}
+
+download() {
+ echo "Downloading bin/fzf ..."
+ if [ -x "$fzf_base"/bin/fzf ]; then
+ echo " - Already exists"
+ check_binary && return
+ fi
+ link_fzf_in_path && return
+ mkdir -p "$fzf_base"/bin && cd "$fzf_base"/bin
+ if [ $? -ne 0 ]; then
+ binary_error="Failed to create bin directory"
+ return
+ fi
+
+ local url
+ url=https://github.com/junegunn/fzf/releases/download/$version/${1}
+ set -o pipefail
+ if ! (try_curl $url || try_wget $url); then
+ set +o pipefail
+ binary_error="Failed to download with curl and wget"
+ return
+ fi
+ set +o pipefail
+
+ if [ ! -f fzf ]; then
+ binary_error="Failed to download ${1}"
+ return
+ fi
+
+ chmod +x fzf && check_binary
+}
+
+# Try to download binary executable
+archi=$(uname -sm)
+binary_available=1
+binary_error=""
+case "$archi" in
+ Darwin\ arm64) download fzf-$version-darwin_arm64.zip ;;
+ Darwin\ x86_64) download fzf-$version-darwin_amd64.zip ;;
+ Linux\ armv5*) download fzf-$version-linux_armv5.tar.gz ;;
+ Linux\ armv6*) download fzf-$version-linux_armv6.tar.gz ;;
+ Linux\ armv7*) download fzf-$version-linux_armv7.tar.gz ;;
+ Linux\ armv8*) download fzf-$version-linux_arm64.tar.gz ;;
+ Linux\ aarch64*) download fzf-$version-linux_arm64.tar.gz ;;
+ Linux\ *64) download fzf-$version-linux_amd64.tar.gz ;;
+ FreeBSD\ *64) download fzf-$version-freebsd_amd64.tar.gz ;;
+ OpenBSD\ *64) download fzf-$version-openbsd_amd64.tar.gz ;;
+ CYGWIN*\ *64) download fzf-$version-windows_amd64.zip ;;
+ MINGW*\ *64) download fzf-$version-windows_amd64.zip ;;
+ MSYS*\ *64) download fzf-$version-windows_amd64.zip ;;
+ Windows*\ *64) download fzf-$version-windows_amd64.zip ;;
+ *) binary_available=0 binary_error=1 ;;
+esac
+
+cd "$fzf_base"
+if [ -n "$binary_error" ]; then
+ if [ $binary_available -eq 0 ]; then
+ echo "No prebuilt binary for $archi ..."
+ else
+ echo " - $binary_error !!!"
+ fi
+ if command -v go > /dev/null; then
+ echo -n "Building binary (go get -u github.com/junegunn/fzf) ... "
+ if [ -z "${GOPATH-}" ]; then
+ export GOPATH="${TMPDIR:-/tmp}/fzf-gopath"
+ mkdir -p "$GOPATH"
+ fi
+ if go get -ldflags "-s -w -X main.version=$version -X main.revision=go-get" github.com/junegunn/fzf; then
+ echo "OK"
+ cp "$GOPATH/bin/fzf" "$fzf_base/bin/"
+ else
+ echo "Failed to build binary. Installation failed."
+ exit 1
+ fi
+ else
+ echo "go executable not found. Installation failed."
+ exit 1
+ fi
+fi
+
+[[ "$*" =~ "--bin" ]] && exit 0
+
+for s in $shells; do
+ if ! command -v "$s" > /dev/null; then
+ shells=${shells/$s/}
+ fi
+done
+
+if [[ ${#shells} -lt 3 ]]; then
+ echo "No shell configuration to be updated."
+ exit 0
+fi
+
+# Auto-completion
+if [ -z "$auto_completion" ]; then
+ ask "Do you want to enable fuzzy auto-completion?"
+ auto_completion=$?
+fi
+
+# Key-bindings
+if [ -z "$key_bindings" ]; then
+ ask "Do you want to enable key bindings?"
+ key_bindings=$?
+fi
+
+echo
+for shell in $shells; do
+ [[ "$shell" = fish ]] && continue
+ src=${prefix_expand}.${shell}
+ echo -n "Generate $src ... "
+
+ fzf_completion="[[ \$- == *i* ]] && source \"$fzf_base/shell/completion.${shell}\" 2> /dev/null"
+ if [ $auto_completion -eq 0 ]; then
+ fzf_completion="# $fzf_completion"
+ fi
+
+ fzf_key_bindings="source \"$fzf_base/shell/key-bindings.${shell}\""
+ if [ $key_bindings -eq 0 ]; then
+ fzf_key_bindings="# $fzf_key_bindings"
+ fi
+
+ cat > "$src" << EOF
+# Setup fzf
+# ---------
+if [[ ! "\$PATH" == *$fzf_base_esc/bin* ]]; then
+ PATH="\${PATH:+\${PATH}:}$fzf_base/bin"
+fi
+
+# Auto-completion
+# ---------------
+$fzf_completion
+
+# Key bindings
+# ------------
+$fzf_key_bindings
+EOF
+ echo "OK"
+done
+
+# fish
+if [[ "$shells" =~ fish ]]; then
+ echo -n "Update fish_user_paths ... "
+ fish << EOF
+ echo \$fish_user_paths | \grep "$fzf_base"/bin > /dev/null
+ or set --universal fish_user_paths \$fish_user_paths "$fzf_base"/bin
+EOF
+ [ $? -eq 0 ] && echo "OK" || echo "Failed"
+
+ mkdir -p "${fish_dir}/functions"
+ fish_binding="${fish_dir}/functions/fzf_key_bindings.fish"
+ if [ $key_bindings -ne 0 ]; then
+ echo -n "Symlink $fish_binding ... "
+ ln -sf "$fzf_base/shell/key-bindings.fish" \
+ "$fish_binding" && echo "OK" || echo "Failed"
+ else
+ echo -n "Removing $fish_binding ... "
+ rm -f "$fish_binding"
+ echo "OK"
+ fi
+fi
+
+append_line() {
+ set -e
+
+ local update line file pat lno
+ update="$1"
+ line="$2"
+ file="$3"
+ pat="${4:-}"
+ lno=""
+
+ echo "Update $file:"
+ echo " - $line"
+ if [ -f "$file" ]; then
+ if [ $# -lt 4 ]; then
+ lno=$(\grep -nF "$line" "$file" | sed 's/:.*//' | tr '\n' ' ')
+ else
+ lno=$(\grep -nF "$pat" "$file" | sed 's/:.*//' | tr '\n' ' ')
+ fi
+ fi
+ if [ -n "$lno" ]; then
+ echo " - Already exists: line #$lno"
+ else
+ if [ $update -eq 1 ]; then
+ [ -f "$file" ] && echo >> "$file"
+ echo "$line" >> "$file"
+ echo " + Added"
+ else
+ echo " ~ Skipped"
+ fi
+ fi
+ echo
+ set +e
+}
+
+create_file() {
+ local file="$1"
+ shift
+ echo "Create $file:"
+ for line in "$@"; do
+ echo " $line"
+ echo "$line" >> "$file"
+ done
+ echo
+}
+
+if [ $update_config -eq 2 ]; then
+ echo
+ ask "Do you want to update your shell configuration files?"
+ update_config=$?
+fi
+echo
+for shell in $shells; do
+ [[ "$shell" = fish ]] && continue
+ [ $shell = zsh ] && dest=${ZDOTDIR:-~}/.zshrc || dest=~/.bashrc
+ append_line $update_config "[ -f ${prefix}.${shell} ] && source ${prefix}.${shell}" "$dest" "${prefix}.${shell}"
+done
+
+if [ $key_bindings -eq 1 ] && [[ "$shells" =~ fish ]]; then
+ bind_file="${fish_dir}/functions/fish_user_key_bindings.fish"
+ if [ ! -e "$bind_file" ]; then
+ create_file "$bind_file" \
+ 'function fish_user_key_bindings' \
+ ' fzf_key_bindings' \
+ 'end'
+ else
+ append_line $update_config "fzf_key_bindings" "$bind_file"
+ fi
+fi
+
+if [ $update_config -eq 1 ]; then
+ echo 'Finished. Restart your shell or reload config file.'
+ if [[ "$shells" =~ bash ]]; then
+ echo -n ' source ~/.bashrc # bash'
+ [[ "$archi" =~ Darwin ]] && echo -n ' (.bashrc should be loaded from .bash_profile)'
+ echo
+ fi
+ [[ "$shells" =~ zsh ]] && echo " source ${ZDOTDIR:-~}/.zshrc # zsh"
+ [[ "$shells" =~ fish ]] && [ $key_bindings -eq 1 ] && echo ' fzf_key_bindings # fish'
+ echo
+ echo 'Use uninstall script to remove fzf.'
+ echo
+fi
+echo 'For more information, see: https://github.com/junegunn/fzf'
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/install.ps1 b/dot-oh-my-zsh/custom/plugins/fzf/install.ps1
new file mode 100644
index 00000000..21e33bab
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/install.ps1
@@ -0,0 +1,65 @@
+$version="0.33.0"
+
+$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
+
+function check_binary () {
+ Write-Host " - Checking fzf executable ... " -NoNewline
+ $output=cmd /c $fzf_base\bin\fzf.exe --version 2>&1
+ if (-not $?) {
+ Write-Host "Error: $output"
+ $binary_error="Invalid binary"
+ } else {
+ $output=(-Split $output)[0]
+ if ($version -ne $output) {
+ Write-Host "$output != $version"
+ $binary_error="Invalid version"
+ } else {
+ Write-Host "$output"
+ $binary_error=""
+ return 1
+ }
+ }
+ Remove-Item "$fzf_base\bin\fzf.exe"
+ return 0
+}
+
+function download {
+ param($file)
+ Write-Host "Downloading bin/fzf ..."
+ if (Test-Path "$fzf_base\bin\fzf.exe") {
+ Write-Host " - Already exists"
+ if (check_binary) {
+ return
+ }
+ }
+ if (-not (Test-Path "$fzf_base\bin")) {
+ md "$fzf_base\bin"
+ }
+ if (-not $?) {
+ $binary_error="Failed to create bin directory"
+ return
+ }
+ cd "$fzf_base\bin"
+ $url="https://github.com/junegunn/fzf/releases/download/$version/$file"
+ $temp=$env:TMP + "\fzf.zip"
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+ if ($PSVersionTable.PSVersion.Major -ge 3) {
+ Invoke-WebRequest -Uri $url -OutFile $temp
+ } else {
+ (New-Object Net.WebClient).DownloadFile($url, $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$temp"))
+ }
+ if ($?) {
+ (Microsoft.PowerShell.Archive\Expand-Archive -Path $temp -DestinationPath .); (Remove-Item $temp)
+ } else {
+ $binary_error="Failed to download with powershell"
+ }
+ if (-not (Test-Path fzf.exe)) {
+ $binary_error="Failed to download $file"
+ return
+ }
+ echo y | icacls $fzf_base\bin\fzf.exe /grant Administrator:F ; check_binary >$null
+}
+
+download "fzf-$version-windows_amd64.zip"
+
+Write-Host 'For more information, see: https://github.com/junegunn/fzf'
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/main.go b/dot-oh-my-zsh/custom/plugins/fzf/main.go
new file mode 100644
index 00000000..98917cb0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/main.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+ fzf "github.com/junegunn/fzf/src"
+ "github.com/junegunn/fzf/src/protector"
+)
+
+var version string = "0.33"
+var revision string = "devel"
+
+func main() {
+ protector.Protect()
+ fzf.Run(fzf.ParseOptions(), version, revision)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/man/man1/fzf-tmux.1 b/dot-oh-my-zsh/custom/plugins/fzf/man/man1/fzf-tmux.1
new file mode 100644
index 00000000..47a49c45
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/man/man1/fzf-tmux.1
@@ -0,0 +1,68 @@
+.ig
+The MIT License (MIT)
+
+Copyright (c) 2013-2021 Junegunn Choi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+..
+.TH fzf-tmux 1 "Aug 2022" "fzf 0.33.0" "fzf-tmux - open fzf in tmux split pane"
+
+.SH NAME
+fzf-tmux - open fzf in tmux split pane
+
+.SH SYNOPSIS
+.B fzf-tmux [LAYOUT OPTIONS] [--] [FZF OPTIONS]
+
+.SH DESCRIPTION
+fzf-tmux is a wrapper script for fzf that opens fzf in a tmux split pane or in
+a tmux popup window. It is designed to work just like fzf except that it does
+not take up the whole screen. You can safely use fzf-tmux instead of fzf in
+your scripts as the extra options will be silently ignored if you're not on
+tmux.
+
+.SH LAYOUT OPTIONS
+
+(default layout: \fB-d 50%\fR)
+
+.SS Popup window
+(requires tmux 3.2 or above)
+.TP
+.B "-p [WIDTH[%][,HEIGHT[%]]]"
+.TP
+.B "-w WIDTH[%]"
+.TP
+.B "-h WIDTH[%]"
+.TP
+.B "-x COL"
+.TP
+.B "-y ROW"
+
+.SS Split pane
+.TP
+.B "-u [height[%]]"
+Split above (up)
+.TP
+.B "-d [height[%]]"
+Split below (down)
+.TP
+.B "-l [width[%]]"
+Split left
+.TP
+.B "-r [width[%]]"
+Split right
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/man/man1/fzf.1 b/dot-oh-my-zsh/custom/plugins/fzf/man/man1/fzf.1
new file mode 100644
index 00000000..a6455cc2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/man/man1/fzf.1
@@ -0,0 +1,1046 @@
+.ig
+The MIT License (MIT)
+
+Copyright (c) 2013-2021 Junegunn Choi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+..
+.TH fzf 1 "Aug 2022" "fzf 0.33.0" "fzf - a command-line fuzzy finder"
+
+.SH NAME
+fzf - a command-line fuzzy finder
+
+.SH SYNOPSIS
+fzf [options]
+
+.SH DESCRIPTION
+fzf is a general-purpose command-line fuzzy finder.
+
+.SH OPTIONS
+.SS Search mode
+.TP
+.B "-x, --extended"
+Extended-search mode. Since 0.10.9, this is enabled by default. You can disable
+it with \fB+x\fR or \fB--no-extended\fR.
+.TP
+.B "-e, --exact"
+Enable exact-match
+.TP
+.B "-i"
+Case-insensitive match (default: smart-case match)
+.TP
+.B "+i"
+Case-sensitive match
+.TP
+.B "--literal"
+Do not normalize latin script letters for matching.
+.TP
+.BI "--scheme=" SCHEME
+Choose scoring scheme tailored for different types of input.
+
+.br
+.BR default " Generic scoring scheme designed to work well with any type of input"
+.br
+.BR path " Scoring scheme for paths (additional bonus point only after path separator)
+.br
+.BR history " Scoring scheme for command history (no additional bonus points).
+ Sets \fB--tiebreak=index\fR as well.
+.br
+.TP
+.BI "--algo=" TYPE
+Fuzzy matching algorithm (default: v2)
+
+.br
+.BR v2 " Optimal scoring algorithm (quality)"
+.br
+.BR v1 " Faster but not guaranteed to find the optimal result (performance)"
+.br
+
+.TP
+.BI "-n, --nth=" "N[,..]"
+Comma-separated list of field index expressions for limiting search scope.
+See \fBFIELD INDEX EXPRESSION\fR for the details.
+.TP
+.BI "--with-nth=" "N[,..]"
+Transform the presentation of each line using field index expressions
+.TP
+.BI "-d, --delimiter=" "STR"
+Field delimiter regex for \fB--nth\fR and \fB--with-nth\fR (default: AWK-style)
+.TP
+.BI "--disabled"
+Do not perform search. With this option, fzf becomes a simple selector
+interface rather than a "fuzzy finder". You can later enable the search using
+\fBenable-search\fR or \fBtoggle-search\fR action.
+.SS Search result
+.TP
+.B "+s, --no-sort"
+Do not sort the result
+.TP
+.B "--tac"
+Reverse the order of the input
+
+.RS
+e.g.
+ \fBhistory | fzf --tac --no-sort\fR
+.RE
+.TP
+.BI "--tiebreak=" "CRI[,..]"
+Comma-separated list of sort criteria to apply when the scores are tied.
+.br
+
+.br
+.BR length " Prefers line with shorter length"
+.br
+.BR chunk " Prefers line with shorter matched chunk (delimited by whitespaces)"
+.br
+.BR begin " Prefers line with matched substring closer to the beginning"
+.br
+.BR end " Prefers line with matched substring closer to the end"
+.br
+.BR index " Prefers line that appeared earlier in the input stream"
+.br
+
+.br
+- Each criterion should appear only once in the list
+.br
+- \fBindex\fR is only allowed at the end of the list
+.br
+- \fBindex\fR is implicitly appended to the list when not specified
+.br
+- Default is \fBlength\fR (or equivalently \fBlength\fR,index)
+.br
+- If \fBend\fR is found in the list, fzf will scan each line backwards
+.SS Interface
+.TP
+.B "-m, --multi"
+Enable multi-select with tab/shift-tab. It optionally takes an integer argument
+which denotes the maximum number of items that can be selected.
+.TP
+.B "+m, --no-multi"
+Disable multi-select
+.TP
+.B "--no-mouse"
+Disable mouse
+.TP
+.BI "--bind=" "KEYBINDS"
+Comma-separated list of custom key bindings. See \fBKEY/EVENT BINDINGS\fR for
+the details.
+.TP
+.B "--cycle"
+Enable cyclic scroll
+.TP
+.B "--keep-right"
+Keep the right end of the line visible when it's too long. Effective only when
+the query string is empty.
+.TP
+.BI "--scroll-off=" "LINES"
+Number of screen lines to keep above or below when scrolling to the top or to
+the bottom (default: 0).
+.TP
+.B "--no-hscroll"
+Disable horizontal scroll
+.TP
+.BI "--hscroll-off=" "COLS"
+Number of screen columns to keep to the right of the highlighted substring
+(default: 10). Setting it to a large value will cause the text to be positioned
+on the center of the screen.
+.TP
+.B "--filepath-word"
+Make word-wise movements and actions respect path separators. The following
+actions are affected:
+
+\fBbackward-kill-word\fR
+.br
+\fBbackward-word\fR
+.br
+\fBforward-word\fR
+.br
+\fBkill-word\fR
+.TP
+.BI "--jump-labels=" "CHARS"
+Label characters for \fBjump\fR and \fBjump-accept\fR
+.SS Layout
+.TP
+.BI "--height=" "HEIGHT[%]"
+Display fzf window below the cursor with the given height instead of using
+the full screen.
+.TP
+.BI "--min-height=" "HEIGHT"
+Minimum height when \fB--height\fR is given in percent (default: 10).
+Ignored when \fB--height\fR is not specified.
+.TP
+.BI "--layout=" "LAYOUT"
+Choose the layout (default: default)
+
+.br
+.BR default " Display from the bottom of the screen"
+.br
+.BR reverse " Display from the top of the screen"
+.br
+.BR reverse-list " Display from the top of the screen, prompt at the bottom"
+.br
+
+.TP
+.B "--reverse"
+A synonym for \fB--layout=reverse\fB
+
+.TP
+.BI "--border" [=BORDER_OPT]
+Draw border around the finder
+
+.br
+.BR rounded " Border with rounded corners (default)"
+.br
+.BR sharp " Border with sharp corners"
+.br
+.BR horizontal " Horizontal lines above and below the finder"
+.br
+.BR vertical " Vertical lines on each side of the finder"
+.br
+.BR top " (up)"
+.br
+.BR bottom " (down)"
+.br
+.BR left
+.br
+.BR right
+.br
+.BR none
+.br
+
+.TP
+.B "--no-unicode"
+Use ASCII characters instead of Unicode box drawing characters to draw border
+
+.TP
+.BI "--margin=" MARGIN
+Comma-separated expression for margins around the finder.
+.br
+
+.br
+.RS
+.BR TRBL " Same margin for top, right, bottom, and left"
+.br
+.BR TB,RL " Vertical, horizontal margin"
+.br
+.BR T,RL,B " Top, horizontal, bottom margin"
+.br
+.BR T,R,B,L " Top, right, bottom, left margin"
+.br
+
+.br
+Each part can be given in absolute number or in percentage relative to the
+terminal size with \fB%\fR suffix.
+.br
+
+.br
+e.g.
+ \fBfzf --margin 10%
+ fzf --margin 1,5%\fR
+.RE
+.TP
+.BI "--padding=" PADDING
+Comma-separated expression for padding inside the border. Padding is
+distinguishable from margin only when \fB--border\fR option is used.
+.br
+
+.br
+e.g.
+ \fBfzf --margin 5% --padding 5% --border --preview 'cat {}' \\
+ --color bg:#222222,preview-bg:#333333\fR
+
+.br
+.RS
+.BR TRBL " Same padding for top, right, bottom, and left"
+.br
+.BR TB,RL " Vertical, horizontal padding"
+.br
+.BR T,RL,B " Top, horizontal, bottom padding"
+.br
+.BR T,R,B,L " Top, right, bottom, left padding"
+.br
+.RE
+
+.TP
+.BI "--info=" "STYLE"
+Determines the display style of finder info.
+
+.br
+.BR default " Display on the next line to the prompt"
+.br
+.BR inline " Display on the same line"
+.br
+.BR hidden " Do not display finder info"
+.br
+
+.TP
+.B "--no-info"
+A synonym for \fB--info=hidden\fB
+
+.TP
+.BI "--prompt=" "STR"
+Input prompt (default: '> ')
+.TP
+.BI "--pointer=" "STR"
+Pointer to the current line (default: '>')
+.TP
+.BI "--marker=" "STR"
+Multi-select marker (default: '>')
+.TP
+.BI "--header=" "STR"
+The given string will be printed as the sticky header. The lines are displayed
+in the given order from top to bottom regardless of \fB--layout\fR option, and
+are not affected by \fB--with-nth\fR. ANSI color codes are processed even when
+\fB--ansi\fR is not set.
+.TP
+.BI "--header-lines=" "N"
+The first N lines of the input are treated as the sticky header. When
+\fB--with-nth\fR is set, the lines are transformed just like the other
+lines that follow.
+.TP
+.B "--header-first"
+Print header before the prompt line
+.TP
+.BI "--ellipsis=" "STR"
+Ellipsis to show when line is truncated (default: '..')
+.SS Display
+.TP
+.B "--ansi"
+Enable processing of ANSI color codes
+.TP
+.BI "--tabstop=" SPACES
+Number of spaces for a tab character (default: 8)
+.TP
+.BI "--color=" "[BASE_SCHEME][,COLOR_NAME[:ANSI_COLOR][:ANSI_ATTRIBUTES]]..."
+Color configuration. The name of the base color scheme is followed by custom
+color mappings.
+
+.RS
+.B BASE SCHEME:
+ (default: dark on 256-color terminal, otherwise 16)
+
+ \fBdark \fRColor scheme for dark 256-color terminal
+ \fBlight \fRColor scheme for light 256-color terminal
+ \fB16 \fRColor scheme for 16-color terminal
+ \fBbw \fRNo colors (equivalent to \fB--no-color\fR)
+
+.B COLOR NAMES:
+ \fBfg \fRText
+ \fBbg \fRBackground
+ \fBpreview-fg \fRPreview window text
+ \fBpreview-bg \fRPreview window background
+ \fBhl \fRHighlighted substrings
+ \fBfg+ \fRText (current line)
+ \fBbg+ \fRBackground (current line)
+ \fBgutter \fRGutter on the left (defaults to \fBbg+\fR)
+ \fBhl+ \fRHighlighted substrings (current line)
+ \fBquery \fRQuery string
+ \fBdisabled \fRQuery string when search is disabled
+ \fBinfo \fRInfo line (match counters)
+ \fBborder \fRBorder around the window (\fB--border\fR and \fB--preview\fR)
+ \fBprompt \fRPrompt
+ \fBpointer \fRPointer to the current line
+ \fBmarker \fRMulti-select marker
+ \fBspinner \fRStreaming input indicator
+ \fBheader \fRHeader
+
+.B ANSI COLORS:
+ \fB-1 \fRDefault terminal foreground/background color
+ \fB \fR(or the original color of the text)
+ \fB0 ~ 15 \fR16 base colors
+ \fBblack\fR
+ \fBred\fR
+ \fBgreen\fR
+ \fByellow\fR
+ \fBblue\fR
+ \fBmagenta\fR
+ \fBcyan\fR
+ \fBwhite\fR
+ \fBbright-black\fR (gray | grey)
+ \fBbright-red\fR
+ \fBbright-green\fR
+ \fBbright-yellow\fR
+ \fBbright-blue\fR
+ \fBbright-magenta\fR
+ \fBbright-cyan\fR
+ \fBbright-white\fR
+ \fB16 ~ 255 \fRANSI 256 colors
+ \fB#rrggbb \fR24-bit colors
+
+.B ANSI ATTRIBUTES: (Only applies to foreground colors)
+ \fBregular \fRClears previously set attributes; should precede the other ones
+ \fBbold\fR
+ \fBunderline\fR
+ \fBreverse\fR
+ \fBdim\fR
+ \fBitalic\fR
+ \fBstrikethrough\fR
+
+.B EXAMPLES:
+
+ \fB# Seoul256 theme with 8-bit colors
+ # (https://github.com/junegunn/seoul256.vim)
+ fzf --color='bg:237,bg+:236,info:143,border:240,spinner:108' \\
+ --color='hl:65,fg:252,header:65,fg+:252' \\
+ --color='pointer:161,marker:168,prompt:110,hl+:108'
+
+ # Seoul256 theme with 24-bit colors
+ fzf --color='bg:#4B4B4B,bg+:#3F3F3F,info:#BDBB72,border:#6B6B6B,spinner:#98BC99' \\
+ --color='hl:#719872,fg:#D9D9D9,header:#719872,fg+:#D9D9D9' \\
+ --color='pointer:#E12672,marker:#E17899,prompt:#98BEDE,hl+:#98BC99'\fR
+.RE
+.TP
+.B "--no-bold"
+Do not use bold text
+.TP
+.B "--black"
+Use black background
+.SS History
+.TP
+.BI "--history=" "HISTORY_FILE"
+Load search history from the specified file and update the file on completion.
+When enabled, \fBCTRL-N\fR and \fBCTRL-P\fR are automatically remapped to
+\fBnext-history\fR and \fBprevious-history\fR.
+.TP
+.BI "--history-size=" "N"
+Maximum number of entries in the history file (default: 1000). The file is
+automatically truncated when the number of the lines exceeds the value.
+.SS Preview
+.TP
+.BI "--preview=" "COMMAND"
+Execute the given command for the current line and display the result on the
+preview window. \fB{}\fR in the command is the placeholder that is replaced to
+the single-quoted string of the current line. To transform the replacement
+string, specify field index expressions between the braces (See \fBFIELD INDEX
+EXPRESSION\fR for the details).
+
+.RS
+e.g.
+ \fBfzf --preview='head -$LINES {}'
+ ls -l | fzf --preview="echo user={3} when={-4..-2}; cat {-1}" --header-lines=1\fR
+
+fzf exports \fB$FZF_PREVIEW_LINES\fR and \fB$FZF_PREVIEW_COLUMNS\fR so that
+they represent the exact size of the preview window. (It also overrides
+\fB$LINES\fR and \fB$COLUMNS\fR with the same values but they can be reset
+by the default shell, so prefer to refer to the ones with \fBFZF_PREVIEW_\fR
+prefix.)
+
+A placeholder expression starting with \fB+\fR flag will be replaced to the
+space-separated list of the selected lines (or the current line if no selection
+was made) individually quoted.
+
+e.g.
+ \fBfzf --multi --preview='head -10 {+}'
+ git log --oneline | fzf --multi --preview 'git show {+1}'\fR
+
+When using a field index expression, leading and trailing whitespace is stripped
+from the replacement string. To preserve the whitespace, use the \fBs\fR flag.
+
+Also, \fB{q}\fR is replaced to the current query string, and \fB{n}\fR is
+replaced to zero-based ordinal index of the line. Use \fB{+n}\fR if you want
+all index numbers when multiple lines are selected.
+
+A placeholder expression with \fBf\fR flag is replaced to the path of
+a temporary file that holds the evaluated list. This is useful when you
+multi-select a large number of items and the length of the evaluated string may
+exceed \fBARG_MAX\fR.
+
+e.g.
+ \fB# Press CTRL-A to select 100K items and see the sum of all the numbers.
+ # This won't work properly without 'f' flag due to ARG_MAX limit.
+ seq 100000 | fzf --multi --bind ctrl-a:select-all \\
+ --preview "awk '{sum+=\\$1} END {print sum}' {+f}"\fR
+
+Note that you can escape a placeholder pattern by prepending a backslash.
+
+Preview window will be updated even when there is no match for the current
+query if any of the placeholder expressions evaluates to a non-empty string.
+
+Since 0.24.0, fzf can render partial preview content before the preview command
+completes. ANSI escape sequence for clearing the display (\fBCSI 2 J\fR) is
+supported, so you can use it to implement preview window that is constantly
+updating.
+
+e.g.
+ \fBfzf --preview 'for i in $(seq 100000); do
+ (( i % 200 == 0 )) && printf "\\033[2J"
+ echo "$i"
+ sleep 0.01
+ done'\fR
+.RE
+.TP
+.BI "--preview-window=" "[POSITION][,SIZE[%]][,border-BORDER_OPT][,[no]wrap][,[no]follow][,[no]cycle][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]"
+
+.RS
+.B POSITION: (default: right)
+ \fBup
+ \fBdown
+ \fBleft
+ \fBright
+
+\fRDetermines the layout of the preview window.
+
+* If the argument contains \fB:hidden\fR, the preview window will be hidden by
+default until \fBtoggle-preview\fR action is triggered.
+
+* If size is given as 0, preview window will not be visible, but fzf will still
+execute the command in the background.
+
+* Long lines are truncated by default. Line wrap can be enabled with
+\fBwrap\fR flag.
+
+* Preview window will automatically scroll to the bottom when \fBfollow\fR
+flag is set, similarly to how \fBtail -f\fR works.
+
+.RS
+e.g.
+ \fBfzf --preview-window follow --preview 'for i in $(seq 100000); do
+ echo "$i"
+ sleep 0.01
+ (( i % 300 == 0 )) && printf "\\033[2J"
+ done'\fR
+.RE
+
+* Cyclic scrolling is enabled with \fBcycle\fR flag.
+
+* To change the style of the border of the preview window, specify one of
+the options for \fB--border\fR with \fBborder-\fR prefix.
+e.g. \fBborder-rounded\fR (border with rounded edges, default),
+\fBborder-sharp\fR (border with sharp edges), \fBborder-left\fR,
+\fBborder-none\fR, etc.
+
+* \fB[:+SCROLL[OFFSETS][/DENOM]]\fR determines the initial scroll offset of the
+preview window.
+
+ - \fBSCROLL\fR can be either a numeric integer or a single-field index expression that refers to a numeric integer.
+
+ - The optional \fBOFFSETS\fR part is for adjusting the base offset. It should be given as a series of signed integers (\fB-INTEGER\fR or \fB+INTEGER\fR).
+
+ - The final \fB/DENOM\fR part is for specifying a fraction of the preview window height.
+
+* \fB~HEADER_LINES\fR keeps the top N lines as the fixed header so that they
+are always visible.
+
+* \fBdefault\fR resets all options previously set to the default.
+
+.RS
+e.g.
+ \fB# Non-default scroll window positions and sizes
+ fzf --preview="head {}" --preview-window=up,30%
+ fzf --preview="file {}" --preview-window=down,1
+
+ # Initial scroll offset is set to the line number of each line of
+ # git grep output *minus* 5 lines (-5)
+ git grep --line-number '' |
+ fzf --delimiter : --preview 'nl {1}' --preview-window '+{2}-5'
+
+ # Preview with bat, matching line in the middle of the window below
+ # the fixed header of the top 3 lines
+ #
+ # ~3 Top 3 lines as the fixed header
+ # +{2} Base scroll offset extracted from the second field
+ # +3 Extra offset to compensate for the 3-line header
+ # /2 Put in the middle of the preview area
+ #
+ git grep --line-number '' |
+ fzf --delimiter : \\
+ --preview 'bat --style=full --color=always --highlight-line {2} {1}' \\
+ --preview-window '~3,+{2}+3/2'
+
+ # Display top 3 lines as the fixed header
+ fzf --preview 'bat --style=full --color=always {}' --preview-window '~3'\fR
+.RE
+
+* You can specify an alternative set of options that are used only when the size
+ of the preview window is below a certain threshold. Note that only one
+ alternative layout is allowed.
+
+.RS
+e.g.
+ \fBfzf --preview 'cat {}' --preview-window 'right,border-left,<30(up,30%,border-bottom)'\fR
+.RE
+
+.SS Scripting
+.TP
+.BI "-q, --query=" "STR"
+Start the finder with the given query
+.TP
+.B "-1, --select-1"
+If there is only one match for the initial query (\fB--query\fR), do not start
+interactive finder and automatically select the only match
+.TP
+.B "-0, --exit-0"
+If there is no match for the initial query (\fB--query\fR), do not start
+interactive finder and exit immediately
+.TP
+.BI "-f, --filter=" "STR"
+Filter mode. Do not start interactive finder. When used with \fB--no-sort\fR,
+fzf becomes a fuzzy-version of grep.
+.TP
+.B "--print-query"
+Print query as the first line
+.TP
+.BI "--expect=" "KEY[,..]"
+Comma-separated list of keys that can be used to complete fzf in addition to
+the default enter key. When this option is set, fzf will print the name of the
+key pressed as the first line of its output (or as the second line if
+\fB--print-query\fR is also used). The line will be empty if fzf is completed
+with the default enter key. If \fB--expect\fR option is specified multiple
+times, fzf will expect the union of the keys. \fB--no-expect\fR will clear the
+list.
+
+.RS
+e.g.
+ \fBfzf --expect=ctrl-v,ctrl-t,alt-s --expect=f1,f2,~,@\fR
+.RE
+.TP
+.B "--read0"
+Read input delimited by ASCII NUL characters instead of newline characters
+.TP
+.B "--print0"
+Print output delimited by ASCII NUL characters instead of newline characters
+.TP
+.B "--no-clear"
+Do not clear finder interface on exit. If fzf was started in full screen mode,
+it will not switch back to the original screen, so you'll have to manually run
+\fBtput rmcup\fR to return. This option can be used to avoid flickering of the
+screen when your application needs to start fzf multiple times in order.
+.TP
+.B "--sync"
+Synchronous search for multi-staged filtering. If specified, fzf will launch
+ncurses finder only after the input stream is complete.
+
+.RS
+e.g. \fBfzf --multi | fzf --sync\fR
+.RE
+.TP
+.B "--version"
+Display version information and exit
+
+.TP
+Note that most options have the opposite versions with \fB--no-\fR prefix.
+
+.SH ENVIRONMENT VARIABLES
+.TP
+.B FZF_DEFAULT_COMMAND
+Default command to use when input is tty. On *nix systems, fzf runs the command
+with \fB$SHELL -c\fR if \fBSHELL\fR is set, otherwise with \fBsh -c\fR, so in
+this case make sure that the command is POSIX-compliant.
+.TP
+.B FZF_DEFAULT_OPTS
+Default options. e.g. \fBexport FZF_DEFAULT_OPTS="--extended --cycle"\fR
+
+.SH EXIT STATUS
+.BR 0 " Normal exit"
+.br
+.BR 1 " No match"
+.br
+.BR 2 " Error"
+.br
+.BR 130 " Interrupted with \fBCTRL-C\fR or \fBESC\fR"
+
+.SH FIELD INDEX EXPRESSION
+
+A field index expression can be a non-zero integer or a range expression
+([BEGIN]..[END]). \fB--nth\fR and \fB--with-nth\fR take a comma-separated list
+of field index expressions.
+
+.SS Examples
+.BR 1 " The 1st field"
+.br
+.BR 2 " The 2nd field"
+.br
+.BR -1 " The last field"
+.br
+.BR -2 " The 2nd to last field"
+.br
+.BR 3..5 " From the 3rd field to the 5th field"
+.br
+.BR 2.. " From the 2nd field to the last field"
+.br
+.BR ..-3 " From the 1st field to the 3rd to the last field"
+.br
+.BR .. " All the fields"
+.br
+
+.SH EXTENDED SEARCH MODE
+
+Unless specified otherwise, fzf will start in "extended-search mode". In this
+mode, you can specify multiple patterns delimited by spaces, such as: \fB'wild
+^music .mp3$ sbtrkt !rmx\fR
+
+You can prepend a backslash to a space (\fB\\ \fR) to match a literal space
+character.
+
+.SS Exact-match (quoted)
+A term that is prefixed by a single-quote character (\fB'\fR) is interpreted as
+an "exact-match" (or "non-fuzzy") term. fzf will search for the exact
+occurrences of the string.
+
+.SS Anchored-match
+A term can be prefixed by \fB^\fR, or suffixed by \fB$\fR to become an
+anchored-match term. Then fzf will search for the lines that start with or end
+with the given string. An anchored-match term is also an exact-match term.
+
+.SS Negation
+If a term is prefixed by \fB!\fR, fzf will exclude the lines that satisfy the
+term from the result. In this case, fzf performs exact match by default.
+
+.SS Exact-match by default
+If you don't prefer fuzzy matching and do not wish to "quote" (prefixing with
+\fB'\fR) every word, start fzf with \fB-e\fR or \fB--exact\fR option. Note that
+when \fB--exact\fR is set, \fB'\fR-prefix "unquotes" the term.
+
+.SS OR operator
+A single bar character term acts as an OR operator. For example, the following
+query matches entries that start with \fBcore\fR and end with either \fBgo\fR,
+\fBrb\fR, or \fBpy\fR.
+
+e.g. \fB^core go$ | rb$ | py$\fR
+
+.SH KEY/EVENT BINDINGS
+\fB--bind\fR option allows you to bind \fBa key\fR or \fBan event\fR to one or
+more \fBactions\fR. You can use it to customize key bindings or implement
+dynamic behaviors.
+
+\fB--bind\fR takes a comma-separated list of binding expressions. Each binding
+expression is \fBKEY:ACTION\fR or \fBEVENT:ACTION\fR.
+
+e.g.
+ \fBfzf --bind=ctrl-j:accept,ctrl-k:kill-line\fR
+
+.SS AVAILABLE KEYS: (SYNONYMS)
+\fIctrl-[a-z]\fR
+.br
+\fIctrl-space\fR
+.br
+\fIctrl-\\\fR
+.br
+\fIctrl-]\fR
+.br
+\fIctrl-^\fR (\fIctrl-6\fR)
+.br
+\fIctrl-/\fR (\fIctrl-_\fR)
+.br
+\fIctrl-alt-[a-z]\fR
+.br
+\fIalt-[*]\fR (Any case-sensitive single character is allowed)
+.br
+\fIf[1-12]\fR
+.br
+\fIenter\fR (\fIreturn\fR \fIctrl-m\fR)
+.br
+\fIspace\fR
+.br
+\fIbspace\fR (\fIbs\fR)
+.br
+\fIalt-up\fR
+.br
+\fIalt-down\fR
+.br
+\fIalt-left\fR
+.br
+\fIalt-right\fR
+.br
+\fIalt-enter\fR
+.br
+\fIalt-space\fR
+.br
+\fIalt-bspace\fR (\fIalt-bs\fR)
+.br
+\fItab\fR
+.br
+\fIbtab\fR (\fIshift-tab\fR)
+.br
+\fIesc\fR
+.br
+\fIdel\fR
+.br
+\fIup\fR
+.br
+\fIdown\fR
+.br
+\fIleft\fR
+.br
+\fIright\fR
+.br
+\fIhome\fR
+.br
+\fIend\fR
+.br
+\fIinsert\fR
+.br
+\fIpgup\fR (\fIpage-up\fR)
+.br
+\fIpgdn\fR (\fIpage-down\fR)
+.br
+\fIshift-up\fR
+.br
+\fIshift-down\fR
+.br
+\fIshift-left\fR
+.br
+\fIshift-right\fR
+.br
+\fIalt-shift-up\fR
+.br
+\fIalt-shift-down\fR
+.br
+\fIalt-shift-left\fR
+.br
+\fIalt-shift-right\fR
+.br
+\fIleft-click\fR
+.br
+\fIright-click\fR
+.br
+\fIdouble-click\fR
+.br
+or any single character
+
+.SS AVAILABLE EVENTS:
+\fIchange\fR
+.RS
+Triggered whenever the query string is changed
+
+e.g.
+ \fB# Move cursor to the first entry whenever the query is changed
+ fzf --bind change:first\fR
+.RE
+
+\fIbackward-eof\fR
+.RS
+Triggered when the query string is already empty and you try to delete it
+backward.
+
+e.g.
+ \fBfzf --bind backward-eof:abort\fR
+.RE
+
+.SS AVAILABLE ACTIONS:
+A key or an event can be bound to one or more of the following actions.
+
+ \fBACTION: DEFAULT BINDINGS (NOTES):
+ \fBabort\fR \fIctrl-c ctrl-g ctrl-q esc\fR
+ \fBaccept\fR \fIenter double-click\fR
+ \fBaccept-non-empty\fR (same as \fBaccept\fR except that it prevents fzf from exiting without selection)
+ \fBbackward-char\fR \fIctrl-b left\fR
+ \fBbackward-delete-char\fR \fIctrl-h bspace\fR
+ \fBbackward-delete-char/eof\fR (same as \fBbackward-delete-char\fR except aborts fzf if query is empty)
+ \fBbackward-kill-word\fR \fIalt-bs\fR
+ \fBbackward-word\fR \fIalt-b shift-left\fR
+ \fBbeginning-of-line\fR \fIctrl-a home\fR
+ \fBcancel\fR (clear query string if not empty, abort fzf otherwise)
+ \fBchange-preview(...)\fR (change \fB--preview\fR option)
+ \fBchange-preview-window(...)\fR (change \fB--preview-window\fR option; rotate through the multiple option sets separated by '|')
+ \fBchange-prompt(...)\fR (change prompt to the given string)
+ \fBclear-screen\fR \fIctrl-l\fR
+ \fBclear-selection\fR (clear multi-selection)
+ \fBclose\fR (close preview window if open, abort fzf otherwise)
+ \fBclear-query\fR (clear query string)
+ \fBdelete-char\fR \fIdel\fR
+ \fBdelete-char/eof\fR \fIctrl-d\fR (same as \fBdelete-char\fR except aborts fzf if query is empty)
+ \fBdeselect\fR
+ \fBdeselect-all\fR (deselect all matches)
+ \fBdisable-search\fR (disable search functionality)
+ \fBdown\fR \fIctrl-j ctrl-n down\fR
+ \fBenable-search\fR (enable search functionality)
+ \fBend-of-line\fR \fIctrl-e end\fR
+ \fBexecute(...)\fR (see below for the details)
+ \fBexecute-silent(...)\fR (see below for the details)
+ \fBfirst\fR (move to the first match)
+ \fBforward-char\fR \fIctrl-f right\fR
+ \fBforward-word\fR \fIalt-f shift-right\fR
+ \fBignore\fR
+ \fBjump\fR (EasyMotion-like 2-keystroke movement)
+ \fBjump-accept\fR (jump and accept)
+ \fBkill-line\fR
+ \fBkill-word\fR \fIalt-d\fR
+ \fBlast\fR (move to the last match)
+ \fBnext-history\fR (\fIctrl-n\fR on \fB--history\fR)
+ \fBpage-down\fR \fIpgdn\fR
+ \fBpage-up\fR \fIpgup\fR
+ \fBhalf-page-down\fR
+ \fBhalf-page-up\fR
+ \fBpreview(...)\fR (see below for the details)
+ \fBpreview-down\fR \fIshift-down\fR
+ \fBpreview-up\fR \fIshift-up\fR
+ \fBpreview-page-down\fR
+ \fBpreview-page-up\fR
+ \fBpreview-half-page-down\fR
+ \fBpreview-half-page-up\fR
+ \fBpreview-bottom\fR
+ \fBpreview-top\fR
+ \fBprevious-history\fR (\fIctrl-p\fR on \fB--history\fR)
+ \fBprint-query\fR (print query and exit)
+ \fBput\fR (put the character to the prompt)
+ \fBrefresh-preview\fR
+ \fBrebind(...)\fR (rebind bindings after \fBunbind\fR)
+ \fBreload(...)\fR (see below for the details)
+ \fBreplace-query\fR (replace query string with the current selection)
+ \fBselect\fR
+ \fBselect-all\fR (select all matches)
+ \fBtoggle\fR (\fIright-click\fR)
+ \fBtoggle-all\fR (toggle all matches)
+ \fBtoggle+down\fR \fIctrl-i (tab)\fR
+ \fBtoggle-in\fR (\fB--layout=reverse*\fR ? \fBtoggle+up\fR : \fBtoggle+down\fR)
+ \fBtoggle-out\fR (\fB--layout=reverse*\fR ? \fBtoggle+down\fR : \fBtoggle+up\fR)
+ \fBtoggle-preview\fR
+ \fBtoggle-preview-wrap\fR
+ \fBtoggle-search\fR (toggle search functionality)
+ \fBtoggle-sort\fR
+ \fBtoggle+up\fR \fIbtab (shift-tab)\fR
+ \fBunbind(...)\fR (unbind bindings)
+ \fBunix-line-discard\fR \fIctrl-u\fR
+ \fBunix-word-rubout\fR \fIctrl-w\fR
+ \fBup\fR \fIctrl-k ctrl-p up\fR
+ \fByank\fR \fIctrl-y\fR
+
+.SS ACTION COMPOSITION
+
+Multiple actions can be chained using \fB+\fR separator.
+
+e.g.
+ \fBfzf --multi --bind 'ctrl-a:select-all+accept'\fR
+ \fBfzf --multi --bind 'ctrl-a:select-all' --bind 'ctrl-a:+accept'\fR
+
+.SS ACTION ARGUMENT
+
+An action denoted with \fB(...)\fR suffix takes an argument.
+
+e.g.
+ \fBfzf --bind 'ctrl-a:change-prompt(NewPrompt> )'\fR
+ \fBfzf --bind 'ctrl-v:preview(cat {})' --preview-window hidden\fR
+
+If the argument contains parentheses, fzf may fail to parse the expression. In
+that case, you can use any of the following alternative notations to avoid
+parse errors.
+
+ \fBaction-name[...]\fR
+ \fBaction-name~...~\fR
+ \fBaction-name!...!\fR
+ \fBaction-name@...@\fR
+ \fBaction-name#...#\fR
+ \fBaction-name$...$\fR
+ \fBaction-name%...%\fR
+ \fBaction-name^...^\fR
+ \fBaction-name&...&\fR
+ \fBaction-name*...*\fR
+ \fBaction-name;...;\fR
+ \fBaction-name/.../\fR
+ \fBaction-name|...|\fR
+ \fBaction-name:...\fR
+.RS
+The last one is the special form that frees you from parse errors as it does
+not expect the closing character. The catch is that it should be the last one
+in the comma-separated list of key-action pairs.
+.RE
+
+.SS COMMAND EXECUTION
+
+With \fBexecute(...)\fR action, you can execute arbitrary commands without
+leaving fzf. For example, you can turn fzf into a simple file browser by
+binding \fBenter\fR key to \fBless\fR command like follows.
+
+ \fBfzf --bind "enter:execute(less {})"\fR
+
+You can use the same placeholder expressions as in \fB--preview\fR.
+
+fzf switches to the alternate screen when executing a command. However, if the
+command is expected to complete quickly, and you are not interested in its
+output, you might want to use \fBexecute-silent\fR instead, which silently
+executes the command without the switching. Note that fzf will not be
+responsive until the command is complete. For asynchronous execution, start
+your command as a background process (i.e. appending \fB&\fR).
+
+On *nix systems, fzf runs the command with \fB$SHELL -c\fR if \fBSHELL\fR is
+set, otherwise with \fBsh -c\fR, so in this case make sure that the command is
+POSIX-compliant.
+
+.SS RELOAD INPUT
+
+\fBreload(...)\fR action is used to dynamically update the input list
+without restarting fzf. It takes the same command template with placeholder
+expressions as \fBexecute(...)\fR.
+
+See \fIhttps://github.com/junegunn/fzf/issues/1750\fR for more info.
+
+e.g.
+ \fB# Update the list of processes by pressing CTRL-R
+ ps -ef | fzf --bind 'ctrl-r:reload(ps -ef)' --header 'Press CTRL-R to reload' \\
+ --header-lines=1 --layout=reverse
+
+ # Integration with ripgrep
+ RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
+ INITIAL_QUERY="foobar"
+ FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY'" \\
+ fzf --bind "change:reload:$RG_PREFIX {q} || true" \\
+ --ansi --disabled --query "$INITIAL_QUERY"\fR
+
+.SS PREVIEW BINDING
+
+With \fBpreview(...)\fR action, you can specify multiple different preview
+commands in addition to the default preview command given by \fB--preview\fR
+option.
+
+e.g.
+ # Default preview command with an extra preview binding
+ fzf --preview 'file {}' --bind '?:preview:cat {}'
+
+ # A preview binding with no default preview command
+ # (Preview window is initially empty)
+ fzf --bind '?:preview:cat {}'
+
+ # Preview window hidden by default, it appears when you first hit '?'
+ fzf --bind '?:preview:cat {}' --preview-window hidden
+
+.SS CHANGE PREVIEW WINDOW ATTRIBUTES
+
+\fBchange-preview-window\fR action can be used to change the properties of the
+preview window. Unlike the \fB--preview-window\fR option, you can specify
+multiple sets of options separated by '|' characters.
+
+e.g.
+ # Rotate through the options using CTRL-/
+ fzf --preview 'cat {}' --bind 'ctrl-/:change-preview-window(right,70%|down,40%,border-horizontal|hidden|right)'
+
+ # The default properties given by `--preview-window` are inherited, so an empty string in the list is interpreted as the default
+ fzf --preview 'cat {}' --preview-window 'right,40%,border-left' --bind 'ctrl-/:change-preview-window(70%|down,border-top|hidden|)'
+
+ # This is equivalent to toggle-preview action
+ fzf --preview 'cat {}' --bind 'ctrl-/:change-preview-window(hidden|)'
+
+.SH AUTHOR
+Junegunn Choi (\fIjunegunn.c@gmail.com\fR)
+
+.SH SEE ALSO
+.B Project homepage:
+.RS
+.I https://github.com/junegunn/fzf
+.RE
+.br
+
+.br
+.B Extra Vim plugin:
+.RS
+.I https://github.com/junegunn/fzf.vim
+.RE
+
+.SH LICENSE
+MIT
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/plugin/fzf.vim b/dot-oh-my-zsh/custom/plugins/fzf/plugin/fzf.vim
new file mode 100644
index 00000000..4dd7ece8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/plugin/fzf.vim
@@ -0,0 +1,1060 @@
+" Copyright (c) 2017 Junegunn Choi
+"
+" MIT License
+"
+" Permission is hereby granted, free of charge, to any person obtaining
+" a copy of this software and associated documentation files (the
+" "Software"), to deal in the Software without restriction, including
+" without limitation the rights to use, copy, modify, merge, publish,
+" distribute, sublicense, and/or sell copies of the Software, and to
+" permit persons to whom the Software is furnished to do so, subject to
+" the following conditions:
+"
+" The above copyright notice and this permission notice shall be
+" included in all copies or substantial portions of the Software.
+"
+" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+if exists('g:loaded_fzf')
+ finish
+endif
+let g:loaded_fzf = 1
+
+let s:is_win = has('win32') || has('win64')
+if s:is_win && &shellslash
+ set noshellslash
+ let s:base_dir = expand('<sfile>:h:h')
+ set shellslash
+else
+ let s:base_dir = expand('<sfile>:h:h')
+endif
+if s:is_win
+ let s:term_marker = '&::FZF'
+
+ function! s:fzf_call(fn, ...)
+ let shellslash = &shellslash
+ try
+ set noshellslash
+ return call(a:fn, a:000)
+ finally
+ let &shellslash = shellslash
+ endtry
+ endfunction
+
+ " Use utf-8 for fzf.vim commands
+ " Return array of shell commands for cmd.exe
+ function! s:enc_to_cp(str)
+ if !has('iconv')
+ return a:str
+ endif
+ if !exists('s:codepage')
+ let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0)
+ endif
+ return iconv(a:str, &encoding, 'cp'.s:codepage)
+ endfunction
+ function! s:wrap_cmds(cmds)
+ return map([
+ \ '@echo off',
+ \ 'setlocal enabledelayedexpansion']
+ \ + (has('gui_running') ? ['set TERM= > nul'] : [])
+ \ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds])
+ \ + ['endlocal'],
+ \ '<SID>enc_to_cp(v:val."\r")')
+ endfunction
+else
+ let s:term_marker = ";#FZF"
+
+ function! s:fzf_call(fn, ...)
+ return call(a:fn, a:000)
+ endfunction
+
+ function! s:wrap_cmds(cmds)
+ return a:cmds
+ endfunction
+
+ function! s:enc_to_cp(str)
+ return a:str
+ endfunction
+endif
+
+function! s:shellesc_cmd(arg)
+ let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g')
+ let escaped = substitute(escaped, '%', '%%', 'g')
+ let escaped = substitute(escaped, '"', '\\^&', 'g')
+ let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g')
+ return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"'
+endfunction
+
+function! fzf#shellescape(arg, ...)
+ let shell = get(a:000, 0, s:is_win ? 'cmd.exe' : 'sh')
+ if shell =~# 'cmd.exe$'
+ return s:shellesc_cmd(a:arg)
+ endif
+ try
+ let [shell, &shell] = [&shell, shell]
+ return s:fzf_call('shellescape', a:arg)
+ finally
+ let [shell, &shell] = [&shell, shell]
+ endtry
+endfunction
+
+function! s:fzf_getcwd()
+ return s:fzf_call('getcwd')
+endfunction
+
+function! s:fzf_fnamemodify(fname, mods)
+ return s:fzf_call('fnamemodify', a:fname, a:mods)
+endfunction
+
+function! s:fzf_expand(fmt)
+ return s:fzf_call('expand', a:fmt, 1)
+endfunction
+
+function! s:fzf_tempname()
+ return s:fzf_call('tempname')
+endfunction
+
+let s:layout_keys = ['window', 'tmux', 'up', 'down', 'left', 'right']
+let s:fzf_go = s:base_dir.'/bin/fzf'
+let s:fzf_tmux = s:base_dir.'/bin/fzf-tmux'
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+function! s:popup_support()
+ return has('nvim') ? has('nvim-0.4') : has('popupwin') && has('patch-8.2.191')
+endfunction
+
+function! s:default_layout()
+ return s:popup_support()
+ \ ? { 'window' : { 'width': 0.9, 'height': 0.6 } }
+ \ : { 'down': '~40%' }
+endfunction
+
+function! fzf#install()
+ if s:is_win && !has('win32unix')
+ let script = s:base_dir.'/install.ps1'
+ if !filereadable(script)
+ throw script.' not found'
+ endif
+ let script = 'powershell -ExecutionPolicy Bypass -file ' . script
+ else
+ let script = s:base_dir.'/install'
+ if !executable(script)
+ throw script.' not found'
+ endif
+ let script .= ' --bin'
+ endif
+
+ call s:warn('Running fzf installer ...')
+ call system(script)
+ if v:shell_error
+ throw 'Failed to download fzf: '.script
+ endif
+endfunction
+
+let s:versions = {}
+function s:get_version(bin)
+ if has_key(s:versions, a:bin)
+ return s:versions[a:bin]
+ end
+ let command = (&shell =~ 'powershell' ? '&' : '') . shellescape(a:bin) . ' --version --no-height'
+ let output = systemlist(command)
+ if v:shell_error || empty(output)
+ return ''
+ endif
+ let ver = matchstr(output[-1], '[0-9.]\+')
+ let s:versions[a:bin] = ver
+ return ver
+endfunction
+
+function! s:compare_versions(a, b)
+ let a = split(a:a, '\.')
+ let b = split(a:b, '\.')
+ for idx in range(0, max([len(a), len(b)]) - 1)
+ let v1 = str2nr(get(a, idx, 0))
+ let v2 = str2nr(get(b, idx, 0))
+ if v1 < v2 | return -1
+ elseif v1 > v2 | return 1
+ endif
+ endfor
+ return 0
+endfunction
+
+function! s:compare_binary_versions(a, b)
+ return s:compare_versions(s:get_version(a:a), s:get_version(a:b))
+endfunction
+
+let s:checked = {}
+function! fzf#exec(...)
+ if !exists('s:exec')
+ let binaries = []
+ if executable('fzf')
+ call add(binaries, 'fzf')
+ endif
+ if executable(s:fzf_go)
+ call add(binaries, s:fzf_go)
+ endif
+
+ if empty(binaries)
+ if input('fzf executable not found. Download binary? (y/n) ') =~? '^y'
+ redraw
+ call fzf#install()
+ return fzf#exec()
+ else
+ redraw
+ throw 'fzf executable not found'
+ endif
+ elseif len(binaries) > 1
+ call sort(binaries, 's:compare_binary_versions')
+ endif
+
+ let s:exec = binaries[-1]
+ endif
+
+ if a:0 && !has_key(s:checked, a:1)
+ let fzf_version = s:get_version(s:exec)
+ if empty(fzf_version)
+ let message = printf('Failed to run "%s --version"', s:exec)
+ unlet s:exec
+ throw message
+ end
+
+ if s:compare_versions(fzf_version, a:1) >= 0
+ let s:checked[a:1] = 1
+ return s:exec
+ elseif a:0 < 2 && input(printf('You need fzf %s or above. Found: %s. Download binary? (y/n) ', a:1, fzf_version)) =~? '^y'
+ let s:versions = {}
+ unlet s:exec
+ redraw
+ call fzf#install()
+ return fzf#exec(a:1, 1)
+ else
+ throw printf('You need to upgrade fzf (required: %s or above)', a:1)
+ endif
+ endif
+
+ return s:exec
+endfunction
+
+function! s:tmux_enabled()
+ if has('gui_running') || !exists('$TMUX')
+ return 0
+ endif
+
+ if exists('s:tmux')
+ return s:tmux
+ endif
+
+ let s:tmux = 0
+ if !executable(s:fzf_tmux)
+ if executable('fzf-tmux')
+ let s:fzf_tmux = 'fzf-tmux'
+ else
+ return 0
+ endif
+ endif
+
+ let output = system('tmux -V')
+ let s:tmux = !v:shell_error && output >= 'tmux 1.7'
+ return s:tmux
+endfunction
+
+function! s:escape(path)
+ let path = fnameescape(a:path)
+ return s:is_win ? escape(path, '$') : path
+endfunction
+
+function! s:error(msg)
+ echohl ErrorMsg
+ echom a:msg
+ echohl None
+endfunction
+
+function! s:warn(msg)
+ echohl WarningMsg
+ echom a:msg
+ echohl None
+endfunction
+
+function! s:has_any(dict, keys)
+ for key in a:keys
+ if has_key(a:dict, key)
+ return 1
+ endif
+ endfor
+ return 0
+endfunction
+
+function! s:open(cmd, target)
+ if stridx('edit', a:cmd) == 0 && s:fzf_fnamemodify(a:target, ':p') ==# s:fzf_expand('%:p')
+ return
+ endif
+ execute a:cmd s:escape(a:target)
+endfunction
+
+function! s:common_sink(action, lines) abort
+ if len(a:lines) < 2
+ return
+ endif
+ let key = remove(a:lines, 0)
+ let Cmd = get(a:action, key, 'e')
+ if type(Cmd) == type(function('call'))
+ return Cmd(a:lines)
+ endif
+ if len(a:lines) > 1
+ augroup fzf_swap
+ autocmd SwapExists * let v:swapchoice='o'
+ \| call s:warn('fzf: E325: swap file exists: '.s:fzf_expand('<afile>'))
+ augroup END
+ endif
+ try
+ let empty = empty(s:fzf_expand('%')) && line('$') == 1 && empty(getline(1)) && !&modified
+ " Preserve the current working directory in case it's changed during
+ " the execution (e.g. `set autochdir` or `autocmd BufEnter * lcd ...`)
+ let cwd = exists('w:fzf_pushd') ? w:fzf_pushd.dir : expand('%:p:h')
+ for item in a:lines
+ if item[0] != '~' && item !~ (s:is_win ? '^[A-Z]:\' : '^/')
+ let sep = s:is_win ? '\' : '/'
+ let item = join([cwd, item], cwd[len(cwd)-1] == sep ? '' : sep)
+ endif
+ if empty
+ execute 'e' s:escape(item)
+ let empty = 0
+ else
+ call s:open(Cmd, item)
+ endif
+ if !has('patch-8.0.0177') && !has('nvim-0.2') && exists('#BufEnter')
+ \ && isdirectory(item)
+ doautocmd BufEnter
+ endif
+ endfor
+ catch /^Vim:Interrupt$/
+ finally
+ silent! autocmd! fzf_swap
+ endtry
+endfunction
+
+function! s:get_color(attr, ...)
+ " Force 24 bit colors: g:fzf_force_termguicolors (temporary workaround for https://github.com/junegunn/fzf.vim/issues/1152)
+ let gui = get(g:, 'fzf_force_termguicolors', 0) || (!s:is_win && !has('win32unix') && has('termguicolors') && &termguicolors)
+ let fam = gui ? 'gui' : 'cterm'
+ let pat = gui ? '^#[a-f0-9]\+' : '^[0-9]\+$'
+ for group in a:000
+ let code = synIDattr(synIDtrans(hlID(group)), a:attr, fam)
+ if code =~? pat
+ return code
+ endif
+ endfor
+ return ''
+endfunction
+
+function! s:defaults()
+ let rules = copy(get(g:, 'fzf_colors', {}))
+ let colors = join(map(items(filter(map(rules, 'call("s:get_color", v:val)'), '!empty(v:val)')), 'join(v:val, ":")'), ',')
+ return empty(colors) ? '' : fzf#shellescape('--color='.colors)
+endfunction
+
+function! s:validate_layout(layout)
+ for key in keys(a:layout)
+ if index(s:layout_keys, key) < 0
+ throw printf('Invalid entry in g:fzf_layout: %s (allowed: %s)%s',
+ \ key, join(s:layout_keys, ', '), key == 'options' ? '. Use $FZF_DEFAULT_OPTS.' : '')
+ endif
+ endfor
+ return a:layout
+endfunction
+
+function! s:evaluate_opts(options)
+ return type(a:options) == type([]) ?
+ \ join(map(copy(a:options), 'fzf#shellescape(v:val)')) : a:options
+endfunction
+
+" [name string,] [opts dict,] [fullscreen boolean]
+function! fzf#wrap(...)
+ let args = ['', {}, 0]
+ let expects = map(copy(args), 'type(v:val)')
+ let tidx = 0
+ for arg in copy(a:000)
+ let tidx = index(expects, type(arg) == 6 ? type(0) : type(arg), tidx)
+ if tidx < 0
+ throw 'Invalid arguments (expected: [name string] [opts dict] [fullscreen boolean])'
+ endif
+ let args[tidx] = arg
+ let tidx += 1
+ unlet arg
+ endfor
+ let [name, opts, bang] = args
+
+ if len(name)
+ let opts.name = name
+ end
+
+ " Layout: g:fzf_layout (and deprecated g:fzf_height)
+ if bang
+ for key in s:layout_keys
+ if has_key(opts, key)
+ call remove(opts, key)
+ endif
+ endfor
+ elseif !s:has_any(opts, s:layout_keys)
+ if !exists('g:fzf_layout') && exists('g:fzf_height')
+ let opts.down = g:fzf_height
+ else
+ let opts = extend(opts, s:validate_layout(get(g:, 'fzf_layout', s:default_layout())))
+ endif
+ endif
+
+ " Colors: g:fzf_colors
+ let opts.options = s:defaults() .' '. s:evaluate_opts(get(opts, 'options', ''))
+
+ " History: g:fzf_history_dir
+ if len(name) && len(get(g:, 'fzf_history_dir', ''))
+ let dir = s:fzf_expand(g:fzf_history_dir)
+ if !isdirectory(dir)
+ call mkdir(dir, 'p')
+ endif
+ let history = fzf#shellescape(dir.'/'.name)
+ let opts.options = join(['--history', history, opts.options])
+ endif
+
+ " Action: g:fzf_action
+ if !s:has_any(opts, ['sink', 'sinklist', 'sink*'])
+ let opts._action = get(g:, 'fzf_action', s:default_action)
+ let opts.options .= ' --expect='.join(keys(opts._action), ',')
+ function! opts.sinklist(lines) abort
+ return s:common_sink(self._action, a:lines)
+ endfunction
+ let opts['sink*'] = opts.sinklist " For backward compatibility
+ endif
+
+ return opts
+endfunction
+
+function! s:use_sh()
+ let [shell, shellslash, shellcmdflag, shellxquote] = [&shell, &shellslash, &shellcmdflag, &shellxquote]
+ if s:is_win
+ set shell=cmd.exe
+ set noshellslash
+ let &shellcmdflag = has('nvim') ? '/s /c' : '/c'
+ let &shellxquote = has('nvim') ? '"' : '('
+ else
+ set shell=sh
+ endif
+ return [shell, shellslash, shellcmdflag, shellxquote]
+endfunction
+
+function! s:writefile(...)
+ if call('writefile', a:000) == -1
+ throw 'Failed to write temporary file. Check if you can write to the path tempname() returns.'
+ endif
+endfunction
+
+function! fzf#run(...) abort
+try
+ let [shell, shellslash, shellcmdflag, shellxquote] = s:use_sh()
+
+ let dict = exists('a:1') ? copy(a:1) : {}
+ let temps = { 'result': s:fzf_tempname() }
+ let optstr = s:evaluate_opts(get(dict, 'options', ''))
+ try
+ let fzf_exec = fzf#shellescape(fzf#exec())
+ catch
+ throw v:exception
+ endtry
+
+ if !s:present(dict, 'dir')
+ let dict.dir = s:fzf_getcwd()
+ endif
+ if has('win32unix') && s:present(dict, 'dir')
+ let dict.dir = fnamemodify(dict.dir, ':p')
+ endif
+
+ if has_key(dict, 'source')
+ let source = remove(dict, 'source')
+ let type = type(source)
+ if type == 1
+ let source_command = source
+ elseif type == 3
+ let temps.input = s:fzf_tempname()
+ call s:writefile(source, temps.input)
+ let source_command = (s:is_win ? 'type ' : 'cat ').fzf#shellescape(temps.input)
+ else
+ throw 'Invalid source type'
+ endif
+ else
+ let source_command = ''
+ endif
+
+ let prefer_tmux = get(g:, 'fzf_prefer_tmux', 0) || has_key(dict, 'tmux')
+ let use_height = has_key(dict, 'down') && !has('gui_running') &&
+ \ !(has('nvim') || s:is_win || has('win32unix') || s:present(dict, 'up', 'left', 'right', 'window')) &&
+ \ executable('tput') && filereadable('/dev/tty')
+ let has_vim8_term = has('terminal') && has('patch-8.0.995')
+ let has_nvim_term = has('nvim-0.2.1') || has('nvim') && !s:is_win
+ let use_term = has_nvim_term ||
+ \ has_vim8_term && !has('win32unix') && (has('gui_running') || s:is_win || s:present(dict, 'down', 'up', 'left', 'right', 'window'))
+ let use_tmux = (has_key(dict, 'tmux') || (!use_height && !use_term || prefer_tmux) && !has('win32unix') && s:splittable(dict)) && s:tmux_enabled()
+ if prefer_tmux && use_tmux
+ let use_height = 0
+ let use_term = 0
+ endif
+ if use_term
+ let optstr .= ' --no-height'
+ elseif use_height
+ let height = s:calc_size(&lines, dict.down, dict)
+ let optstr .= ' --height='.height
+ endif
+ let optstr .= s:border_opt(get(dict, 'window', 0))
+ let prev_default_command = $FZF_DEFAULT_COMMAND
+ if len(source_command)
+ let $FZF_DEFAULT_COMMAND = source_command
+ endif
+ let command = (use_tmux ? s:fzf_tmux(dict) : fzf_exec).' '.optstr.' > '.temps.result
+
+ if use_term
+ return s:execute_term(dict, command, temps)
+ endif
+
+ let lines = use_tmux ? s:execute_tmux(dict, command, temps)
+ \ : s:execute(dict, command, use_height, temps)
+ call s:callback(dict, lines)
+ return lines
+finally
+ if exists('source_command') && len(source_command)
+ if len(prev_default_command)
+ let $FZF_DEFAULT_COMMAND = prev_default_command
+ else
+ let $FZF_DEFAULT_COMMAND = ''
+ silent! execute 'unlet $FZF_DEFAULT_COMMAND'
+ endif
+ endif
+ let [&shell, &shellslash, &shellcmdflag, &shellxquote] = [shell, shellslash, shellcmdflag, shellxquote]
+endtry
+endfunction
+
+function! s:present(dict, ...)
+ for key in a:000
+ if !empty(get(a:dict, key, ''))
+ return 1
+ endif
+ endfor
+ return 0
+endfunction
+
+function! s:fzf_tmux(dict)
+ let size = get(a:dict, 'tmux', '')
+ if empty(size)
+ for o in ['up', 'down', 'left', 'right']
+ if s:present(a:dict, o)
+ let spec = a:dict[o]
+ if (o == 'up' || o == 'down') && spec[0] == '~'
+ let size = '-'.o[0].s:calc_size(&lines, spec, a:dict)
+ else
+ " Legacy boolean option
+ let size = '-'.o[0].(spec == 1 ? '' : substitute(spec, '^\~', '', ''))
+ endif
+ break
+ endif
+ endfor
+ endif
+ return printf('LINES=%d COLUMNS=%d %s %s - --',
+ \ &lines, &columns, fzf#shellescape(s:fzf_tmux), size)
+endfunction
+
+function! s:splittable(dict)
+ return s:present(a:dict, 'up', 'down') && &lines > 15 ||
+ \ s:present(a:dict, 'left', 'right') && &columns > 40
+endfunction
+
+function! s:pushd(dict)
+ if s:present(a:dict, 'dir')
+ let cwd = s:fzf_getcwd()
+ let w:fzf_pushd = {
+ \ 'command': haslocaldir() ? 'lcd' : (exists(':tcd') && haslocaldir(-1) ? 'tcd' : 'cd'),
+ \ 'origin': cwd,
+ \ 'bufname': bufname('')
+ \ }
+ execute 'lcd' s:escape(a:dict.dir)
+ let cwd = s:fzf_getcwd()
+ let w:fzf_pushd.dir = cwd
+ let a:dict.pushd = w:fzf_pushd
+ return cwd
+ endif
+ return ''
+endfunction
+
+augroup fzf_popd
+ autocmd!
+ autocmd WinEnter * call s:dopopd()
+augroup END
+
+function! s:dopopd()
+ if !exists('w:fzf_pushd')
+ return
+ endif
+
+ " FIXME: We temporarily change the working directory to 'dir' entry
+ " of options dictionary (set to the current working directory if not given)
+ " before running fzf.
+ "
+ " e.g. call fzf#run({'dir': '/tmp', 'source': 'ls', 'sink': 'e'})
+ "
+ " After processing the sink function, we have to restore the current working
+ " directory. But doing so may not be desirable if the function changed the
+ " working directory on purpose.
+ "
+ " So how can we tell if we should do it or not? A simple heuristic we use
+ " here is that we change directory only if the current working directory
+ " matches 'dir' entry. However, it is possible that the sink function did
+ " change the directory to 'dir'. In that case, the user will have an
+ " unexpected result.
+ if s:fzf_getcwd() ==# w:fzf_pushd.dir && (!&autochdir || w:fzf_pushd.bufname ==# bufname(''))
+ execute w:fzf_pushd.command s:escape(w:fzf_pushd.origin)
+ endif
+ unlet! w:fzf_pushd
+endfunction
+
+function! s:xterm_launcher()
+ let fmt = 'xterm -T "[fzf]" -bg "%s" -fg "%s" -geometry %dx%d+%d+%d -e bash -ic %%s'
+ if has('gui_macvim')
+ let fmt .= '&& osascript -e "tell application \"MacVim\" to activate"'
+ endif
+ return printf(fmt,
+ \ escape(synIDattr(hlID("Normal"), "bg"), '#'), escape(synIDattr(hlID("Normal"), "fg"), '#'),
+ \ &columns, &lines/2, getwinposx(), getwinposy())
+endfunction
+unlet! s:launcher
+if s:is_win || has('win32unix')
+ let s:launcher = '%s'
+else
+ let s:launcher = function('s:xterm_launcher')
+endif
+
+function! s:exit_handler(code, command, ...)
+ if a:code == 130
+ return 0
+ elseif has('nvim') && a:code == 129
+ " When deleting the terminal buffer while fzf is still running,
+ " Nvim sends SIGHUP.
+ return 0
+ elseif a:code > 1
+ call s:error('Error running ' . a:command)
+ if !empty(a:000)
+ sleep
+ endif
+ return 0
+ endif
+ return 1
+endfunction
+
+function! s:execute(dict, command, use_height, temps) abort
+ call s:pushd(a:dict)
+ if has('unix') && !a:use_height
+ silent! !clear 2> /dev/null
+ endif
+ let escaped = (a:use_height || s:is_win) ? a:command : escape(substitute(a:command, '\n', '\\n', 'g'), '%#!')
+ if has('gui_running')
+ let Launcher = get(a:dict, 'launcher', get(g:, 'Fzf_launcher', get(g:, 'fzf_launcher', s:launcher)))
+ let fmt = type(Launcher) == 2 ? call(Launcher, []) : Launcher
+ if has('unix')
+ let escaped = "'".substitute(escaped, "'", "'\"'\"'", 'g')."'"
+ endif
+ let command = printf(fmt, escaped)
+ else
+ let command = escaped
+ endif
+ if s:is_win
+ let batchfile = s:fzf_tempname().'.bat'
+ call s:writefile(s:wrap_cmds(command), batchfile)
+ let command = batchfile
+ let a:temps.batchfile = batchfile
+ if has('nvim')
+ let fzf = {}
+ let fzf.dict = a:dict
+ let fzf.temps = a:temps
+ function! fzf.on_exit(job_id, exit_status, event) dict
+ call s:pushd(self.dict)
+ let lines = s:collect(self.temps)
+ call s:callback(self.dict, lines)
+ endfunction
+ let cmd = 'start /wait cmd /c '.command
+ call jobstart(cmd, fzf)
+ return []
+ endif
+ elseif has('win32unix') && $TERM !=# 'cygwin'
+ let shellscript = s:fzf_tempname()
+ call s:writefile([command], shellscript)
+ let command = 'cmd.exe /C '.fzf#shellescape('set "TERM=" & start /WAIT sh -c '.shellscript)
+ let a:temps.shellscript = shellscript
+ endif
+ if a:use_height
+ call system(printf('tput cup %d > /dev/tty; tput cnorm > /dev/tty; %s < /dev/tty 2> /dev/tty', &lines, command))
+ else
+ execute 'silent !'.command
+ endif
+ let exit_status = v:shell_error
+ redraw!
+ let lines = s:collect(a:temps)
+ return s:exit_handler(exit_status, command) ? lines : []
+endfunction
+
+function! s:execute_tmux(dict, command, temps) abort
+ let command = a:command
+ let cwd = s:pushd(a:dict)
+ if len(cwd)
+ " -c '#{pane_current_path}' is only available on tmux 1.9 or above
+ let command = join(['cd', fzf#shellescape(cwd), '&&', command])
+ endif
+
+ call system(command)
+ let exit_status = v:shell_error
+ redraw!
+ let lines = s:collect(a:temps)
+ return s:exit_handler(exit_status, command) ? lines : []
+endfunction
+
+function! s:calc_size(max, val, dict)
+ let val = substitute(a:val, '^\~', '', '')
+ if val =~ '%$'
+ let size = a:max * str2nr(val[:-2]) / 100
+ else
+ let size = min([a:max, str2nr(val)])
+ endif
+
+ let srcsz = -1
+ if type(get(a:dict, 'source', 0)) == type([])
+ let srcsz = len(a:dict.source)
+ endif
+
+ let opts = $FZF_DEFAULT_OPTS.' '.s:evaluate_opts(get(a:dict, 'options', ''))
+ if opts =~ 'preview'
+ return size
+ endif
+ let margin = match(opts, '--inline-info\|--info[^-]\{-}inline') > match(opts, '--no-inline-info\|--info[^-]\{-}\(default\|hidden\)') ? 1 : 2
+ let margin += stridx(opts, '--border') > stridx(opts, '--no-border') ? 2 : 0
+ if stridx(opts, '--header') > stridx(opts, '--no-header')
+ let margin += len(split(opts, "\n"))
+ endif
+ return srcsz >= 0 ? min([srcsz + margin, size]) : size
+endfunction
+
+function! s:getpos()
+ return {'tab': tabpagenr(), 'win': winnr(), 'winid': win_getid(), 'cnt': winnr('$'), 'tcnt': tabpagenr('$')}
+endfunction
+
+function! s:border_opt(window)
+ if type(a:window) != type({})
+ return ''
+ endif
+
+ " Border style
+ let style = tolower(get(a:window, 'border', 'rounded'))
+ if !has_key(a:window, 'border') && !get(a:window, 'rounded', 1)
+ let style = 'sharp'
+ endif
+ if style == 'none' || style == 'no'
+ return ''
+ endif
+
+ " For --border styles, we need fzf 0.24.0 or above
+ call fzf#exec('0.24.0')
+ let opt = ' --border=' . style
+ if has_key(a:window, 'highlight')
+ let color = s:get_color('fg', a:window.highlight)
+ if len(color)
+ let opt .= ' --color=border:' . color
+ endif
+ endif
+ return opt
+endfunction
+
+function! s:split(dict)
+ let directions = {
+ \ 'up': ['topleft', 'resize', &lines],
+ \ 'down': ['botright', 'resize', &lines],
+ \ 'left': ['vertical topleft', 'vertical resize', &columns],
+ \ 'right': ['vertical botright', 'vertical resize', &columns] }
+ let ppos = s:getpos()
+ let is_popup = 0
+ try
+ if s:present(a:dict, 'window')
+ if type(a:dict.window) == type({})
+ if !s:popup_support()
+ throw 'Nvim 0.4+ or Vim 8.2.191+ with popupwin feature is required for pop-up window'
+ end
+ call s:popup(a:dict.window)
+ let is_popup = 1
+ else
+ execute 'keepalt' a:dict.window
+ endif
+ elseif !s:splittable(a:dict)
+ execute (tabpagenr()-1).'tabnew'
+ else
+ for [dir, triple] in items(directions)
+ let val = get(a:dict, dir, '')
+ if !empty(val)
+ let [cmd, resz, max] = triple
+ if (dir == 'up' || dir == 'down') && val[0] == '~'
+ let sz = s:calc_size(max, val, a:dict)
+ else
+ let sz = s:calc_size(max, val, {})
+ endif
+ execute cmd sz.'new'
+ execute resz sz
+ return [ppos, {}, is_popup]
+ endif
+ endfor
+ endif
+ return [ppos, is_popup ? {} : { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }, is_popup]
+ finally
+ if !is_popup
+ setlocal winfixwidth winfixheight
+ endif
+ endtry
+endfunction
+
+nnoremap <silent> <Plug>(fzf-insert) i
+nnoremap <silent> <Plug>(fzf-normal) <Nop>
+if exists(':tnoremap')
+ tnoremap <silent> <Plug>(fzf-insert) <C-\><C-n>i
+ tnoremap <silent> <Plug>(fzf-normal) <C-\><C-n>
+endif
+
+function! s:execute_term(dict, command, temps) abort
+ let winrest = winrestcmd()
+ let pbuf = bufnr('')
+ let [ppos, winopts, is_popup] = s:split(a:dict)
+ call s:use_sh()
+ let b:fzf = a:dict
+ let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,
+ \ 'winopts': winopts, 'winrest': winrest, 'lines': &lines,
+ \ 'columns': &columns, 'command': a:command }
+ function! fzf.switch_back(inplace)
+ if a:inplace && bufnr('') == self.buf
+ if bufexists(self.pbuf)
+ execute 'keepalt keepjumps b' self.pbuf
+ endif
+ " No other listed buffer
+ if bufnr('') == self.buf
+ enew
+ endif
+ endif
+ endfunction
+ function! fzf.on_exit(id, code, ...)
+ if s:getpos() == self.ppos " {'window': 'enew'}
+ for [opt, val] in items(self.winopts)
+ execute 'let' opt '=' val
+ endfor
+ call self.switch_back(1)
+ else
+ if bufnr('') == self.buf
+ " We use close instead of bd! since Vim does not close the split when
+ " there's no other listed buffer (nvim +'set nobuflisted')
+ close
+ endif
+ silent! execute 'tabnext' self.ppos.tab
+ silent! execute self.ppos.win.'wincmd w'
+ endif
+
+ if bufexists(self.buf)
+ execute 'bd!' self.buf
+ endif
+
+ if &lines == self.lines && &columns == self.columns && s:getpos() == self.ppos
+ execute self.winrest
+ endif
+
+ let lines = s:collect(self.temps)
+ if !s:exit_handler(a:code, self.command, 1)
+ return
+ endif
+
+ call s:pushd(self.dict)
+ call s:callback(self.dict, lines)
+ call self.switch_back(s:getpos() == self.ppos)
+
+ if &buftype == 'terminal'
+ call feedkeys(&filetype == 'fzf' ? "\<Plug>(fzf-insert)" : "\<Plug>(fzf-normal)")
+ endif
+ endfunction
+
+ try
+ call s:pushd(a:dict)
+ if s:is_win
+ let fzf.temps.batchfile = s:fzf_tempname().'.bat'
+ call s:writefile(s:wrap_cmds(a:command), fzf.temps.batchfile)
+ let command = fzf.temps.batchfile
+ else
+ let command = a:command
+ endif
+ let command .= s:term_marker
+ if has('nvim')
+ call termopen(command, fzf)
+ else
+ let term_opts = {'exit_cb': function(fzf.on_exit)}
+ if v:version >= 802
+ let term_opts.term_kill = 'term'
+ endif
+ if is_popup
+ let term_opts.hidden = 1
+ else
+ let term_opts.curwin = 1
+ endif
+ let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts)
+ if is_popup && exists('#TerminalWinOpen')
+ doautocmd <nomodeline> TerminalWinOpen
+ endif
+ if !has('patch-8.0.1261') && !s:is_win
+ call term_wait(fzf.buf, 20)
+ endif
+ endif
+ tnoremap <buffer> <c-z> <nop>
+ if exists('&termwinkey') && (empty(&termwinkey) || &termwinkey =~? '<c-w>')
+ tnoremap <buffer> <c-w> <c-w>.
+ endif
+ finally
+ call s:dopopd()
+ endtry
+ setlocal nospell bufhidden=wipe nobuflisted nonumber
+ setf fzf
+ startinsert
+ return []
+endfunction
+
+function! s:collect(temps) abort
+ try
+ return filereadable(a:temps.result) ? readfile(a:temps.result) : []
+ finally
+ for tf in values(a:temps)
+ silent! call delete(tf)
+ endfor
+ endtry
+endfunction
+
+function! s:callback(dict, lines) abort
+ let popd = has_key(a:dict, 'pushd')
+ if popd
+ let w:fzf_pushd = a:dict.pushd
+ endif
+
+ try
+ if has_key(a:dict, 'sink')
+ for line in a:lines
+ if type(a:dict.sink) == 2
+ call a:dict.sink(line)
+ else
+ execute a:dict.sink s:escape(line)
+ endif
+ endfor
+ endif
+ if has_key(a:dict, 'sink*')
+ call a:dict['sink*'](a:lines)
+ elseif has_key(a:dict, 'sinklist')
+ call a:dict['sinklist'](a:lines)
+ endif
+ catch
+ if stridx(v:exception, ':E325:') < 0
+ echoerr v:exception
+ endif
+ endtry
+
+ " We may have opened a new window or tab
+ if popd
+ let w:fzf_pushd = a:dict.pushd
+ call s:dopopd()
+ endif
+endfunction
+
+if has('nvim')
+ function s:create_popup(hl, opts) abort
+ let buf = nvim_create_buf(v:false, v:true)
+ let opts = extend({'relative': 'editor', 'style': 'minimal'}, a:opts)
+ let win = nvim_open_win(buf, v:true, opts)
+ call setwinvar(win, '&winhighlight', 'NormalFloat:'..a:hl)
+ call setwinvar(win, '&colorcolumn', '')
+ return buf
+ endfunction
+else
+ function! s:create_popup(hl, opts) abort
+ let s:popup_create = {buf -> popup_create(buf, #{
+ \ line: a:opts.row,
+ \ col: a:opts.col,
+ \ minwidth: a:opts.width,
+ \ maxwidth: a:opts.width,
+ \ minheight: a:opts.height,
+ \ maxheight: a:opts.height,
+ \ zindex: 1000,
+ \ })}
+ autocmd TerminalOpen * ++once call s:popup_create(str2nr(expand('<abuf>')))
+ endfunction
+endif
+
+function! s:popup(opts) abort
+ let xoffset = get(a:opts, 'xoffset', 0.5)
+ let yoffset = get(a:opts, 'yoffset', 0.5)
+ let relative = get(a:opts, 'relative', 0)
+
+ " Use current window size for positioning relatively positioned popups
+ let columns = relative ? winwidth(0) : &columns
+ let lines = relative ? winheight(0) : (&lines - has('nvim'))
+
+ " Size and position
+ let width = min([max([8, a:opts.width > 1 ? a:opts.width : float2nr(columns * a:opts.width)]), columns])
+ let height = min([max([4, a:opts.height > 1 ? a:opts.height : float2nr(lines * a:opts.height)]), lines])
+ let row = float2nr(yoffset * (lines - height)) + (relative ? win_screenpos(0)[0] - 1 : 0)
+ let col = float2nr(xoffset * (columns - width)) + (relative ? win_screenpos(0)[1] - 1 : 0)
+
+ " Managing the differences
+ let row = min([max([0, row]), &lines - has('nvim') - height])
+ let col = min([max([0, col]), &columns - width])
+ let row += !has('nvim')
+ let col += !has('nvim')
+
+ call s:create_popup('Normal', {
+ \ 'row': row, 'col': col, 'width': width, 'height': height
+ \ })
+endfunction
+
+let s:default_action = {
+ \ 'ctrl-t': 'tab split',
+ \ 'ctrl-x': 'split',
+ \ 'ctrl-v': 'vsplit' }
+
+function! s:shortpath()
+ let short = fnamemodify(getcwd(), ':~:.')
+ if !has('win32unix')
+ let short = pathshorten(short)
+ endif
+ let slash = (s:is_win && !&shellslash) ? '\' : '/'
+ return empty(short) ? '~'.slash : short . (short =~ escape(slash, '\').'$' ? '' : slash)
+endfunction
+
+function! s:cmd(bang, ...) abort
+ let args = copy(a:000)
+ let opts = { 'options': ['--multi'] }
+ if len(args) && isdirectory(expand(args[-1]))
+ let opts.dir = substitute(substitute(remove(args, -1), '\\\(["'']\)', '\1', 'g'), '[/\\]*$', '/', '')
+ if s:is_win && !&shellslash
+ let opts.dir = substitute(opts.dir, '/', '\\', 'g')
+ endif
+ let prompt = opts.dir
+ else
+ let prompt = s:shortpath()
+ endif
+ let prompt = strwidth(prompt) < &columns - 20 ? prompt : '> '
+ call extend(opts.options, ['--prompt', prompt])
+ call extend(opts.options, args)
+ call fzf#run(fzf#wrap('FZF', opts, a:bang))
+endfunction
+
+command! -nargs=* -complete=dir -bang FZF call s:cmd(<bang>0, <f-args>)
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/shell/completion.bash b/dot-oh-my-zsh/custom/plugins/fzf/shell/completion.bash
new file mode 100644
index 00000000..4b1e0dba
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/shell/completion.bash
@@ -0,0 +1,379 @@
+# ____ ____
+# / __/___ / __/
+# / /_/_ / / /_
+# / __/ / /_/ __/
+# /_/ /___/_/ completion.bash
+#
+# - $FZF_TMUX (default: 0)
+# - $FZF_TMUX_OPTS (default: empty)
+# - $FZF_COMPLETION_TRIGGER (default: '**')
+# - $FZF_COMPLETION_OPTS (default: empty)
+
+if [[ $- =~ i ]]; then
+
+# To use custom commands instead of find, override _fzf_compgen_{path,dir}
+if ! declare -f _fzf_compgen_path > /dev/null; then
+ _fzf_compgen_path() {
+ echo "$1"
+ command find -L "$1" \
+ -name .git -prune -o -name .hg -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
+ -a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
+ }
+fi
+
+if ! declare -f _fzf_compgen_dir > /dev/null; then
+ _fzf_compgen_dir() {
+ command find -L "$1" \
+ -name .git -prune -o -name .hg -prune -o -name .svn -prune -o -type d \
+ -a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
+ }
+fi
+
+###########################################################
+
+# To redraw line after fzf closes (printf '\e[5n')
+bind '"\e[0n": redraw-current-line' 2> /dev/null
+
+__fzf_comprun() {
+ if [[ "$(type -t _fzf_comprun 2>&1)" = function ]]; then
+ _fzf_comprun "$@"
+ elif [[ -n "$TMUX_PANE" ]] && { [[ "${FZF_TMUX:-0}" != 0 ]] || [[ -n "$FZF_TMUX_OPTS" ]]; }; then
+ shift
+ fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- "$@"
+ else
+ shift
+ fzf "$@"
+ fi
+}
+
+__fzf_orig_completion() {
+ local l comp f cmd
+ while read -r l; do
+ if [[ "$l" =~ ^(.*\ -F)\ *([^ ]*).*\ ([^ ]*)$ ]]; then
+ comp="${BASH_REMATCH[1]}"
+ f="${BASH_REMATCH[2]}"
+ cmd="${BASH_REMATCH[3]}"
+ [[ "$f" = _fzf_* ]] && continue
+ printf -v "_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}" "%s" "${comp} %s ${cmd} #${f}"
+ if [[ "$l" = *" -o nospace "* ]] && [[ ! "$__fzf_nospace_commands" = *" $cmd "* ]]; then
+ __fzf_nospace_commands="$__fzf_nospace_commands $cmd "
+ fi
+ fi
+ done
+}
+
+_fzf_opts_completion() {
+ local cur prev opts
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ opts="
+ -x --extended
+ -e --exact
+ --algo
+ -i +i
+ -n --nth
+ --with-nth
+ -d --delimiter
+ +s --no-sort
+ --tac
+ --tiebreak
+ -m --multi
+ --no-mouse
+ --bind
+ --cycle
+ --no-hscroll
+ --jump-labels
+ --height
+ --literal
+ --reverse
+ --margin
+ --inline-info
+ --prompt
+ --pointer
+ --marker
+ --header
+ --header-lines
+ --ansi
+ --tabstop
+ --color
+ --no-bold
+ --history
+ --history-size
+ --preview
+ --preview-window
+ -q --query
+ -1 --select-1
+ -0 --exit-0
+ -f --filter
+ --print-query
+ --expect
+ --sync"
+
+ case "${prev}" in
+ --tiebreak)
+ COMPREPLY=( $(compgen -W "length begin end index" -- "$cur") )
+ return 0
+ ;;
+ --color)
+ COMPREPLY=( $(compgen -W "dark light 16 bw" -- "$cur") )
+ return 0
+ ;;
+ --history)
+ COMPREPLY=()
+ return 0
+ ;;
+ esac
+
+ if [[ "$cur" =~ ^-|\+ ]]; then
+ COMPREPLY=( $(compgen -W "${opts}" -- "$cur") )
+ return 0
+ fi
+
+ return 0
+}
+
+_fzf_handle_dynamic_completion() {
+ local cmd orig_var orig ret orig_cmd orig_complete
+ cmd="$1"
+ shift
+ orig_cmd="$1"
+ orig_var="_fzf_orig_completion_$cmd"
+ orig="${!orig_var##*#}"
+ if [[ -n "$orig" ]] && type "$orig" > /dev/null 2>&1; then
+ $orig "$@"
+ elif [[ -n "$_fzf_completion_loader" ]]; then
+ orig_complete=$(complete -p "$orig_cmd" 2> /dev/null)
+ _completion_loader "$@"
+ ret=$?
+ # _completion_loader may not have updated completion for the command
+ if [[ "$(complete -p "$orig_cmd" 2> /dev/null)" != "$orig_complete" ]]; then
+ __fzf_orig_completion < <(complete -p "$orig_cmd" 2> /dev/null)
+ if [[ "$__fzf_nospace_commands" = *" $orig_cmd "* ]]; then
+ eval "${orig_complete/ -F / -o nospace -F }"
+ else
+ eval "$orig_complete"
+ fi
+ fi
+ return $ret
+ fi
+}
+
+__fzf_generic_path_completion() {
+ local cur base dir leftover matches trigger cmd
+ cmd="${COMP_WORDS[0]}"
+ if [[ $cmd == \\* ]]; then
+ cmd="${cmd:1}"
+ fi
+ cmd="${cmd//[^A-Za-z0-9_=]/_}"
+ COMPREPLY=()
+ trigger=${FZF_COMPLETION_TRIGGER-'**'}
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ if [[ "$cur" == *"$trigger" ]]; then
+ base=${cur:0:${#cur}-${#trigger}}
+ eval "base=$base"
+
+ [[ $base = *"/"* ]] && dir="$base"
+ while true; do
+ if [[ -z "$dir" ]] || [[ -d "$dir" ]]; then
+ leftover=${base/#"$dir"}
+ leftover=${leftover/#\/}
+ [[ -z "$dir" ]] && dir='.'
+ [[ "$dir" != "/" ]] && dir="${dir/%\//}"
+ matches=$(eval "$1 $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $2" __fzf_comprun "$4" -q "$leftover" | while read -r item; do
+ printf "%q " "${item%$3}$3"
+ done)
+ matches=${matches% }
+ [[ -z "$3" ]] && [[ "$__fzf_nospace_commands" = *" ${COMP_WORDS[0]} "* ]] && matches="$matches "
+ if [[ -n "$matches" ]]; then
+ COMPREPLY=( "$matches" )
+ else
+ COMPREPLY=( "$cur" )
+ fi
+ printf '\e[5n'
+ return 0
+ fi
+ dir=$(dirname "$dir")
+ [[ "$dir" =~ /$ ]] || dir="$dir"/
+ done
+ else
+ shift
+ shift
+ shift
+ _fzf_handle_dynamic_completion "$cmd" "$@"
+ fi
+}
+
+_fzf_complete() {
+ # Split arguments around --
+ local args rest str_arg i sep
+ args=("$@")
+ sep=
+ for i in "${!args[@]}"; do
+ if [[ "${args[$i]}" = -- ]]; then
+ sep=$i
+ break
+ fi
+ done
+ if [[ -n "$sep" ]]; then
+ str_arg=
+ rest=("${args[@]:$((sep + 1)):${#args[@]}}")
+ args=("${args[@]:0:$sep}")
+ else
+ str_arg=$1
+ args=()
+ shift
+ rest=("$@")
+ fi
+
+ local cur selected trigger cmd post
+ post="$(caller 0 | awk '{print $2}')_post"
+ type -t "$post" > /dev/null 2>&1 || post=cat
+
+ cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}"
+ trigger=${FZF_COMPLETION_TRIGGER-'**'}
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ if [[ "$cur" == *"$trigger" ]]; then
+ cur=${cur:0:${#cur}-${#trigger}}
+
+ selected=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $str_arg" __fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | $post | tr '\n' ' ')
+ selected=${selected% } # Strip trailing space not to repeat "-o nospace"
+ if [[ -n "$selected" ]]; then
+ COMPREPLY=("$selected")
+ else
+ COMPREPLY=("$cur")
+ fi
+ printf '\e[5n'
+ return 0
+ else
+ _fzf_handle_dynamic_completion "$cmd" "${rest[@]}"
+ fi
+}
+
+_fzf_path_completion() {
+ __fzf_generic_path_completion _fzf_compgen_path "-m" "" "$@"
+}
+
+# Deprecated. No file only completion.
+_fzf_file_completion() {
+ _fzf_path_completion "$@"
+}
+
+_fzf_dir_completion() {
+ __fzf_generic_path_completion _fzf_compgen_dir "" "/" "$@"
+}
+
+_fzf_complete_kill() {
+ _fzf_proc_completion "$@"
+}
+
+_fzf_proc_completion() {
+ _fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
+ command ps -ef | sed 1d
+ )
+}
+
+_fzf_proc_completion_post() {
+ awk '{print $2}'
+}
+
+_fzf_host_completion() {
+ _fzf_complete +m -- "$@" < <(
+ command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \
+ <(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
+ <(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
+ awk '{if (length($2) > 0) {print $2}}' | sort -u
+ )
+}
+
+_fzf_var_completion() {
+ _fzf_complete -m -- "$@" < <(
+ declare -xp | sed -En 's|^declare [^ ]+ ([^=]+).*|\1|p'
+ )
+}
+
+_fzf_alias_completion() {
+ _fzf_complete -m -- "$@" < <(
+ alias | sed -En 's|^alias ([^=]+).*|\1|p'
+ )
+}
+
+# fzf options
+complete -o default -F _fzf_opts_completion fzf
+# fzf-tmux is a thin fzf wrapper that has only a few more options than fzf
+# itself. As a quick improvement we take fzf's completion. Adding the few extra
+# fzf-tmux specific options (like `-w WIDTH`) are left as a future patch.
+complete -o default -F _fzf_opts_completion fzf-tmux
+
+d_cmds="${FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}"
+a_cmds="
+ awk cat diff diff3
+ emacs emacsclient ex file ftp g++ gcc gvim head hg java
+ javac ld less more mvim nvim patch perl python ruby
+ sed sftp sort source tail tee uniq vi view vim wc xdg-open
+ basename bunzip2 bzip2 chmod chown curl cp dirname du
+ find git grep gunzip gzip hg jar
+ ln ls mv open rm rsync scp
+ svn tar unzip zip"
+
+# Preserve existing completion
+__fzf_orig_completion < <(complete -p $d_cmds $a_cmds 2> /dev/null)
+
+if type _completion_loader > /dev/null 2>&1; then
+ _fzf_completion_loader=1
+fi
+
+__fzf_defc() {
+ local cmd func opts orig_var orig def
+ cmd="$1"
+ func="$2"
+ opts="$3"
+ orig_var="_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}"
+ orig="${!orig_var}"
+ if [[ -n "$orig" ]]; then
+ printf -v def "$orig" "$func"
+ eval "$def"
+ else
+ complete -F "$func" $opts "$cmd"
+ fi
+}
+
+# Anything
+for cmd in $a_cmds; do
+ __fzf_defc "$cmd" _fzf_path_completion "-o default -o bashdefault"
+done
+
+# Directory
+for cmd in $d_cmds; do
+ __fzf_defc "$cmd" _fzf_dir_completion "-o nospace -o dirnames"
+done
+
+unset cmd d_cmds a_cmds
+
+_fzf_setup_completion() {
+ local kind fn cmd
+ kind=$1
+ fn=_fzf_${1}_completion
+ if [[ $# -lt 2 ]] || ! type -t "$fn" > /dev/null; then
+ echo "usage: ${FUNCNAME[0]} path|dir|var|alias|host|proc COMMANDS..."
+ return 1
+ fi
+ shift
+ __fzf_orig_completion < <(complete -p "$@" 2> /dev/null)
+ for cmd in "$@"; do
+ case "$kind" in
+ dir) __fzf_defc "$cmd" "$fn" "-o nospace -o dirnames" ;;
+ var) __fzf_defc "$cmd" "$fn" "-o default -o nospace -v" ;;
+ alias) __fzf_defc "$cmd" "$fn" "-a" ;;
+ *) __fzf_defc "$cmd" "$fn" "-o default -o bashdefault" ;;
+ esac
+ done
+}
+
+# Environment variables / Aliases / Hosts / Process
+_fzf_setup_completion 'var' export unset
+_fzf_setup_completion 'alias' unalias
+_fzf_setup_completion 'host' ssh telnet
+_fzf_setup_completion 'proc' kill
+
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/shell/completion.zsh b/dot-oh-my-zsh/custom/plugins/fzf/shell/completion.zsh
new file mode 100644
index 00000000..417d03c0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/shell/completion.zsh
@@ -0,0 +1,324 @@
+# ____ ____
+# / __/___ / __/
+# / /_/_ / / /_
+# / __/ / /_/ __/
+# /_/ /___/_/ completion.zsh
+#
+# - $FZF_TMUX (default: 0)
+# - $FZF_TMUX_OPTS (default: '-d 40%')
+# - $FZF_COMPLETION_TRIGGER (default: '**')
+# - $FZF_COMPLETION_OPTS (default: empty)
+
+# Both branches of the following `if` do the same thing -- define
+# __fzf_completion_options such that `eval $__fzf_completion_options` sets
+# all options to the same values they currently have. We'll do just that at
+# the bottom of the file after changing options to what we prefer.
+#
+# IMPORTANT: Until we get to the `emulate` line, all words that *can* be quoted
+# *must* be quoted in order to prevent alias expansion. In addition, code must
+# be written in a way works with any set of zsh options. This is very tricky, so
+# careful when you change it.
+#
+# Start by loading the builtin zsh/parameter module. It provides `options`
+# associative array that stores current shell options.
+if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then
+ # This is the fast branch and it gets taken on virtually all Zsh installations.
+ #
+ # ${(kv)options[@]} expands to array of keys (option names) and values ("on"
+ # or "off"). The subsequent expansion# with (j: :) flag joins all elements
+ # together separated by spaces. __fzf_completion_options ends up with a value
+ # like this: "options=(shwordsplit off aliases on ...)".
+ __fzf_completion_options="options=(${(j: :)${(kv)options[@]}})"
+else
+ # This branch is much slower because it forks to get the names of all
+ # zsh options. It's possible to eliminate this fork but it's not worth the
+ # trouble because this branch gets taken only on very ancient or broken
+ # zsh installations.
+ () {
+ # That `()` above defines an anonymous function. This is essentially a scope
+ # for local parameters. We use it to avoid polluting global scope.
+ 'local' '__fzf_opt'
+ __fzf_completion_options="setopt"
+ # `set -o` prints one line for every zsh option. Each line contains option
+ # name, some spaces, and then either "on" or "off". We just want option names.
+ # Expansion with (@f) flag splits a string into lines. The outer expansion
+ # removes spaces and everything that follow them on every line. __fzf_opt
+ # ends up iterating over option names: shwordsplit, aliases, etc.
+ for __fzf_opt in "${(@)${(@f)$(set -o)}%% *}"; do
+ if [[ -o "$__fzf_opt" ]]; then
+ # Option $__fzf_opt is currently on, so remember to set it back on.
+ __fzf_completion_options+=" -o $__fzf_opt"
+ else
+ # Option $__fzf_opt is currently off, so remember to set it back off.
+ __fzf_completion_options+=" +o $__fzf_opt"
+ fi
+ done
+ # The value of __fzf_completion_options here looks like this:
+ # "setopt +o shwordsplit -o aliases ..."
+ }
+fi
+
+# Enable the default zsh options (those marked with <Z> in `man zshoptions`)
+# but without `aliases`. Aliases in functions are expanded when functions are
+# defined, so if we disable aliases here, we'll be sure to have no pesky
+# aliases in any of our functions. This way we won't need prefix every
+# command with `command` or to quote every word to defend against global
+# aliases. Note that `aliases` is not the only option that's important to
+# control. There are several others that could wreck havoc if they are set
+# to values we don't expect. With the following `emulate` command we
+# sidestep this issue entirely.
+'emulate' 'zsh' '-o' 'no_aliases'
+
+# This brace is the start of try-always block. The `always` part is like
+# `finally` in lesser languages. We use it to *always* restore user options.
+{
+
+# Bail out if not interactive shell.
+[[ -o interactive ]] || return 0
+
+# To use custom commands instead of find, override _fzf_compgen_{path,dir}
+if ! declare -f _fzf_compgen_path > /dev/null; then
+ _fzf_compgen_path() {
+ echo "$1"
+ command find -L "$1" \
+ -name .git -prune -o -name .hg -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
+ -a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
+ }
+fi
+
+if ! declare -f _fzf_compgen_dir > /dev/null; then
+ _fzf_compgen_dir() {
+ command find -L "$1" \
+ -name .git -prune -o -name .hg -prune -o -name .svn -prune -o -type d \
+ -a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
+ }
+fi
+
+###########################################################
+
+__fzf_comprun() {
+ if [[ "$(type _fzf_comprun 2>&1)" =~ function ]]; then
+ _fzf_comprun "$@"
+ elif [ -n "$TMUX_PANE" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "$FZF_TMUX_OPTS" ]; }; then
+ shift
+ if [ -n "$FZF_TMUX_OPTS" ]; then
+ fzf-tmux ${(Q)${(Z+n+)FZF_TMUX_OPTS}} -- "$@"
+ else
+ fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%} -- "$@"
+ fi
+ else
+ shift
+ fzf "$@"
+ fi
+}
+
+# Extract the name of the command. e.g. foo=1 bar baz**<tab>
+__fzf_extract_command() {
+ local token tokens
+ tokens=(${(z)1})
+ for token in $tokens; do
+ token=${(Q)token}
+ if [[ "$token" =~ [[:alnum:]] && ! "$token" =~ "=" ]]; then
+ echo "$token"
+ return
+ fi
+ done
+ echo "${tokens[1]}"
+}
+
+__fzf_generic_path_completion() {
+ local base lbuf cmd compgen fzf_opts suffix tail dir leftover matches
+ base=$1
+ lbuf=$2
+ cmd=$(__fzf_extract_command "$lbuf")
+ compgen=$3
+ fzf_opts=$4
+ suffix=$5
+ tail=$6
+
+ setopt localoptions nonomatch
+ eval "base=$base"
+ [[ $base = *"/"* ]] && dir="$base"
+ while [ 1 ]; do
+ if [[ -z "$dir" || -d ${dir} ]]; then
+ leftover=${base/#"$dir"}
+ leftover=${leftover/#\/}
+ [ -z "$dir" ] && dir='.'
+ [ "$dir" != "/" ] && dir="${dir/%\//}"
+ matches=$(eval "$compgen $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS" __fzf_comprun "$cmd" ${(Q)${(Z+n+)fzf_opts}} -q "$leftover" | while read item; do
+ item="${item%$suffix}$suffix"
+ echo -n "${(q)item} "
+ done)
+ matches=${matches% }
+ if [ -n "$matches" ]; then
+ LBUFFER="$lbuf$matches$tail"
+ fi
+ zle reset-prompt
+ break
+ fi
+ dir=$(dirname "$dir")
+ dir=${dir%/}/
+ done
+}
+
+_fzf_path_completion() {
+ __fzf_generic_path_completion "$1" "$2" _fzf_compgen_path \
+ "-m" "" " "
+}
+
+_fzf_dir_completion() {
+ __fzf_generic_path_completion "$1" "$2" _fzf_compgen_dir \
+ "" "/" ""
+}
+
+_fzf_feed_fifo() (
+ command rm -f "$1"
+ mkfifo "$1"
+ cat <&0 > "$1" &
+)
+
+_fzf_complete() {
+ setopt localoptions ksh_arrays
+ # Split arguments around --
+ local args rest str_arg i sep
+ args=("$@")
+ sep=
+ for i in {0..${#args[@]}}; do
+ if [[ "${args[$i]}" = -- ]]; then
+ sep=$i
+ break
+ fi
+ done
+ if [[ -n "$sep" ]]; then
+ str_arg=
+ rest=("${args[@]:$((sep + 1)):${#args[@]}}")
+ args=("${args[@]:0:$sep}")
+ else
+ str_arg=$1
+ args=()
+ shift
+ rest=("$@")
+ fi
+
+ local fifo lbuf cmd matches post
+ fifo="${TMPDIR:-/tmp}/fzf-complete-fifo-$$"
+ lbuf=${rest[0]}
+ cmd=$(__fzf_extract_command "$lbuf")
+ post="${funcstack[1]}_post"
+ type $post > /dev/null 2>&1 || post=cat
+
+ _fzf_feed_fifo "$fifo"
+ matches=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $str_arg" __fzf_comprun "$cmd" "${args[@]}" -q "${(Q)prefix}" < "$fifo" | $post | tr '\n' ' ')
+ if [ -n "$matches" ]; then
+ LBUFFER="$lbuf$matches"
+ fi
+ command rm -f "$fifo"
+}
+
+_fzf_complete_telnet() {
+ _fzf_complete +m -- "$@" < <(
+ command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0' |
+ awk '{if (length($2) > 0) {print $2}}' | sort -u
+ )
+}
+
+_fzf_complete_ssh() {
+ _fzf_complete +m -- "$@" < <(
+ setopt localoptions nonomatch
+ command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \
+ <(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
+ <(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
+ awk '{if (length($2) > 0) {print $2}}' | sort -u
+ )
+}
+
+_fzf_complete_export() {
+ _fzf_complete -m -- "$@" < <(
+ declare -xp | sed 's/=.*//' | sed 's/.* //'
+ )
+}
+
+_fzf_complete_unset() {
+ _fzf_complete -m -- "$@" < <(
+ declare -xp | sed 's/=.*//' | sed 's/.* //'
+ )
+}
+
+_fzf_complete_unalias() {
+ _fzf_complete +m -- "$@" < <(
+ alias | sed 's/=.*//'
+ )
+}
+
+_fzf_complete_kill() {
+ _fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
+ command ps -ef | sed 1d
+ )
+}
+
+_fzf_complete_kill_post() {
+ awk '{print $2}'
+}
+
+fzf-completion() {
+ local tokens cmd prefix trigger tail matches lbuf d_cmds
+ setopt localoptions noshwordsplit noksh_arrays noposixbuiltins
+
+ # http://zsh.sourceforge.net/FAQ/zshfaq03.html
+ # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion-Flags
+ tokens=(${(z)LBUFFER})
+ if [ ${#tokens} -lt 1 ]; then
+ zle ${fzf_default_completion:-expand-or-complete}
+ return
+ fi
+
+ cmd=$(__fzf_extract_command "$LBUFFER")
+
+ # Explicitly allow for empty trigger.
+ trigger=${FZF_COMPLETION_TRIGGER-'**'}
+ [ -z "$trigger" -a ${LBUFFER[-1]} = ' ' ] && tokens+=("")
+
+ # When the trigger starts with ';', it becomes a separate token
+ if [[ ${LBUFFER} = *"${tokens[-2]}${tokens[-1]}" ]]; then
+ tokens[-2]="${tokens[-2]}${tokens[-1]}"
+ tokens=(${tokens[0,-2]})
+ fi
+
+ lbuf=$LBUFFER
+ tail=${LBUFFER:$(( ${#LBUFFER} - ${#trigger} ))}
+
+ # Trigger sequence given
+ if [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then
+ d_cmds=(${=FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir})
+
+ [ -z "$trigger" ] && prefix=${tokens[-1]} || prefix=${tokens[-1]:0:-${#trigger}}
+ [ -n "${tokens[-1]}" ] && lbuf=${lbuf:0:-${#tokens[-1]}}
+
+ if eval "type _fzf_complete_${cmd} > /dev/null"; then
+ prefix="$prefix" eval _fzf_complete_${cmd} ${(q)lbuf}
+ zle reset-prompt
+ elif [ ${d_cmds[(i)$cmd]} -le ${#d_cmds} ]; then
+ _fzf_dir_completion "$prefix" "$lbuf"
+ else
+ _fzf_path_completion "$prefix" "$lbuf"
+ fi
+ # Fall back to default completion
+ else
+ zle ${fzf_default_completion:-expand-or-complete}
+ fi
+}
+
+[ -z "$fzf_default_completion" ] && {
+ binding=$(bindkey '^I')
+ [[ $binding =~ 'undefined-key' ]] || fzf_default_completion=$binding[(s: :w)2]
+ unset binding
+}
+
+zle -N fzf-completion
+bindkey '^I' fzf-completion
+
+} always {
+ # Restore the original options.
+ eval $__fzf_completion_options
+ 'unset' '__fzf_completion_options'
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.bash b/dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.bash
new file mode 100644
index 00000000..f6797d49
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.bash
@@ -0,0 +1,102 @@
+# ____ ____
+# / __/___ / __/
+# / /_/_ / / /_
+# / __/ / /_/ __/
+# /_/ /___/_/ key-bindings.bash
+#
+# - $FZF_TMUX_OPTS
+# - $FZF_CTRL_T_COMMAND
+# - $FZF_CTRL_T_OPTS
+# - $FZF_CTRL_R_OPTS
+# - $FZF_ALT_C_COMMAND
+# - $FZF_ALT_C_OPTS
+
+# Key bindings
+# ------------
+__fzf_select__() {
+ local cmd opts
+ cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
+ -o -type f -print \
+ -o -type d -print \
+ -o -type l -print 2> /dev/null | cut -b3-"}"
+ opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS -m"
+ eval "$cmd" |
+ FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) "$@" |
+ while read -r item; do
+ printf '%q ' "$item" # escape special chars
+ done
+}
+
+if [[ $- =~ i ]]; then
+
+__fzfcmd() {
+ [[ -n "$TMUX_PANE" ]] && { [[ "${FZF_TMUX:-0}" != 0 ]] || [[ -n "$FZF_TMUX_OPTS" ]]; } &&
+ echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf"
+}
+
+fzf-file-widget() {
+ local selected="$(__fzf_select__ "$@")"
+ READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
+ READLINE_POINT=$(( READLINE_POINT + ${#selected} ))
+}
+
+__fzf_cd__() {
+ local cmd opts dir
+ cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
+ -o -type d -print 2> /dev/null | cut -b3-"}"
+ opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore --reverse $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS +m"
+ dir=$(eval "$cmd" | FZF_DEFAULT_OPTS="$opts" $(__fzfcmd)) && printf 'builtin cd -- %q' "$dir"
+}
+
+__fzf_history__() {
+ local output opts script
+ opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS +m --read0"
+ script='BEGIN { getc; $/ = "\n\t"; $HISTCOUNT = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCOUNT - $. . "\t$_" if !$seen{$_}++'
+ output=$(
+ builtin fc -lnr -2147483648 |
+ last_hist=$(HISTTIMEFORMAT='' builtin history 1) perl -n -l0 -e "$script" |
+ FZF_DEFAULT_OPTS="$opts" $(__fzfcmd) --query "$READLINE_LINE"
+ ) || return
+ READLINE_LINE=${output#*$'\t'}
+ if [[ -z "$READLINE_POINT" ]]; then
+ echo "$READLINE_LINE"
+ else
+ READLINE_POINT=0x7fffffff
+ fi
+}
+
+# Required to refresh the prompt after fzf
+bind -m emacs-standard '"\er": redraw-current-line'
+
+bind -m vi-command '"\C-z": emacs-editing-mode'
+bind -m vi-insert '"\C-z": emacs-editing-mode'
+bind -m emacs-standard '"\C-z": vi-editing-mode'
+
+if (( BASH_VERSINFO[0] < 4 )); then
+ # CTRL-T - Paste the selected file path into the command line
+ bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__fzf_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
+ bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
+ bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
+
+ # CTRL-R - Paste the selected command from history into the command line
+ bind -m emacs-standard '"\C-r": "\C-e \C-u\C-y\ey\C-u"$(__fzf_history__)"\e\C-e\er"'
+ bind -m vi-command '"\C-r": "\C-z\C-r\C-z"'
+ bind -m vi-insert '"\C-r": "\C-z\C-r\C-z"'
+else
+ # CTRL-T - Paste the selected file path into the command line
+ bind -m emacs-standard -x '"\C-t": fzf-file-widget'
+ bind -m vi-command -x '"\C-t": fzf-file-widget'
+ bind -m vi-insert -x '"\C-t": fzf-file-widget'
+
+ # CTRL-R - Paste the selected command from history into the command line
+ bind -m emacs-standard -x '"\C-r": __fzf_history__'
+ bind -m vi-command -x '"\C-r": __fzf_history__'
+ bind -m vi-insert -x '"\C-r": __fzf_history__'
+fi
+
+# ALT-C - cd into the selected directory
+bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d"'
+bind -m vi-command '"\ec": "\C-z\ec\C-z"'
+bind -m vi-insert '"\ec": "\C-z\ec\C-z"'
+
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.fish b/dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.fish
new file mode 100644
index 00000000..743c7c18
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.fish
@@ -0,0 +1,172 @@
+# ____ ____
+# / __/___ / __/
+# / /_/_ / / /_
+# / __/ / /_/ __/
+# /_/ /___/_/ key-bindings.fish
+#
+# - $FZF_TMUX_OPTS
+# - $FZF_CTRL_T_COMMAND
+# - $FZF_CTRL_T_OPTS
+# - $FZF_CTRL_R_OPTS
+# - $FZF_ALT_C_COMMAND
+# - $FZF_ALT_C_OPTS
+
+# Key bindings
+# ------------
+function fzf_key_bindings
+
+ # Store current token in $dir as root for the 'find' command
+ function fzf-file-widget -d "List files and folders"
+ set -l commandline (__fzf_parse_commandline)
+ set -l dir $commandline[1]
+ set -l fzf_query $commandline[2]
+ set -l prefix $commandline[3]
+
+ # "-path \$dir'*/\\.*'" matches hidden files/folders inside $dir but not
+ # $dir itself, even if hidden.
+ test -n "$FZF_CTRL_T_COMMAND"; or set -l FZF_CTRL_T_COMMAND "
+ command find -L \$dir -mindepth 1 \\( -path \$dir'*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \
+ -o -type f -print \
+ -o -type d -print \
+ -o -type l -print 2> /dev/null | sed 's@^\./@@'"
+
+ test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
+ begin
+ set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS"
+ eval "$FZF_CTRL_T_COMMAND | "(__fzfcmd)' -m --query "'$fzf_query'"' | while read -l r; set result $result $r; end
+ end
+ if [ -z "$result" ]
+ commandline -f repaint
+ return
+ else
+ # Remove last token from commandline.
+ commandline -t ""
+ end
+ for i in $result
+ commandline -it -- $prefix
+ commandline -it -- (string escape $i)
+ commandline -it -- ' '
+ end
+ commandline -f repaint
+ end
+
+ function fzf-history-widget -d "Show command history"
+ test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
+ begin
+ set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT $FZF_DEFAULT_OPTS --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS +m"
+
+ set -l FISH_MAJOR (echo $version | cut -f1 -d.)
+ set -l FISH_MINOR (echo $version | cut -f2 -d.)
+
+ # history's -z flag is needed for multi-line support.
+ # history's -z flag was added in fish 2.4.0, so don't use it for versions
+ # before 2.4.0.
+ if [ "$FISH_MAJOR" -gt 2 -o \( "$FISH_MAJOR" -eq 2 -a "$FISH_MINOR" -ge 4 \) ];
+ history -z | eval (__fzfcmd) --read0 --print0 -q '(commandline)' | read -lz result
+ and commandline -- $result
+ else
+ history | eval (__fzfcmd) -q '(commandline)' | read -l result
+ and commandline -- $result
+ end
+ end
+ commandline -f repaint
+ end
+
+ function fzf-cd-widget -d "Change directory"
+ set -l commandline (__fzf_parse_commandline)
+ set -l dir $commandline[1]
+ set -l fzf_query $commandline[2]
+ set -l prefix $commandline[3]
+
+ test -n "$FZF_ALT_C_COMMAND"; or set -l FZF_ALT_C_COMMAND "
+ command find -L \$dir -mindepth 1 \\( -path \$dir'*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \
+ -o -type d -print 2> /dev/null | sed 's@^\./@@'"
+ test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
+ begin
+ set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS"
+ eval "$FZF_ALT_C_COMMAND | "(__fzfcmd)' +m --query "'$fzf_query'"' | read -l result
+
+ if [ -n "$result" ]
+ cd -- $result
+
+ # Remove last token from commandline.
+ commandline -t ""
+ commandline -it -- $prefix
+ end
+ end
+
+ commandline -f repaint
+ end
+
+ function __fzfcmd
+ test -n "$FZF_TMUX"; or set FZF_TMUX 0
+ test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
+ if [ -n "$FZF_TMUX_OPTS" ]
+ echo "fzf-tmux $FZF_TMUX_OPTS -- "
+ else if [ $FZF_TMUX -eq 1 ]
+ echo "fzf-tmux -d$FZF_TMUX_HEIGHT -- "
+ else
+ echo "fzf"
+ end
+ end
+
+ bind \ct fzf-file-widget
+ bind \cr fzf-history-widget
+ bind \ec fzf-cd-widget
+
+ if bind -M insert > /dev/null 2>&1
+ bind -M insert \ct fzf-file-widget
+ bind -M insert \cr fzf-history-widget
+ bind -M insert \ec fzf-cd-widget
+ end
+
+ function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix'
+ set -l commandline (commandline -t)
+
+ # strip -option= from token if present
+ set -l prefix (string match -r -- '^-[^\s=]+=' $commandline)
+ set commandline (string replace -- "$prefix" '' $commandline)
+
+ # eval is used to do shell expansion on paths
+ eval set commandline $commandline
+
+ if [ -z $commandline ]
+ # Default to current directory with no --query
+ set dir '.'
+ set fzf_query ''
+ else
+ set dir (__fzf_get_dir $commandline)
+
+ if [ "$dir" = "." -a (string sub -l 1 -- $commandline) != '.' ]
+ # if $dir is "." but commandline is not a relative path, this means no file path found
+ set fzf_query $commandline
+ else
+ # Also remove trailing slash after dir, to "split" input properly
+ set fzf_query (string replace -r "^$dir/?" -- '' "$commandline")
+ end
+ end
+
+ echo $dir
+ echo $fzf_query
+ echo $prefix
+ end
+
+ function __fzf_get_dir -d 'Find the longest existing filepath from input string'
+ set dir $argv
+
+ # Strip all trailing slashes. Ignore if $dir is root dir (/)
+ if [ (string length -- $dir) -gt 1 ]
+ set dir (string replace -r '/*$' -- '' $dir)
+ end
+
+ # Iteratively check if dir exists and strip tail end of path
+ while [ ! -d "$dir" ]
+ # If path is absolute, this can keep going until ends up at /
+ # If path is relative, this can keep going until entire input is consumed, dirname returns "."
+ set dir (dirname -- "$dir")
+ end
+
+ echo $dir
+ end
+
+end
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.zsh b/dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.zsh
new file mode 100644
index 00000000..47ef17a7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/shell/key-bindings.zsh
@@ -0,0 +1,120 @@
+# ____ ____
+# / __/___ / __/
+# / /_/_ / / /_
+# / __/ / /_/ __/
+# /_/ /___/_/ key-bindings.zsh
+#
+# - $FZF_TMUX_OPTS
+# - $FZF_CTRL_T_COMMAND
+# - $FZF_CTRL_T_OPTS
+# - $FZF_CTRL_R_OPTS
+# - $FZF_ALT_C_COMMAND
+# - $FZF_ALT_C_OPTS
+
+# Key bindings
+# ------------
+
+# The code at the top and the bottom of this file is the same as in completion.zsh.
+# Refer to that file for explanation.
+if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then
+ __fzf_key_bindings_options="options=(${(j: :)${(kv)options[@]}})"
+else
+ () {
+ __fzf_key_bindings_options="setopt"
+ 'local' '__fzf_opt'
+ for __fzf_opt in "${(@)${(@f)$(set -o)}%% *}"; do
+ if [[ -o "$__fzf_opt" ]]; then
+ __fzf_key_bindings_options+=" -o $__fzf_opt"
+ else
+ __fzf_key_bindings_options+=" +o $__fzf_opt"
+ fi
+ done
+ }
+fi
+
+'emulate' 'zsh' '-o' 'no_aliases'
+
+{
+
+[[ -o interactive ]] || return 0
+
+# CTRL-T - Paste the selected file path(s) into the command line
+__fsel() {
+ local cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
+ -o -type f -print \
+ -o -type d -print \
+ -o -type l -print 2> /dev/null | cut -b3-"}"
+ setopt localoptions pipefail no_aliases 2> /dev/null
+ local item
+ eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS" $(__fzfcmd) -m "$@" | while read item; do
+ echo -n "${(q)item} "
+ done
+ local ret=$?
+ echo
+ return $ret
+}
+
+__fzfcmd() {
+ [ -n "$TMUX_PANE" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "$FZF_TMUX_OPTS" ]; } &&
+ echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf"
+}
+
+fzf-file-widget() {
+ LBUFFER="${LBUFFER}$(__fsel)"
+ local ret=$?
+ zle reset-prompt
+ return $ret
+}
+zle -N fzf-file-widget
+bindkey -M emacs '^T' fzf-file-widget
+bindkey -M vicmd '^T' fzf-file-widget
+bindkey -M viins '^T' fzf-file-widget
+
+# ALT-C - cd into the selected directory
+fzf-cd-widget() {
+ local cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
+ -o -type d -print 2> /dev/null | cut -b3-"}"
+ setopt localoptions pipefail no_aliases 2> /dev/null
+ local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" $(__fzfcmd) +m)"
+ if [[ -z "$dir" ]]; then
+ zle redisplay
+ return 0
+ fi
+ zle push-line # Clear buffer. Auto-restored on next prompt.
+ BUFFER="builtin cd -- ${(q)dir}"
+ zle accept-line
+ local ret=$?
+ unset dir # ensure this doesn't end up appearing in prompt expansion
+ zle reset-prompt
+ return $ret
+}
+zle -N fzf-cd-widget
+bindkey -M emacs '\ec' fzf-cd-widget
+bindkey -M vicmd '\ec' fzf-cd-widget
+bindkey -M viins '\ec' fzf-cd-widget
+
+# CTRL-R - Paste the selected command from history into the command line
+fzf-history-widget() {
+ local selected num
+ setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
+ selected=( $(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
+ FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
+ local ret=$?
+ if [ -n "$selected" ]; then
+ num=$selected[1]
+ if [ -n "$num" ]; then
+ zle vi-fetch-history -n $num
+ fi
+ fi
+ zle reset-prompt
+ return $ret
+}
+zle -N fzf-history-widget
+bindkey -M emacs '^R' fzf-history-widget
+bindkey -M vicmd '^R' fzf-history-widget
+bindkey -M viins '^R' fzf-history-widget
+
+} always {
+ eval $__fzf_key_bindings_options
+ 'unset' '__fzf_key_bindings_options'
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/LICENSE b/dot-oh-my-zsh/custom/plugins/fzf/src/LICENSE
new file mode 100644
index 00000000..50aa5d92
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2021 Junegunn Choi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/algo/algo.go b/dot-oh-my-zsh/custom/plugins/fzf/src/algo/algo.go
new file mode 100644
index 00000000..50dd466c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/algo/algo.go
@@ -0,0 +1,946 @@
+package algo
+
+/*
+
+Algorithm
+---------
+
+FuzzyMatchV1 finds the first "fuzzy" occurrence of the pattern within the given
+text in O(n) time where n is the length of the text. Once the position of the
+last character is located, it traverses backwards to see if there's a shorter
+substring that matches the pattern.
+
+ a_____b___abc__ To find "abc"
+ *-----*-----*> 1. Forward scan
+ <*** 2. Backward scan
+
+The algorithm is simple and fast, but as it only sees the first occurrence,
+it is not guaranteed to find the occurrence with the highest score.
+
+ a_____b__c__abc
+ *-----*--* ***
+
+FuzzyMatchV2 implements a modified version of Smith-Waterman algorithm to find
+the optimal solution (highest score) according to the scoring criteria. Unlike
+the original algorithm, omission or mismatch of a character in the pattern is
+not allowed.
+
+Performance
+-----------
+
+The new V2 algorithm is slower than V1 as it examines all occurrences of the
+pattern instead of stopping immediately after finding the first one. The time
+complexity of the algorithm is O(nm) if a match is found and O(n) otherwise
+where n is the length of the item and m is the length of the pattern. Thus, the
+performance overhead may not be noticeable for a query with high selectivity.
+However, if the performance is more important than the quality of the result,
+you can still choose v1 algorithm with --algo=v1.
+
+Scoring criteria
+----------------
+
+- We prefer matches at special positions, such as the start of a word, or
+ uppercase character in camelCase words.
+
+- That is, we prefer an occurrence of the pattern with more characters
+ matching at special positions, even if the total match length is longer.
+ e.g. "fuzzyfinder" vs. "fuzzy-finder" on "ff"
+ ````````````
+- Also, if the first character in the pattern appears at one of the special
+ positions, the bonus point for the position is multiplied by a constant
+ as it is extremely likely that the first character in the typed pattern
+ has more significance than the rest.
+ e.g. "fo-bar" vs. "foob-r" on "br"
+ ``````
+- But since fzf is still a fuzzy finder, not an acronym finder, we should also
+ consider the total length of the matched substring. This is why we have the
+ gap penalty. The gap penalty increases as the length of the gap (distance
+ between the matching characters) increases, so the effect of the bonus is
+ eventually cancelled at some point.
+ e.g. "fuzzyfinder" vs. "fuzzy-blurry-finder" on "ff"
+ ```````````
+- Consequently, it is crucial to find the right balance between the bonus
+ and the gap penalty. The parameters were chosen that the bonus is cancelled
+ when the gap size increases beyond 8 characters.
+
+- The bonus mechanism can have the undesirable side effect where consecutive
+ matches are ranked lower than the ones with gaps.
+ e.g. "foobar" vs. "foo-bar" on "foob"
+ ```````
+- To correct this anomaly, we also give extra bonus point to each character
+ in a consecutive matching chunk.
+ e.g. "foobar" vs. "foo-bar" on "foob"
+ ``````
+- The amount of consecutive bonus is primarily determined by the bonus of the
+ first character in the chunk.
+ e.g. "foobar" vs. "out-of-bound" on "oob"
+ ````````````
+*/
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+var DEBUG bool
+
+var delimiterChars = "/,:;|"
+
+const whiteChars = " \t\n\v\f\r\x85\xA0"
+
+func indexAt(index int, max int, forward bool) int {
+ if forward {
+ return index
+ }
+ return max - index - 1
+}
+
+// Result contains the results of running a match function.
+type Result struct {
+ // TODO int32 should suffice
+ Start int
+ End int
+ Score int
+}
+
+const (
+ scoreMatch = 16
+ scoreGapStart = -3
+ scoreGapExtension = -1
+
+ // We prefer matches at the beginning of a word, but the bonus should not be
+ // too great to prevent the longer acronym matches from always winning over
+ // shorter fuzzy matches. The bonus point here was specifically chosen that
+ // the bonus is cancelled when the gap between the acronyms grows over
+ // 8 characters, which is approximately the average length of the words found
+ // in web2 dictionary and my file system.
+ bonusBoundary = scoreMatch / 2
+
+ // Although bonus point for non-word characters is non-contextual, we need it
+ // for computing bonus points for consecutive chunks starting with a non-word
+ // character.
+ bonusNonWord = scoreMatch / 2
+
+ // Edge-triggered bonus for matches in camelCase words.
+ // Compared to word-boundary case, they don't accompany single-character gaps
+ // (e.g. FooBar vs. foo-bar), so we deduct bonus point accordingly.
+ bonusCamel123 = bonusBoundary + scoreGapExtension
+
+ // Minimum bonus point given to characters in consecutive chunks.
+ // Note that bonus points for consecutive matches shouldn't have needed if we
+ // used fixed match score as in the original algorithm.
+ bonusConsecutive = -(scoreGapStart + scoreGapExtension)
+
+ // The first character in the typed pattern usually has more significance
+ // than the rest so it's important that it appears at special positions where
+ // bonus points are given, e.g. "to-go" vs. "ongoing" on "og" or on "ogo".
+ // The amount of the extra bonus should be limited so that the gap penalty is
+ // still respected.
+ bonusFirstCharMultiplier = 2
+)
+
+var (
+ // Extra bonus for word boundary after whitespace character or beginning of the string
+ bonusBoundaryWhite int16 = bonusBoundary + 2
+
+ // Extra bonus for word boundary after slash, colon, semi-colon, and comma
+ bonusBoundaryDelimiter int16 = bonusBoundary + 1
+
+ initialCharClass charClass = charWhite
+)
+
+type charClass int
+
+const (
+ charWhite charClass = iota
+ charNonWord
+ charDelimiter
+ charLower
+ charUpper
+ charLetter
+ charNumber
+)
+
+func Init(scheme string) bool {
+ switch scheme {
+ case "default":
+ bonusBoundaryWhite = bonusBoundary + 2
+ bonusBoundaryDelimiter = bonusBoundary + 1
+ case "path":
+ bonusBoundaryWhite = bonusBoundary
+ bonusBoundaryDelimiter = bonusBoundary + 1
+ if os.PathSeparator == '/' {
+ delimiterChars = "/"
+ } else {
+ delimiterChars = string([]rune{os.PathSeparator, '/'})
+ }
+ initialCharClass = charDelimiter
+ case "history":
+ bonusBoundaryWhite = bonusBoundary
+ bonusBoundaryDelimiter = bonusBoundary
+ default:
+ return false
+ }
+ return true
+}
+
+func posArray(withPos bool, len int) *[]int {
+ if withPos {
+ pos := make([]int, 0, len)
+ return &pos
+ }
+ return nil
+}
+
+func alloc16(offset int, slab *util.Slab, size int) (int, []int16) {
+ if slab != nil && cap(slab.I16) > offset+size {
+ slice := slab.I16[offset : offset+size]
+ return offset + size, slice
+ }
+ return offset, make([]int16, size)
+}
+
+func alloc32(offset int, slab *util.Slab, size int) (int, []int32) {
+ if slab != nil && cap(slab.I32) > offset+size {
+ slice := slab.I32[offset : offset+size]
+ return offset + size, slice
+ }
+ return offset, make([]int32, size)
+}
+
+func charClassOfAscii(char rune) charClass {
+ if char >= 'a' && char <= 'z' {
+ return charLower
+ } else if char >= 'A' && char <= 'Z' {
+ return charUpper
+ } else if char >= '0' && char <= '9' {
+ return charNumber
+ } else if strings.IndexRune(whiteChars, char) >= 0 {
+ return charWhite
+ } else if strings.IndexRune(delimiterChars, char) >= 0 {
+ return charDelimiter
+ }
+ return charNonWord
+}
+
+func charClassOfNonAscii(char rune) charClass {
+ if unicode.IsLower(char) {
+ return charLower
+ } else if unicode.IsUpper(char) {
+ return charUpper
+ } else if unicode.IsNumber(char) {
+ return charNumber
+ } else if unicode.IsLetter(char) {
+ return charLetter
+ } else if unicode.IsSpace(char) {
+ return charWhite
+ } else if strings.IndexRune(delimiterChars, char) >= 0 {
+ return charDelimiter
+ }
+ return charNonWord
+}
+
+func charClassOf(char rune) charClass {
+ if char <= unicode.MaxASCII {
+ return charClassOfAscii(char)
+ }
+ return charClassOfNonAscii(char)
+}
+
+func bonusFor(prevClass charClass, class charClass) int16 {
+ if class > charNonWord {
+ if prevClass == charWhite {
+ // Word boundary after whitespace
+ return bonusBoundaryWhite
+ } else if prevClass == charDelimiter {
+ // Word boundary after a delimiter character
+ return bonusBoundaryDelimiter
+ } else if prevClass == charNonWord {
+ // Word boundary
+ return bonusBoundary
+ }
+ }
+ if prevClass == charLower && class == charUpper ||
+ prevClass != charNumber && class == charNumber {
+ // camelCase letter123
+ return bonusCamel123
+ } else if class == charNonWord {
+ return bonusNonWord
+ } else if class == charWhite {
+ return bonusBoundaryWhite
+ }
+ return 0
+}
+
+func bonusAt(input *util.Chars, idx int) int16 {
+ if idx == 0 {
+ return bonusBoundaryWhite
+ }
+ return bonusFor(charClassOf(input.Get(idx-1)), charClassOf(input.Get(idx)))
+}
+
+func normalizeRune(r rune) rune {
+ if r < 0x00C0 || r > 0x2184 {
+ return r
+ }
+
+ n := normalized[r]
+ if n > 0 {
+ return n
+ }
+ return r
+}
+
+// Algo functions make two assumptions
+// 1. "pattern" is given in lowercase if "caseSensitive" is false
+// 2. "pattern" is already normalized if "normalize" is true
+type Algo func(caseSensitive bool, normalize bool, forward bool, input *util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int)
+
+func trySkip(input *util.Chars, caseSensitive bool, b byte, from int) int {
+ byteArray := input.Bytes()[from:]
+ idx := bytes.IndexByte(byteArray, b)
+ if idx == 0 {
+ // Can't skip any further
+ return from
+ }
+ // We may need to search for the uppercase letter again. We don't have to
+ // consider normalization as we can be sure that this is an ASCII string.
+ if !caseSensitive && b >= 'a' && b <= 'z' {
+ if idx > 0 {
+ byteArray = byteArray[:idx]
+ }
+ uidx := bytes.IndexByte(byteArray, b-32)
+ if uidx >= 0 {
+ idx = uidx
+ }
+ }
+ if idx < 0 {
+ return -1
+ }
+ return from + idx
+}
+
+func isAscii(runes []rune) bool {
+ for _, r := range runes {
+ if r >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
+
+func asciiFuzzyIndex(input *util.Chars, pattern []rune, caseSensitive bool) int {
+ // Can't determine
+ if !input.IsBytes() {
+ return 0
+ }
+
+ // Not possible
+ if !isAscii(pattern) {
+ return -1
+ }
+
+ firstIdx, idx := 0, 0
+ for pidx := 0; pidx < len(pattern); pidx++ {
+ idx = trySkip(input, caseSensitive, byte(pattern[pidx]), idx)
+ if idx < 0 {
+ return -1
+ }
+ if pidx == 0 && idx > 0 {
+ // Step back to find the right bonus point
+ firstIdx = idx - 1
+ }
+ idx++
+ }
+ return firstIdx
+}
+
+func debugV2(T []rune, pattern []rune, F []int32, lastIdx int, H []int16, C []int16) {
+ width := lastIdx - int(F[0]) + 1
+
+ for i, f := range F {
+ I := i * width
+ if i == 0 {
+ fmt.Print(" ")
+ for j := int(f); j <= lastIdx; j++ {
+ fmt.Printf(" " + string(T[j]) + " ")
+ }
+ fmt.Println()
+ }
+ fmt.Print(string(pattern[i]) + " ")
+ for idx := int(F[0]); idx < int(f); idx++ {
+ fmt.Print(" 0 ")
+ }
+ for idx := int(f); idx <= lastIdx; idx++ {
+ fmt.Printf("%2d ", H[i*width+idx-int(F[0])])
+ }
+ fmt.Println()
+
+ fmt.Print(" ")
+ for idx, p := range C[I : I+width] {
+ if idx+int(F[0]) < int(F[i]) {
+ p = 0
+ }
+ if p > 0 {
+ fmt.Printf("%2d ", p)
+ } else {
+ fmt.Print(" ")
+ }
+ }
+ fmt.Println()
+ }
+}
+
+func FuzzyMatchV2(caseSensitive bool, normalize bool, forward bool, input *util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int) {
+ // Assume that pattern is given in lowercase if case-insensitive.
+ // First check if there's a match and calculate bonus for each position.
+ // If the input string is too long, consider finding the matching chars in
+ // this phase as well (non-optimal alignment).
+ M := len(pattern)
+ if M == 0 {
+ return Result{0, 0, 0}, posArray(withPos, M)
+ }
+ N := input.Length()
+
+ // Since O(nm) algorithm can be prohibitively expensive for large input,
+ // we fall back to the greedy algorithm.
+ if slab != nil && N*M > cap(slab.I16) {
+ return FuzzyMatchV1(caseSensitive, normalize, forward, input, pattern, withPos, slab)
+ }
+
+ // Phase 1. Optimized search for ASCII string
+ idx := asciiFuzzyIndex(input, pattern, caseSensitive)
+ if idx < 0 {
+ return Result{-1, -1, 0}, nil
+ }
+
+ // Reuse pre-allocated integer slice to avoid unnecessary sweeping of garbages
+ offset16 := 0
+ offset32 := 0
+ offset16, H0 := alloc16(offset16, slab, N)
+ offset16, C0 := alloc16(offset16, slab, N)
+ // Bonus point for each position
+ offset16, B := alloc16(offset16, slab, N)
+ // The first occurrence of each character in the pattern
+ offset32, F := alloc32(offset32, slab, M)
+ // Rune array
+ _, T := alloc32(offset32, slab, N)
+ input.CopyRunes(T)
+
+ // Phase 2. Calculate bonus for each point
+ maxScore, maxScorePos := int16(0), 0
+ pidx, lastIdx := 0, 0
+ pchar0, pchar, prevH0, prevClass, inGap := pattern[0], pattern[0], int16(0), initialCharClass, false
+ Tsub := T[idx:]
+ H0sub, C0sub, Bsub := H0[idx:][:len(Tsub)], C0[idx:][:len(Tsub)], B[idx:][:len(Tsub)]
+ for off, char := range Tsub {
+ var class charClass
+ if char <= unicode.MaxASCII {
+ class = charClassOfAscii(char)
+ if !caseSensitive && class == charUpper {
+ char += 32
+ }
+ } else {
+ class = charClassOfNonAscii(char)
+ if !caseSensitive && class == charUpper {
+ char = unicode.To(unicode.LowerCase, char)
+ }
+ if normalize {
+ char = normalizeRune(char)
+ }
+ }
+
+ Tsub[off] = char
+ bonus := bonusFor(prevClass, class)
+ Bsub[off] = bonus
+ prevClass = class
+
+ if char == pchar {
+ if pidx < M {
+ F[pidx] = int32(idx + off)
+ pidx++
+ pchar = pattern[util.Min(pidx, M-1)]
+ }
+ lastIdx = idx + off
+ }
+
+ if char == pchar0 {
+ score := scoreMatch + bonus*bonusFirstCharMultiplier
+ H0sub[off] = score
+ C0sub[off] = 1
+ if M == 1 && (forward && score > maxScore || !forward && score >= maxScore) {
+ maxScore, maxScorePos = score, idx+off
+ if forward && bonus >= bonusBoundary {
+ break
+ }
+ }
+ inGap = false
+ } else {
+ if inGap {
+ H0sub[off] = util.Max16(prevH0+scoreGapExtension, 0)
+ } else {
+ H0sub[off] = util.Max16(prevH0+scoreGapStart, 0)
+ }
+ C0sub[off] = 0
+ inGap = true
+ }
+ prevH0 = H0sub[off]
+ }
+ if pidx != M {
+ return Result{-1, -1, 0}, nil
+ }
+ if M == 1 {
+ result := Result{maxScorePos, maxScorePos + 1, int(maxScore)}
+ if !withPos {
+ return result, nil
+ }
+ pos := []int{maxScorePos}
+ return result, &pos
+ }
+
+ // Phase 3. Fill in score matrix (H)
+ // Unlike the original algorithm, we do not allow omission.
+ f0 := int(F[0])
+ width := lastIdx - f0 + 1
+ offset16, H := alloc16(offset16, slab, width*M)
+ copy(H, H0[f0:lastIdx+1])
+
+ // Possible length of consecutive chunk at each position.
+ _, C := alloc16(offset16, slab, width*M)
+ copy(C, C0[f0:lastIdx+1])
+
+ Fsub := F[1:]
+ Psub := pattern[1:][:len(Fsub)]
+ for off, f := range Fsub {
+ f := int(f)
+ pchar := Psub[off]
+ pidx := off + 1
+ row := pidx * width
+ inGap := false
+ Tsub := T[f : lastIdx+1]
+ Bsub := B[f:][:len(Tsub)]
+ Csub := C[row+f-f0:][:len(Tsub)]
+ Cdiag := C[row+f-f0-1-width:][:len(Tsub)]
+ Hsub := H[row+f-f0:][:len(Tsub)]
+ Hdiag := H[row+f-f0-1-width:][:len(Tsub)]
+ Hleft := H[row+f-f0-1:][:len(Tsub)]
+ Hleft[0] = 0
+ for off, char := range Tsub {
+ col := off + f
+ var s1, s2, consecutive int16
+
+ if inGap {
+ s2 = Hleft[off] + scoreGapExtension
+ } else {
+ s2 = Hleft[off] + scoreGapStart
+ }
+
+ if pchar == char {
+ s1 = Hdiag[off] + scoreMatch
+ b := Bsub[off]
+ consecutive = Cdiag[off] + 1
+ if consecutive > 1 {
+ fb := B[col-int(consecutive)+1]
+ // Break consecutive chunk
+ if b >= bonusBoundary && b > fb {
+ consecutive = 1
+ } else {
+ b = util.Max16(b, util.Max16(bonusConsecutive, fb))
+ }
+ }
+ if s1+b < s2 {
+ s1 += Bsub[off]
+ consecutive = 0
+ } else {
+ s1 += b
+ }
+ }
+ Csub[off] = consecutive
+
+ inGap = s1 < s2
+ score := util.Max16(util.Max16(s1, s2), 0)
+ if pidx == M-1 && (forward && score > maxScore || !forward && score >= maxScore) {
+ maxScore, maxScorePos = score, col
+ }
+ Hsub[off] = score
+ }
+ }
+
+ if DEBUG {
+ debugV2(T, pattern, F, lastIdx, H, C)
+ }
+
+ // Phase 4. (Optional) Backtrace to find character positions
+ pos := posArray(withPos, M)
+ j := f0
+ if withPos {
+ i := M - 1
+ j = maxScorePos
+ preferMatch := true
+ for {
+ I := i * width
+ j0 := j - f0
+ s := H[I+j0]
+
+ var s1, s2 int16
+ if i > 0 && j >= int(F[i]) {
+ s1 = H[I-width+j0-1]
+ }
+ if j > int(F[i]) {
+ s2 = H[I+j0-1]
+ }
+
+ if s > s1 && (s > s2 || s == s2 && preferMatch) {
+ *pos = append(*pos, j)
+ if i == 0 {
+ break
+ }
+ i--
+ }
+ preferMatch = C[I+j0] > 1 || I+width+j0+1 < len(C) && C[I+width+j0+1] > 0
+ j--
+ }
+ }
+ // Start offset we return here is only relevant when begin tiebreak is used.
+ // However finding the accurate offset requires backtracking, and we don't
+ // want to pay extra cost for the option that has lost its importance.
+ return Result{j, maxScorePos + 1, int(maxScore)}, pos
+}
+
+// Implement the same sorting criteria as V2
+func calculateScore(caseSensitive bool, normalize bool, text *util.Chars, pattern []rune, sidx int, eidx int, withPos bool) (int, *[]int) {
+ pidx, score, inGap, consecutive, firstBonus := 0, 0, false, 0, int16(0)
+ pos := posArray(withPos, len(pattern))
+ prevClass := charWhite
+ if sidx > 0 {
+ prevClass = charClassOf(text.Get(sidx - 1))
+ }
+ for idx := sidx; idx < eidx; idx++ {
+ char := text.Get(idx)
+ class := charClassOf(char)
+ if !caseSensitive {
+ if char >= 'A' && char <= 'Z' {
+ char += 32
+ } else if char > unicode.MaxASCII {
+ char = unicode.To(unicode.LowerCase, char)
+ }
+ }
+ // pattern is already normalized
+ if normalize {
+ char = normalizeRune(char)
+ }
+ if char == pattern[pidx] {
+ if withPos {
+ *pos = append(*pos, idx)
+ }
+ score += scoreMatch
+ bonus := bonusFor(prevClass, class)
+ if consecutive == 0 {
+ firstBonus = bonus
+ } else {
+ // Break consecutive chunk
+ if bonus >= bonusBoundary && bonus > firstBonus {
+ firstBonus = bonus
+ }
+ bonus = util.Max16(util.Max16(bonus, firstBonus), bonusConsecutive)
+ }
+ if pidx == 0 {
+ score += int(bonus * bonusFirstCharMultiplier)
+ } else {
+ score += int(bonus)
+ }
+ inGap = false
+ consecutive++
+ pidx++
+ } else {
+ if inGap {
+ score += scoreGapExtension
+ } else {
+ score += scoreGapStart
+ }
+ inGap = true
+ consecutive = 0
+ firstBonus = 0
+ }
+ prevClass = class
+ }
+ return score, pos
+}
+
+// FuzzyMatchV1 performs fuzzy-match
+func FuzzyMatchV1(caseSensitive bool, normalize bool, forward bool, text *util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int) {
+ if len(pattern) == 0 {
+ return Result{0, 0, 0}, nil
+ }
+ if asciiFuzzyIndex(text, pattern, caseSensitive) < 0 {
+ return Result{-1, -1, 0}, nil
+ }
+
+ pidx := 0
+ sidx := -1
+ eidx := -1
+
+ lenRunes := text.Length()
+ lenPattern := len(pattern)
+
+ for index := 0; index < lenRunes; index++ {
+ char := text.Get(indexAt(index, lenRunes, forward))
+ // This is considerably faster than blindly applying strings.ToLower to the
+ // whole string
+ if !caseSensitive {
+ // Partially inlining `unicode.ToLower`. Ugly, but makes a noticeable
+ // difference in CPU cost. (Measured on Go 1.4.1. Also note that the Go
+ // compiler as of now does not inline non-leaf functions.)
+ if char >= 'A' && char <= 'Z' {
+ char += 32
+ } else if char > unicode.MaxASCII {
+ char = unicode.To(unicode.LowerCase, char)
+ }
+ }
+ if normalize {
+ char = normalizeRune(char)
+ }
+ pchar := pattern[indexAt(pidx, lenPattern, forward)]
+ if char == pchar {
+ if sidx < 0 {
+ sidx = index
+ }
+ if pidx++; pidx == lenPattern {
+ eidx = index + 1
+ break
+ }
+ }
+ }
+
+ if sidx >= 0 && eidx >= 0 {
+ pidx--
+ for index := eidx - 1; index >= sidx; index-- {
+ tidx := indexAt(index, lenRunes, forward)
+ char := text.Get(tidx)
+ if !caseSensitive {
+ if char >= 'A' && char <= 'Z' {
+ char += 32
+ } else if char > unicode.MaxASCII {
+ char = unicode.To(unicode.LowerCase, char)
+ }
+ }
+
+ pidx_ := indexAt(pidx, lenPattern, forward)
+ pchar := pattern[pidx_]
+ if char == pchar {
+ if pidx--; pidx < 0 {
+ sidx = index
+ break
+ }
+ }
+ }
+
+ if !forward {
+ sidx, eidx = lenRunes-eidx, lenRunes-sidx
+ }
+
+ score, pos := calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, withPos)
+ return Result{sidx, eidx, score}, pos
+ }
+ return Result{-1, -1, 0}, nil
+}
+
+// ExactMatchNaive is a basic string searching algorithm that handles case
+// sensitivity. Although naive, it still performs better than the combination
+// of strings.ToLower + strings.Index for typical fzf use cases where input
+// strings and patterns are not very long.
+//
+// Since 0.15.0, this function searches for the match with the highest
+// bonus point, instead of stopping immediately after finding the first match.
+// The solution is much cheaper since there is only one possible alignment of
+// the pattern.
+func ExactMatchNaive(caseSensitive bool, normalize bool, forward bool, text *util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int) {
+ if len(pattern) == 0 {
+ return Result{0, 0, 0}, nil
+ }
+
+ lenRunes := text.Length()
+ lenPattern := len(pattern)
+
+ if lenRunes < lenPattern {
+ return Result{-1, -1, 0}, nil
+ }
+
+ if asciiFuzzyIndex(text, pattern, caseSensitive) < 0 {
+ return Result{-1, -1, 0}, nil
+ }
+
+ // For simplicity, only look at the bonus at the first character position
+ pidx := 0
+ bestPos, bonus, bestBonus := -1, int16(0), int16(-1)
+ for index := 0; index < lenRunes; index++ {
+ index_ := indexAt(index, lenRunes, forward)
+ char := text.Get(index_)
+ if !caseSensitive {
+ if char >= 'A' && char <= 'Z' {
+ char += 32
+ } else if char > unicode.MaxASCII {
+ char = unicode.To(unicode.LowerCase, char)
+ }
+ }
+ if normalize {
+ char = normalizeRune(char)
+ }
+ pidx_ := indexAt(pidx, lenPattern, forward)
+ pchar := pattern[pidx_]
+ if pchar == char {
+ if pidx_ == 0 {
+ bonus = bonusAt(text, index_)
+ }
+ pidx++
+ if pidx == lenPattern {
+ if bonus > bestBonus {
+ bestPos, bestBonus = index, bonus
+ }
+ if bonus >= bonusBoundary {
+ break
+ }
+ index -= pidx - 1
+ pidx, bonus = 0, 0
+ }
+ } else {
+ index -= pidx
+ pidx, bonus = 0, 0
+ }
+ }
+ if bestPos >= 0 {
+ var sidx, eidx int
+ if forward {
+ sidx = bestPos - lenPattern + 1
+ eidx = bestPos + 1
+ } else {
+ sidx = lenRunes - (bestPos + 1)
+ eidx = lenRunes - (bestPos - lenPattern + 1)
+ }
+ score, _ := calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, false)
+ return Result{sidx, eidx, score}, nil
+ }
+ return Result{-1, -1, 0}, nil
+}
+
+// PrefixMatch performs prefix-match
+func PrefixMatch(caseSensitive bool, normalize bool, forward bool, text *util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int) {
+ if len(pattern) == 0 {
+ return Result{0, 0, 0}, nil
+ }
+
+ trimmedLen := 0
+ if !unicode.IsSpace(pattern[0]) {
+ trimmedLen = text.LeadingWhitespaces()
+ }
+
+ if text.Length()-trimmedLen < len(pattern) {
+ return Result{-1, -1, 0}, nil
+ }
+
+ for index, r := range pattern {
+ char := text.Get(trimmedLen + index)
+ if !caseSensitive {
+ char = unicode.ToLower(char)
+ }
+ if normalize {
+ char = normalizeRune(char)
+ }
+ if char != r {
+ return Result{-1, -1, 0}, nil
+ }
+ }
+ lenPattern := len(pattern)
+ score, _ := calculateScore(caseSensitive, normalize, text, pattern, trimmedLen, trimmedLen+lenPattern, false)
+ return Result{trimmedLen, trimmedLen + lenPattern, score}, nil
+}
+
+// SuffixMatch performs suffix-match
+func SuffixMatch(caseSensitive bool, normalize bool, forward bool, text *util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int) {
+ lenRunes := text.Length()
+ trimmedLen := lenRunes
+ if len(pattern) == 0 || !unicode.IsSpace(pattern[len(pattern)-1]) {
+ trimmedLen -= text.TrailingWhitespaces()
+ }
+ if len(pattern) == 0 {
+ return Result{trimmedLen, trimmedLen, 0}, nil
+ }
+ diff := trimmedLen - len(pattern)
+ if diff < 0 {
+ return Result{-1, -1, 0}, nil
+ }
+
+ for index, r := range pattern {
+ char := text.Get(index + diff)
+ if !caseSensitive {
+ char = unicode.ToLower(char)
+ }
+ if normalize {
+ char = normalizeRune(char)
+ }
+ if char != r {
+ return Result{-1, -1, 0}, nil
+ }
+ }
+ lenPattern := len(pattern)
+ sidx := trimmedLen - lenPattern
+ eidx := trimmedLen
+ score, _ := calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, false)
+ return Result{sidx, eidx, score}, nil
+}
+
+// EqualMatch performs equal-match
+func EqualMatch(caseSensitive bool, normalize bool, forward bool, text *util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int) {
+ lenPattern := len(pattern)
+ if lenPattern == 0 {
+ return Result{-1, -1, 0}, nil
+ }
+
+ // Strip leading whitespaces
+ trimmedLen := 0
+ if !unicode.IsSpace(pattern[0]) {
+ trimmedLen = text.LeadingWhitespaces()
+ }
+
+ // Strip trailing whitespaces
+ trimmedEndLen := 0
+ if !unicode.IsSpace(pattern[lenPattern-1]) {
+ trimmedEndLen = text.TrailingWhitespaces()
+ }
+
+ if text.Length()-trimmedLen-trimmedEndLen != lenPattern {
+ return Result{-1, -1, 0}, nil
+ }
+ match := true
+ if normalize {
+ runes := text.ToRunes()
+ for idx, pchar := range pattern {
+ char := runes[trimmedLen+idx]
+ if !caseSensitive {
+ char = unicode.To(unicode.LowerCase, char)
+ }
+ if normalizeRune(pchar) != normalizeRune(char) {
+ match = false
+ break
+ }
+ }
+ } else {
+ runes := text.ToRunes()
+ runesStr := string(runes[trimmedLen : len(runes)-trimmedEndLen])
+ if !caseSensitive {
+ runesStr = strings.ToLower(runesStr)
+ }
+ match = runesStr == string(pattern)
+ }
+ if match {
+ return Result{trimmedLen, trimmedLen + lenPattern, (scoreMatch+int(bonusBoundaryWhite))*lenPattern +
+ (bonusFirstCharMultiplier-1)*int(bonusBoundaryWhite)}, nil
+ }
+ return Result{-1, -1, 0}, nil
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/algo/algo_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/algo/algo_test.go
new file mode 100644
index 00000000..a7c4e1d3
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/algo/algo_test.go
@@ -0,0 +1,198 @@
+package algo
+
+import (
+ "math"
+ "sort"
+ "strings"
+ "testing"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+func assertMatch(t *testing.T, fun Algo, caseSensitive, forward bool, input, pattern string, sidx int, eidx int, score int) {
+ assertMatch2(t, fun, caseSensitive, false, forward, input, pattern, sidx, eidx, score)
+}
+
+func assertMatch2(t *testing.T, fun Algo, caseSensitive, normalize, forward bool, input, pattern string, sidx int, eidx int, score int) {
+ if !caseSensitive {
+ pattern = strings.ToLower(pattern)
+ }
+ chars := util.ToChars([]byte(input))
+ res, pos := fun(caseSensitive, normalize, forward, &chars, []rune(pattern), true, nil)
+ var start, end int
+ if pos == nil || len(*pos) == 0 {
+ start = res.Start
+ end = res.End
+ } else {
+ sort.Ints(*pos)
+ start = (*pos)[0]
+ end = (*pos)[len(*pos)-1] + 1
+ }
+ if start != sidx {
+ t.Errorf("Invalid start index: %d (expected: %d, %s / %s)", start, sidx, input, pattern)
+ }
+ if end != eidx {
+ t.Errorf("Invalid end index: %d (expected: %d, %s / %s)", end, eidx, input, pattern)
+ }
+ if res.Score != score {
+ t.Errorf("Invalid score: %d (expected: %d, %s / %s)", res.Score, score, input, pattern)
+ }
+}
+
+func TestFuzzyMatch(t *testing.T) {
+ for _, fn := range []Algo{FuzzyMatchV1, FuzzyMatchV2} {
+ for _, forward := range []bool{true, false} {
+ assertMatch(t, fn, false, forward, "fooBarbaz1", "oBZ", 2, 9,
+ scoreMatch*3+bonusCamel123+scoreGapStart+scoreGapExtension*3)
+ assertMatch(t, fn, false, forward, "foo bar baz", "fbb", 0, 9,
+ scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+
+ int(bonusBoundaryWhite)*2+2*scoreGapStart+4*scoreGapExtension)
+ assertMatch(t, fn, false, forward, "/AutomatorDocument.icns", "rdoc", 9, 13,
+ scoreMatch*4+bonusCamel123+bonusConsecutive*2)
+ assertMatch(t, fn, false, forward, "/man1/zshcompctl.1", "zshc", 6, 10,
+ scoreMatch*4+int(bonusBoundaryDelimiter)*bonusFirstCharMultiplier+int(bonusBoundaryDelimiter)*3)
+ assertMatch(t, fn, false, forward, "/.oh-my-zsh/cache", "zshc", 8, 13,
+ scoreMatch*4+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary*2+scoreGapStart+int(bonusBoundaryDelimiter))
+ assertMatch(t, fn, false, forward, "ab0123 456", "12356", 3, 10,
+ scoreMatch*5+bonusConsecutive*3+scoreGapStart+scoreGapExtension)
+ assertMatch(t, fn, false, forward, "abc123 456", "12356", 3, 10,
+ scoreMatch*5+bonusCamel123*bonusFirstCharMultiplier+bonusCamel123*2+bonusConsecutive+scoreGapStart+scoreGapExtension)
+ assertMatch(t, fn, false, forward, "foo/bar/baz", "fbb", 0, 9,
+ scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+
+ int(bonusBoundaryDelimiter)*2+2*scoreGapStart+4*scoreGapExtension)
+ assertMatch(t, fn, false, forward, "fooBarBaz", "fbb", 0, 7,
+ scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+
+ bonusCamel123*2+2*scoreGapStart+2*scoreGapExtension)
+ assertMatch(t, fn, false, forward, "foo barbaz", "fbb", 0, 8,
+ scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryWhite)+
+ scoreGapStart*2+scoreGapExtension*3)
+ assertMatch(t, fn, false, forward, "fooBar Baz", "foob", 0, 4,
+ scoreMatch*4+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryWhite)*3)
+ assertMatch(t, fn, false, forward, "xFoo-Bar Baz", "foo-b", 1, 6,
+ scoreMatch*5+bonusCamel123*bonusFirstCharMultiplier+bonusCamel123*2+
+ bonusNonWord+bonusBoundary)
+
+ assertMatch(t, fn, true, forward, "fooBarbaz", "oBz", 2, 9,
+ scoreMatch*3+bonusCamel123+scoreGapStart+scoreGapExtension*3)
+ assertMatch(t, fn, true, forward, "Foo/Bar/Baz", "FBB", 0, 9,
+ scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryDelimiter)*2+
+ scoreGapStart*2+scoreGapExtension*4)
+ assertMatch(t, fn, true, forward, "FooBarBaz", "FBB", 0, 7,
+ scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+bonusCamel123*2+
+ scoreGapStart*2+scoreGapExtension*2)
+ assertMatch(t, fn, true, forward, "FooBar Baz", "FooB", 0, 4,
+ scoreMatch*4+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryWhite)*2+
+ util.Max(bonusCamel123, int(bonusBoundaryWhite)))
+
+ // Consecutive bonus updated
+ assertMatch(t, fn, true, forward, "foo-bar", "o-ba", 2, 6,
+ scoreMatch*4+bonusBoundary*3)
+
+ // Non-match
+ assertMatch(t, fn, true, forward, "fooBarbaz", "oBZ", -1, -1, 0)
+ assertMatch(t, fn, true, forward, "Foo Bar Baz", "fbb", -1, -1, 0)
+ assertMatch(t, fn, true, forward, "fooBarbaz", "fooBarbazz", -1, -1, 0)
+ }
+ }
+}
+
+func TestFuzzyMatchBackward(t *testing.T) {
+ assertMatch(t, FuzzyMatchV1, false, true, "foobar fb", "fb", 0, 4,
+ scoreMatch*2+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+
+ scoreGapStart+scoreGapExtension)
+ assertMatch(t, FuzzyMatchV1, false, false, "foobar fb", "fb", 7, 9,
+ scoreMatch*2+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryWhite))
+}
+
+func TestExactMatchNaive(t *testing.T) {
+ for _, dir := range []bool{true, false} {
+ assertMatch(t, ExactMatchNaive, true, dir, "fooBarbaz", "oBA", -1, -1, 0)
+ assertMatch(t, ExactMatchNaive, true, dir, "fooBarbaz", "fooBarbazz", -1, -1, 0)
+
+ assertMatch(t, ExactMatchNaive, false, dir, "fooBarbaz", "oBA", 2, 5,
+ scoreMatch*3+bonusCamel123+bonusConsecutive)
+ assertMatch(t, ExactMatchNaive, false, dir, "/AutomatorDocument.icns", "rdoc", 9, 13,
+ scoreMatch*4+bonusCamel123+bonusConsecutive*2)
+ assertMatch(t, ExactMatchNaive, false, dir, "/man1/zshcompctl.1", "zshc", 6, 10,
+ scoreMatch*4+int(bonusBoundaryDelimiter)*(bonusFirstCharMultiplier+3))
+ assertMatch(t, ExactMatchNaive, false, dir, "/.oh-my-zsh/cache", "zsh/c", 8, 13,
+ scoreMatch*5+bonusBoundary*(bonusFirstCharMultiplier+3)+int(bonusBoundaryDelimiter))
+ }
+}
+
+func TestExactMatchNaiveBackward(t *testing.T) {
+ assertMatch(t, ExactMatchNaive, false, true, "foobar foob", "oo", 1, 3,
+ scoreMatch*2+bonusConsecutive)
+ assertMatch(t, ExactMatchNaive, false, false, "foobar foob", "oo", 8, 10,
+ scoreMatch*2+bonusConsecutive)
+}
+
+func TestPrefixMatch(t *testing.T) {
+ score := scoreMatch*3 + int(bonusBoundaryWhite)*bonusFirstCharMultiplier + int(bonusBoundaryWhite)*2
+
+ for _, dir := range []bool{true, false} {
+ assertMatch(t, PrefixMatch, true, dir, "fooBarbaz", "Foo", -1, -1, 0)
+ assertMatch(t, PrefixMatch, false, dir, "fooBarBaz", "baz", -1, -1, 0)
+ assertMatch(t, PrefixMatch, false, dir, "fooBarbaz", "Foo", 0, 3, score)
+ assertMatch(t, PrefixMatch, false, dir, "foOBarBaZ", "foo", 0, 3, score)
+ assertMatch(t, PrefixMatch, false, dir, "f-oBarbaz", "f-o", 0, 3, score)
+
+ assertMatch(t, PrefixMatch, false, dir, " fooBar", "foo", 1, 4, score)
+ assertMatch(t, PrefixMatch, false, dir, " fooBar", " fo", 0, 3, score)
+ assertMatch(t, PrefixMatch, false, dir, " fo", "foo", -1, -1, 0)
+ }
+}
+
+func TestSuffixMatch(t *testing.T) {
+ for _, dir := range []bool{true, false} {
+ assertMatch(t, SuffixMatch, true, dir, "fooBarbaz", "Baz", -1, -1, 0)
+ assertMatch(t, SuffixMatch, false, dir, "fooBarbaz", "Foo", -1, -1, 0)
+
+ assertMatch(t, SuffixMatch, false, dir, "fooBarbaz", "baz", 6, 9,
+ scoreMatch*3+bonusConsecutive*2)
+ assertMatch(t, SuffixMatch, false, dir, "fooBarBaZ", "baz", 6, 9,
+ (scoreMatch+bonusCamel123)*3+bonusCamel123*(bonusFirstCharMultiplier-1))
+
+ // Strip trailing white space from the string
+ assertMatch(t, SuffixMatch, false, dir, "fooBarbaz ", "baz", 6, 9,
+ scoreMatch*3+bonusConsecutive*2)
+
+ // Only when the pattern doesn't end with a space
+ assertMatch(t, SuffixMatch, false, dir, "fooBarbaz ", "baz ", 6, 10,
+ scoreMatch*4+bonusConsecutive*2+int(bonusBoundaryWhite))
+ }
+}
+
+func TestEmptyPattern(t *testing.T) {
+ for _, dir := range []bool{true, false} {
+ assertMatch(t, FuzzyMatchV1, true, dir, "foobar", "", 0, 0, 0)
+ assertMatch(t, FuzzyMatchV2, true, dir, "foobar", "", 0, 0, 0)
+ assertMatch(t, ExactMatchNaive, true, dir, "foobar", "", 0, 0, 0)
+ assertMatch(t, PrefixMatch, true, dir, "foobar", "", 0, 0, 0)
+ assertMatch(t, SuffixMatch, true, dir, "foobar", "", 6, 6, 0)
+ }
+}
+
+func TestNormalize(t *testing.T) {
+ caseSensitive := false
+ normalize := true
+ forward := true
+ test := func(input, pattern string, sidx, eidx, score int, funs ...Algo) {
+ for _, fun := range funs {
+ assertMatch2(t, fun, caseSensitive, normalize, forward,
+ input, pattern, sidx, eidx, score)
+ }
+ }
+ test("Só Danço Samba", "So", 0, 2, 62, FuzzyMatchV1, FuzzyMatchV2, PrefixMatch, ExactMatchNaive)
+ test("Só Danço Samba", "sodc", 0, 7, 97, FuzzyMatchV1, FuzzyMatchV2)
+ test("Danço", "danco", 0, 5, 140, FuzzyMatchV1, FuzzyMatchV2, PrefixMatch, SuffixMatch, ExactMatchNaive, EqualMatch)
+}
+
+func TestLongString(t *testing.T) {
+ bytes := make([]byte, math.MaxUint16*2)
+ for i := range bytes {
+ bytes[i] = 'x'
+ }
+ bytes[math.MaxUint16] = 'z'
+ assertMatch(t, FuzzyMatchV2, true, true, string(bytes), "zx", math.MaxUint16, math.MaxUint16+2, scoreMatch*2+bonusConsecutive)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/algo/normalize.go b/dot-oh-my-zsh/custom/plugins/fzf/src/algo/normalize.go
new file mode 100644
index 00000000..93247908
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/algo/normalize.go
@@ -0,0 +1,492 @@
+// Normalization of latin script letters
+// Reference: http://www.unicode.org/Public/UCD/latest/ucd/Index.txt
+
+package algo
+
+var normalized map[rune]rune = map[rune]rune{
+ 0x00E1: 'a', // WITH ACUTE, LATIN SMALL LETTER
+ 0x0103: 'a', // WITH BREVE, LATIN SMALL LETTER
+ 0x01CE: 'a', // WITH CARON, LATIN SMALL LETTER
+ 0x00E2: 'a', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x00E4: 'a', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x0227: 'a', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1EA1: 'a', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0201: 'a', // WITH DOUBLE GRAVE, LATIN SMALL LETTER
+ 0x00E0: 'a', // WITH GRAVE, LATIN SMALL LETTER
+ 0x1EA3: 'a', // WITH HOOK ABOVE, LATIN SMALL LETTER
+ 0x0203: 'a', // WITH INVERTED BREVE, LATIN SMALL LETTER
+ 0x0101: 'a', // WITH MACRON, LATIN SMALL LETTER
+ 0x0105: 'a', // WITH OGONEK, LATIN SMALL LETTER
+ 0x1E9A: 'a', // WITH RIGHT HALF RING, LATIN SMALL LETTER
+ 0x00E5: 'a', // WITH RING ABOVE, LATIN SMALL LETTER
+ 0x1E01: 'a', // WITH RING BELOW, LATIN SMALL LETTER
+ 0x00E3: 'a', // WITH TILDE, LATIN SMALL LETTER
+ 0x0363: 'a', // , COMBINING LATIN SMALL LETTER
+ 0x0250: 'a', // , LATIN SMALL LETTER TURNED
+ 0x1E03: 'b', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E05: 'b', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0253: 'b', // WITH HOOK, LATIN SMALL LETTER
+ 0x1E07: 'b', // WITH LINE BELOW, LATIN SMALL LETTER
+ 0x0180: 'b', // WITH STROKE, LATIN SMALL LETTER
+ 0x0183: 'b', // WITH TOPBAR, LATIN SMALL LETTER
+ 0x0107: 'c', // WITH ACUTE, LATIN SMALL LETTER
+ 0x010D: 'c', // WITH CARON, LATIN SMALL LETTER
+ 0x00E7: 'c', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x0109: 'c', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x0255: 'c', // WITH CURL, LATIN SMALL LETTER
+ 0x010B: 'c', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x0188: 'c', // WITH HOOK, LATIN SMALL LETTER
+ 0x023C: 'c', // WITH STROKE, LATIN SMALL LETTER
+ 0x0368: 'c', // , COMBINING LATIN SMALL LETTER
+ 0x0297: 'c', // , LATIN LETTER STRETCHED
+ 0x2184: 'c', // , LATIN SMALL LETTER REVERSED
+ 0x010F: 'd', // WITH CARON, LATIN SMALL LETTER
+ 0x1E11: 'd', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x1E13: 'd', // WITH CIRCUMFLEX BELOW, LATIN SMALL LETTER
+ 0x0221: 'd', // WITH CURL, LATIN SMALL LETTER
+ 0x1E0B: 'd', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E0D: 'd', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0257: 'd', // WITH HOOK, LATIN SMALL LETTER
+ 0x1E0F: 'd', // WITH LINE BELOW, LATIN SMALL LETTER
+ 0x0111: 'd', // WITH STROKE, LATIN SMALL LETTER
+ 0x0256: 'd', // WITH TAIL, LATIN SMALL LETTER
+ 0x018C: 'd', // WITH TOPBAR, LATIN SMALL LETTER
+ 0x0369: 'd', // , COMBINING LATIN SMALL LETTER
+ 0x00E9: 'e', // WITH ACUTE, LATIN SMALL LETTER
+ 0x0115: 'e', // WITH BREVE, LATIN SMALL LETTER
+ 0x011B: 'e', // WITH CARON, LATIN SMALL LETTER
+ 0x0229: 'e', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x1E19: 'e', // WITH CIRCUMFLEX BELOW, LATIN SMALL LETTER
+ 0x00EA: 'e', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x00EB: 'e', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x0117: 'e', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1EB9: 'e', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0205: 'e', // WITH DOUBLE GRAVE, LATIN SMALL LETTER
+ 0x00E8: 'e', // WITH GRAVE, LATIN SMALL LETTER
+ 0x1EBB: 'e', // WITH HOOK ABOVE, LATIN SMALL LETTER
+ 0x025D: 'e', // WITH HOOK, LATIN SMALL LETTER REVERSED OPEN
+ 0x0207: 'e', // WITH INVERTED BREVE, LATIN SMALL LETTER
+ 0x0113: 'e', // WITH MACRON, LATIN SMALL LETTER
+ 0x0119: 'e', // WITH OGONEK, LATIN SMALL LETTER
+ 0x0247: 'e', // WITH STROKE, LATIN SMALL LETTER
+ 0x1E1B: 'e', // WITH TILDE BELOW, LATIN SMALL LETTER
+ 0x1EBD: 'e', // WITH TILDE, LATIN SMALL LETTER
+ 0x0364: 'e', // , COMBINING LATIN SMALL LETTER
+ 0x029A: 'e', // , LATIN SMALL LETTER CLOSED OPEN
+ 0x025E: 'e', // , LATIN SMALL LETTER CLOSED REVERSED OPEN
+ 0x025B: 'e', // , LATIN SMALL LETTER OPEN
+ 0x0258: 'e', // , LATIN SMALL LETTER REVERSED
+ 0x025C: 'e', // , LATIN SMALL LETTER REVERSED OPEN
+ 0x01DD: 'e', // , LATIN SMALL LETTER TURNED
+ 0x1D08: 'e', // , LATIN SMALL LETTER TURNED OPEN
+ 0x1E1F: 'f', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x0192: 'f', // WITH HOOK, LATIN SMALL LETTER
+ 0x01F5: 'g', // WITH ACUTE, LATIN SMALL LETTER
+ 0x011F: 'g', // WITH BREVE, LATIN SMALL LETTER
+ 0x01E7: 'g', // WITH CARON, LATIN SMALL LETTER
+ 0x0123: 'g', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x011D: 'g', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x0121: 'g', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x0260: 'g', // WITH HOOK, LATIN SMALL LETTER
+ 0x1E21: 'g', // WITH MACRON, LATIN SMALL LETTER
+ 0x01E5: 'g', // WITH STROKE, LATIN SMALL LETTER
+ 0x0261: 'g', // , LATIN SMALL LETTER SCRIPT
+ 0x1E2B: 'h', // WITH BREVE BELOW, LATIN SMALL LETTER
+ 0x021F: 'h', // WITH CARON, LATIN SMALL LETTER
+ 0x1E29: 'h', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x0125: 'h', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x1E27: 'h', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x1E23: 'h', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E25: 'h', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x02AE: 'h', // WITH FISHHOOK, LATIN SMALL LETTER TURNED
+ 0x0266: 'h', // WITH HOOK, LATIN SMALL LETTER
+ 0x1E96: 'h', // WITH LINE BELOW, LATIN SMALL LETTER
+ 0x0127: 'h', // WITH STROKE, LATIN SMALL LETTER
+ 0x036A: 'h', // , COMBINING LATIN SMALL LETTER
+ 0x0265: 'h', // , LATIN SMALL LETTER TURNED
+ 0x2095: 'h', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x00ED: 'i', // WITH ACUTE, LATIN SMALL LETTER
+ 0x012D: 'i', // WITH BREVE, LATIN SMALL LETTER
+ 0x01D0: 'i', // WITH CARON, LATIN SMALL LETTER
+ 0x00EE: 'i', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x00EF: 'i', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x1ECB: 'i', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0209: 'i', // WITH DOUBLE GRAVE, LATIN SMALL LETTER
+ 0x00EC: 'i', // WITH GRAVE, LATIN SMALL LETTER
+ 0x1EC9: 'i', // WITH HOOK ABOVE, LATIN SMALL LETTER
+ 0x020B: 'i', // WITH INVERTED BREVE, LATIN SMALL LETTER
+ 0x012B: 'i', // WITH MACRON, LATIN SMALL LETTER
+ 0x012F: 'i', // WITH OGONEK, LATIN SMALL LETTER
+ 0x0268: 'i', // WITH STROKE, LATIN SMALL LETTER
+ 0x1E2D: 'i', // WITH TILDE BELOW, LATIN SMALL LETTER
+ 0x0129: 'i', // WITH TILDE, LATIN SMALL LETTER
+ 0x0365: 'i', // , COMBINING LATIN SMALL LETTER
+ 0x0131: 'i', // , LATIN SMALL LETTER DOTLESS
+ 0x1D09: 'i', // , LATIN SMALL LETTER TURNED
+ 0x1D62: 'i', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x2071: 'i', // , SUPERSCRIPT LATIN SMALL LETTER
+ 0x01F0: 'j', // WITH CARON, LATIN SMALL LETTER
+ 0x0135: 'j', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x029D: 'j', // WITH CROSSED-TAIL, LATIN SMALL LETTER
+ 0x0249: 'j', // WITH STROKE, LATIN SMALL LETTER
+ 0x025F: 'j', // WITH STROKE, LATIN SMALL LETTER DOTLESS
+ 0x0237: 'j', // , LATIN SMALL LETTER DOTLESS
+ 0x1E31: 'k', // WITH ACUTE, LATIN SMALL LETTER
+ 0x01E9: 'k', // WITH CARON, LATIN SMALL LETTER
+ 0x0137: 'k', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x1E33: 'k', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0199: 'k', // WITH HOOK, LATIN SMALL LETTER
+ 0x1E35: 'k', // WITH LINE BELOW, LATIN SMALL LETTER
+ 0x029E: 'k', // , LATIN SMALL LETTER TURNED
+ 0x2096: 'k', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x013A: 'l', // WITH ACUTE, LATIN SMALL LETTER
+ 0x019A: 'l', // WITH BAR, LATIN SMALL LETTER
+ 0x026C: 'l', // WITH BELT, LATIN SMALL LETTER
+ 0x013E: 'l', // WITH CARON, LATIN SMALL LETTER
+ 0x013C: 'l', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x1E3D: 'l', // WITH CIRCUMFLEX BELOW, LATIN SMALL LETTER
+ 0x0234: 'l', // WITH CURL, LATIN SMALL LETTER
+ 0x1E37: 'l', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x1E3B: 'l', // WITH LINE BELOW, LATIN SMALL LETTER
+ 0x0140: 'l', // WITH MIDDLE DOT, LATIN SMALL LETTER
+ 0x026B: 'l', // WITH MIDDLE TILDE, LATIN SMALL LETTER
+ 0x026D: 'l', // WITH RETROFLEX HOOK, LATIN SMALL LETTER
+ 0x0142: 'l', // WITH STROKE, LATIN SMALL LETTER
+ 0x2097: 'l', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x1E3F: 'm', // WITH ACUTE, LATIN SMALL LETTER
+ 0x1E41: 'm', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E43: 'm', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0271: 'm', // WITH HOOK, LATIN SMALL LETTER
+ 0x0270: 'm', // WITH LONG LEG, LATIN SMALL LETTER TURNED
+ 0x036B: 'm', // , COMBINING LATIN SMALL LETTER
+ 0x1D1F: 'm', // , LATIN SMALL LETTER SIDEWAYS TURNED
+ 0x026F: 'm', // , LATIN SMALL LETTER TURNED
+ 0x2098: 'm', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x0144: 'n', // WITH ACUTE, LATIN SMALL LETTER
+ 0x0148: 'n', // WITH CARON, LATIN SMALL LETTER
+ 0x0146: 'n', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x1E4B: 'n', // WITH CIRCUMFLEX BELOW, LATIN SMALL LETTER
+ 0x0235: 'n', // WITH CURL, LATIN SMALL LETTER
+ 0x1E45: 'n', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E47: 'n', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x01F9: 'n', // WITH GRAVE, LATIN SMALL LETTER
+ 0x0272: 'n', // WITH LEFT HOOK, LATIN SMALL LETTER
+ 0x1E49: 'n', // WITH LINE BELOW, LATIN SMALL LETTER
+ 0x019E: 'n', // WITH LONG RIGHT LEG, LATIN SMALL LETTER
+ 0x0273: 'n', // WITH RETROFLEX HOOK, LATIN SMALL LETTER
+ 0x00F1: 'n', // WITH TILDE, LATIN SMALL LETTER
+ 0x2099: 'n', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x00F3: 'o', // WITH ACUTE, LATIN SMALL LETTER
+ 0x014F: 'o', // WITH BREVE, LATIN SMALL LETTER
+ 0x01D2: 'o', // WITH CARON, LATIN SMALL LETTER
+ 0x00F4: 'o', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x00F6: 'o', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x022F: 'o', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1ECD: 'o', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0151: 'o', // WITH DOUBLE ACUTE, LATIN SMALL LETTER
+ 0x020D: 'o', // WITH DOUBLE GRAVE, LATIN SMALL LETTER
+ 0x00F2: 'o', // WITH GRAVE, LATIN SMALL LETTER
+ 0x1ECF: 'o', // WITH HOOK ABOVE, LATIN SMALL LETTER
+ 0x01A1: 'o', // WITH HORN, LATIN SMALL LETTER
+ 0x020F: 'o', // WITH INVERTED BREVE, LATIN SMALL LETTER
+ 0x014D: 'o', // WITH MACRON, LATIN SMALL LETTER
+ 0x01EB: 'o', // WITH OGONEK, LATIN SMALL LETTER
+ 0x00F8: 'o', // WITH STROKE, LATIN SMALL LETTER
+ 0x1D13: 'o', // WITH STROKE, LATIN SMALL LETTER SIDEWAYS
+ 0x00F5: 'o', // WITH TILDE, LATIN SMALL LETTER
+ 0x0366: 'o', // , COMBINING LATIN SMALL LETTER
+ 0x0275: 'o', // , LATIN SMALL LETTER BARRED
+ 0x1D17: 'o', // , LATIN SMALL LETTER BOTTOM HALF
+ 0x0254: 'o', // , LATIN SMALL LETTER OPEN
+ 0x1D11: 'o', // , LATIN SMALL LETTER SIDEWAYS
+ 0x1D12: 'o', // , LATIN SMALL LETTER SIDEWAYS OPEN
+ 0x1D16: 'o', // , LATIN SMALL LETTER TOP HALF
+ 0x1E55: 'p', // WITH ACUTE, LATIN SMALL LETTER
+ 0x1E57: 'p', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x01A5: 'p', // WITH HOOK, LATIN SMALL LETTER
+ 0x209A: 'p', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x024B: 'q', // WITH HOOK TAIL, LATIN SMALL LETTER
+ 0x02A0: 'q', // WITH HOOK, LATIN SMALL LETTER
+ 0x0155: 'r', // WITH ACUTE, LATIN SMALL LETTER
+ 0x0159: 'r', // WITH CARON, LATIN SMALL LETTER
+ 0x0157: 'r', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x1E59: 'r', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E5B: 'r', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0211: 'r', // WITH DOUBLE GRAVE, LATIN SMALL LETTER
+ 0x027E: 'r', // WITH FISHHOOK, LATIN SMALL LETTER
+ 0x027F: 'r', // WITH FISHHOOK, LATIN SMALL LETTER REVERSED
+ 0x027B: 'r', // WITH HOOK, LATIN SMALL LETTER TURNED
+ 0x0213: 'r', // WITH INVERTED BREVE, LATIN SMALL LETTER
+ 0x1E5F: 'r', // WITH LINE BELOW, LATIN SMALL LETTER
+ 0x027C: 'r', // WITH LONG LEG, LATIN SMALL LETTER
+ 0x027A: 'r', // WITH LONG LEG, LATIN SMALL LETTER TURNED
+ 0x024D: 'r', // WITH STROKE, LATIN SMALL LETTER
+ 0x027D: 'r', // WITH TAIL, LATIN SMALL LETTER
+ 0x036C: 'r', // , COMBINING LATIN SMALL LETTER
+ 0x0279: 'r', // , LATIN SMALL LETTER TURNED
+ 0x1D63: 'r', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x015B: 's', // WITH ACUTE, LATIN SMALL LETTER
+ 0x0161: 's', // WITH CARON, LATIN SMALL LETTER
+ 0x015F: 's', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x015D: 's', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x0219: 's', // WITH COMMA BELOW, LATIN SMALL LETTER
+ 0x1E61: 's', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E9B: 's', // WITH DOT ABOVE, LATIN SMALL LETTER LONG
+ 0x1E63: 's', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0282: 's', // WITH HOOK, LATIN SMALL LETTER
+ 0x023F: 's', // WITH SWASH TAIL, LATIN SMALL LETTER
+ 0x017F: 's', // , LATIN SMALL LETTER LONG
+ 0x00DF: 's', // , LATIN SMALL LETTER SHARP
+ 0x209B: 's', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x0165: 't', // WITH CARON, LATIN SMALL LETTER
+ 0x0163: 't', // WITH CEDILLA, LATIN SMALL LETTER
+ 0x1E71: 't', // WITH CIRCUMFLEX BELOW, LATIN SMALL LETTER
+ 0x021B: 't', // WITH COMMA BELOW, LATIN SMALL LETTER
+ 0x0236: 't', // WITH CURL, LATIN SMALL LETTER
+ 0x1E97: 't', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x1E6B: 't', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E6D: 't', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x01AD: 't', // WITH HOOK, LATIN SMALL LETTER
+ 0x1E6F: 't', // WITH LINE BELOW, LATIN SMALL LETTER
+ 0x01AB: 't', // WITH PALATAL HOOK, LATIN SMALL LETTER
+ 0x0288: 't', // WITH RETROFLEX HOOK, LATIN SMALL LETTER
+ 0x0167: 't', // WITH STROKE, LATIN SMALL LETTER
+ 0x036D: 't', // , COMBINING LATIN SMALL LETTER
+ 0x0287: 't', // , LATIN SMALL LETTER TURNED
+ 0x209C: 't', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x0289: 'u', // BAR, LATIN SMALL LETTER
+ 0x00FA: 'u', // WITH ACUTE, LATIN SMALL LETTER
+ 0x016D: 'u', // WITH BREVE, LATIN SMALL LETTER
+ 0x01D4: 'u', // WITH CARON, LATIN SMALL LETTER
+ 0x1E77: 'u', // WITH CIRCUMFLEX BELOW, LATIN SMALL LETTER
+ 0x00FB: 'u', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x1E73: 'u', // WITH DIAERESIS BELOW, LATIN SMALL LETTER
+ 0x00FC: 'u', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x1EE5: 'u', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0171: 'u', // WITH DOUBLE ACUTE, LATIN SMALL LETTER
+ 0x0215: 'u', // WITH DOUBLE GRAVE, LATIN SMALL LETTER
+ 0x00F9: 'u', // WITH GRAVE, LATIN SMALL LETTER
+ 0x1EE7: 'u', // WITH HOOK ABOVE, LATIN SMALL LETTER
+ 0x01B0: 'u', // WITH HORN, LATIN SMALL LETTER
+ 0x0217: 'u', // WITH INVERTED BREVE, LATIN SMALL LETTER
+ 0x016B: 'u', // WITH MACRON, LATIN SMALL LETTER
+ 0x0173: 'u', // WITH OGONEK, LATIN SMALL LETTER
+ 0x016F: 'u', // WITH RING ABOVE, LATIN SMALL LETTER
+ 0x1E75: 'u', // WITH TILDE BELOW, LATIN SMALL LETTER
+ 0x0169: 'u', // WITH TILDE, LATIN SMALL LETTER
+ 0x0367: 'u', // , COMBINING LATIN SMALL LETTER
+ 0x1D1D: 'u', // , LATIN SMALL LETTER SIDEWAYS
+ 0x1D1E: 'u', // , LATIN SMALL LETTER SIDEWAYS DIAERESIZED
+ 0x1D64: 'u', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x1E7F: 'v', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x028B: 'v', // WITH HOOK, LATIN SMALL LETTER
+ 0x1E7D: 'v', // WITH TILDE, LATIN SMALL LETTER
+ 0x036E: 'v', // , COMBINING LATIN SMALL LETTER
+ 0x028C: 'v', // , LATIN SMALL LETTER TURNED
+ 0x1D65: 'v', // , LATIN SUBSCRIPT SMALL LETTER
+ 0x1E83: 'w', // WITH ACUTE, LATIN SMALL LETTER
+ 0x0175: 'w', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x1E85: 'w', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x1E87: 'w', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E89: 'w', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x1E81: 'w', // WITH GRAVE, LATIN SMALL LETTER
+ 0x1E98: 'w', // WITH RING ABOVE, LATIN SMALL LETTER
+ 0x028D: 'w', // , LATIN SMALL LETTER TURNED
+ 0x1E8D: 'x', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x1E8B: 'x', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x036F: 'x', // , COMBINING LATIN SMALL LETTER
+ 0x00FD: 'y', // WITH ACUTE, LATIN SMALL LETTER
+ 0x0177: 'y', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x00FF: 'y', // WITH DIAERESIS, LATIN SMALL LETTER
+ 0x1E8F: 'y', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1EF5: 'y', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x1EF3: 'y', // WITH GRAVE, LATIN SMALL LETTER
+ 0x1EF7: 'y', // WITH HOOK ABOVE, LATIN SMALL LETTER
+ 0x01B4: 'y', // WITH HOOK, LATIN SMALL LETTER
+ 0x0233: 'y', // WITH MACRON, LATIN SMALL LETTER
+ 0x1E99: 'y', // WITH RING ABOVE, LATIN SMALL LETTER
+ 0x024F: 'y', // WITH STROKE, LATIN SMALL LETTER
+ 0x1EF9: 'y', // WITH TILDE, LATIN SMALL LETTER
+ 0x028E: 'y', // , LATIN SMALL LETTER TURNED
+ 0x017A: 'z', // WITH ACUTE, LATIN SMALL LETTER
+ 0x017E: 'z', // WITH CARON, LATIN SMALL LETTER
+ 0x1E91: 'z', // WITH CIRCUMFLEX, LATIN SMALL LETTER
+ 0x0291: 'z', // WITH CURL, LATIN SMALL LETTER
+ 0x017C: 'z', // WITH DOT ABOVE, LATIN SMALL LETTER
+ 0x1E93: 'z', // WITH DOT BELOW, LATIN SMALL LETTER
+ 0x0225: 'z', // WITH HOOK, LATIN SMALL LETTER
+ 0x1E95: 'z', // WITH LINE BELOW, LATIN SMALL LETTER
+ 0x0290: 'z', // WITH RETROFLEX HOOK, LATIN SMALL LETTER
+ 0x01B6: 'z', // WITH STROKE, LATIN SMALL LETTER
+ 0x0240: 'z', // WITH SWASH TAIL, LATIN SMALL LETTER
+ 0x0251: 'a', // , latin small letter script
+ 0x00C1: 'A', // WITH ACUTE, LATIN CAPITAL LETTER
+ 0x00C2: 'A', // WITH CIRCUMFLEX, LATIN CAPITAL LETTER
+ 0x00C4: 'A', // WITH DIAERESIS, LATIN CAPITAL LETTER
+ 0x00C0: 'A', // WITH GRAVE, LATIN CAPITAL LETTER
+ 0x00C5: 'A', // WITH RING ABOVE, LATIN CAPITAL LETTER
+ 0x023A: 'A', // WITH STROKE, LATIN CAPITAL LETTER
+ 0x00C3: 'A', // WITH TILDE, LATIN CAPITAL LETTER
+ 0x1D00: 'A', // , LATIN LETTER SMALL CAPITAL
+ 0x0181: 'B', // WITH HOOK, LATIN CAPITAL LETTER
+ 0x0243: 'B', // WITH STROKE, LATIN CAPITAL LETTER
+ 0x0299: 'B', // , LATIN LETTER SMALL CAPITAL
+ 0x1D03: 'B', // , LATIN LETTER SMALL CAPITAL BARRED
+ 0x00C7: 'C', // WITH CEDILLA, LATIN CAPITAL LETTER
+ 0x023B: 'C', // WITH STROKE, LATIN CAPITAL LETTER
+ 0x1D04: 'C', // , LATIN LETTER SMALL CAPITAL
+ 0x018A: 'D', // WITH HOOK, LATIN CAPITAL LETTER
+ 0x0189: 'D', // , LATIN CAPITAL LETTER AFRICAN
+ 0x1D05: 'D', // , LATIN LETTER SMALL CAPITAL
+ 0x00C9: 'E', // WITH ACUTE, LATIN CAPITAL LETTER
+ 0x00CA: 'E', // WITH CIRCUMFLEX, LATIN CAPITAL LETTER
+ 0x00CB: 'E', // WITH DIAERESIS, LATIN CAPITAL LETTER
+ 0x00C8: 'E', // WITH GRAVE, LATIN CAPITAL LETTER
+ 0x0246: 'E', // WITH STROKE, LATIN CAPITAL LETTER
+ 0x0190: 'E', // , LATIN CAPITAL LETTER OPEN
+ 0x018E: 'E', // , LATIN CAPITAL LETTER REVERSED
+ 0x1D07: 'E', // , LATIN LETTER SMALL CAPITAL
+ 0x0193: 'G', // WITH HOOK, LATIN CAPITAL LETTER
+ 0x029B: 'G', // WITH HOOK, LATIN LETTER SMALL CAPITAL
+ 0x0262: 'G', // , LATIN LETTER SMALL CAPITAL
+ 0x029C: 'H', // , LATIN LETTER SMALL CAPITAL
+ 0x00CD: 'I', // WITH ACUTE, LATIN CAPITAL LETTER
+ 0x00CE: 'I', // WITH CIRCUMFLEX, LATIN CAPITAL LETTER
+ 0x00CF: 'I', // WITH DIAERESIS, LATIN CAPITAL LETTER
+ 0x0130: 'I', // WITH DOT ABOVE, LATIN CAPITAL LETTER
+ 0x00CC: 'I', // WITH GRAVE, LATIN CAPITAL LETTER
+ 0x0197: 'I', // WITH STROKE, LATIN CAPITAL LETTER
+ 0x026A: 'I', // , LATIN LETTER SMALL CAPITAL
+ 0x0248: 'J', // WITH STROKE, LATIN CAPITAL LETTER
+ 0x1D0A: 'J', // , LATIN LETTER SMALL CAPITAL
+ 0x1D0B: 'K', // , LATIN LETTER SMALL CAPITAL
+ 0x023D: 'L', // WITH BAR, LATIN CAPITAL LETTER
+ 0x1D0C: 'L', // WITH STROKE, LATIN LETTER SMALL CAPITAL
+ 0x029F: 'L', // , LATIN LETTER SMALL CAPITAL
+ 0x019C: 'M', // , LATIN CAPITAL LETTER TURNED
+ 0x1D0D: 'M', // , LATIN LETTER SMALL CAPITAL
+ 0x019D: 'N', // WITH LEFT HOOK, LATIN CAPITAL LETTER
+ 0x0220: 'N', // WITH LONG RIGHT LEG, LATIN CAPITAL LETTER
+ 0x00D1: 'N', // WITH TILDE, LATIN CAPITAL LETTER
+ 0x0274: 'N', // , LATIN LETTER SMALL CAPITAL
+ 0x1D0E: 'N', // , LATIN LETTER SMALL CAPITAL REVERSED
+ 0x00D3: 'O', // WITH ACUTE, LATIN CAPITAL LETTER
+ 0x00D4: 'O', // WITH CIRCUMFLEX, LATIN CAPITAL LETTER
+ 0x00D6: 'O', // WITH DIAERESIS, LATIN CAPITAL LETTER
+ 0x00D2: 'O', // WITH GRAVE, LATIN CAPITAL LETTER
+ 0x019F: 'O', // WITH MIDDLE TILDE, LATIN CAPITAL LETTER
+ 0x00D8: 'O', // WITH STROKE, LATIN CAPITAL LETTER
+ 0x00D5: 'O', // WITH TILDE, LATIN CAPITAL LETTER
+ 0x0186: 'O', // , LATIN CAPITAL LETTER OPEN
+ 0x1D0F: 'O', // , LATIN LETTER SMALL CAPITAL
+ 0x1D10: 'O', // , LATIN LETTER SMALL CAPITAL OPEN
+ 0x1D18: 'P', // , LATIN LETTER SMALL CAPITAL
+ 0x024A: 'Q', // WITH HOOK TAIL, LATIN CAPITAL LETTER SMALL
+ 0x024C: 'R', // WITH STROKE, LATIN CAPITAL LETTER
+ 0x0280: 'R', // , LATIN LETTER SMALL CAPITAL
+ 0x0281: 'R', // , LATIN LETTER SMALL CAPITAL INVERTED
+ 0x1D19: 'R', // , LATIN LETTER SMALL CAPITAL REVERSED
+ 0x1D1A: 'R', // , LATIN LETTER SMALL CAPITAL TURNED
+ 0x023E: 'T', // WITH DIAGONAL STROKE, LATIN CAPITAL LETTER
+ 0x01AE: 'T', // WITH RETROFLEX HOOK, LATIN CAPITAL LETTER
+ 0x1D1B: 'T', // , LATIN LETTER SMALL CAPITAL
+ 0x0244: 'U', // BAR, LATIN CAPITAL LETTER
+ 0x00DA: 'U', // WITH ACUTE, LATIN CAPITAL LETTER
+ 0x00DB: 'U', // WITH CIRCUMFLEX, LATIN CAPITAL LETTER
+ 0x00DC: 'U', // WITH DIAERESIS, LATIN CAPITAL LETTER
+ 0x00D9: 'U', // WITH GRAVE, LATIN CAPITAL LETTER
+ 0x1D1C: 'U', // , LATIN LETTER SMALL CAPITAL
+ 0x01B2: 'V', // WITH HOOK, LATIN CAPITAL LETTER
+ 0x0245: 'V', // , LATIN CAPITAL LETTER TURNED
+ 0x1D20: 'V', // , LATIN LETTER SMALL CAPITAL
+ 0x1D21: 'W', // , LATIN LETTER SMALL CAPITAL
+ 0x00DD: 'Y', // WITH ACUTE, LATIN CAPITAL LETTER
+ 0x0178: 'Y', // WITH DIAERESIS, LATIN CAPITAL LETTER
+ 0x024E: 'Y', // WITH STROKE, LATIN CAPITAL LETTER
+ 0x028F: 'Y', // , LATIN LETTER SMALL CAPITAL
+ 0x1D22: 'Z', // , LATIN LETTER SMALL CAPITAL
+
+ 'Ắ': 'A',
+ 'Ấ': 'A',
+ 'Ằ': 'A',
+ 'Ầ': 'A',
+ 'Ẳ': 'A',
+ 'Ẩ': 'A',
+ 'Ẵ': 'A',
+ 'Ẫ': 'A',
+ 'Ặ': 'A',
+ 'Ậ': 'A',
+
+ 'ắ': 'a',
+ 'ấ': 'a',
+ 'ằ': 'a',
+ 'ầ': 'a',
+ 'ẳ': 'a',
+ 'ẩ': 'a',
+ 'ẵ': 'a',
+ 'ẫ': 'a',
+ 'ặ': 'a',
+ 'ậ': 'a',
+
+ 'Ế': 'E',
+ 'Ề': 'E',
+ 'Ể': 'E',
+ 'Ễ': 'E',
+ 'Ệ': 'E',
+
+ 'ế': 'e',
+ 'ề': 'e',
+ 'ể': 'e',
+ 'ễ': 'e',
+ 'ệ': 'e',
+
+ 'Ố': 'O',
+ 'Ớ': 'O',
+ 'Ồ': 'O',
+ 'Ờ': 'O',
+ 'Ổ': 'O',
+ 'Ở': 'O',
+ 'Ỗ': 'O',
+ 'Ỡ': 'O',
+ 'Ộ': 'O',
+ 'Ợ': 'O',
+
+ 'ố': 'o',
+ 'ớ': 'o',
+ 'ồ': 'o',
+ 'ờ': 'o',
+ 'ổ': 'o',
+ 'ở': 'o',
+ 'ỗ': 'o',
+ 'ỡ': 'o',
+ 'ộ': 'o',
+ 'ợ': 'o',
+
+ 'Ứ': 'U',
+ 'Ừ': 'U',
+ 'Ử': 'U',
+ 'Ữ': 'U',
+ 'Ự': 'U',
+
+ 'ứ': 'u',
+ 'ừ': 'u',
+ 'ử': 'u',
+ 'ữ': 'u',
+ 'ự': 'u',
+}
+
+// NormalizeRunes normalizes latin script letters
+func NormalizeRunes(runes []rune) []rune {
+ ret := make([]rune, len(runes))
+ copy(ret, runes)
+ for idx, r := range runes {
+ if r < 0x00C0 || r > 0x2184 {
+ continue
+ }
+ n := normalized[r]
+ if n > 0 {
+ ret[idx] = normalized[r]
+ }
+ }
+ return ret
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/ansi.go b/dot-oh-my-zsh/custom/plugins/fzf/src/ansi.go
new file mode 100644
index 00000000..24acc396
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/ansi.go
@@ -0,0 +1,433 @@
+package fzf
+
+import (
+ "strconv"
+ "strings"
+ "unicode/utf8"
+
+ "github.com/junegunn/fzf/src/tui"
+)
+
+type ansiOffset struct {
+ offset [2]int32
+ color ansiState
+}
+
+type ansiState struct {
+ fg tui.Color
+ bg tui.Color
+ attr tui.Attr
+ lbg tui.Color
+}
+
+func (s *ansiState) colored() bool {
+ return s.fg != -1 || s.bg != -1 || s.attr > 0 || s.lbg >= 0
+}
+
+func (s *ansiState) equals(t *ansiState) bool {
+ if t == nil {
+ return !s.colored()
+ }
+ return s.fg == t.fg && s.bg == t.bg && s.attr == t.attr && s.lbg == t.lbg
+}
+
+func (s *ansiState) ToString() string {
+ if !s.colored() {
+ return ""
+ }
+
+ ret := ""
+ if s.attr&tui.Bold > 0 {
+ ret += "1;"
+ }
+ if s.attr&tui.Dim > 0 {
+ ret += "2;"
+ }
+ if s.attr&tui.Italic > 0 {
+ ret += "3;"
+ }
+ if s.attr&tui.Underline > 0 {
+ ret += "4;"
+ }
+ if s.attr&tui.Blink > 0 {
+ ret += "5;"
+ }
+ if s.attr&tui.Reverse > 0 {
+ ret += "7;"
+ }
+ if s.attr&tui.StrikeThrough > 0 {
+ ret += "9;"
+ }
+ ret += toAnsiString(s.fg, 30) + toAnsiString(s.bg, 40)
+
+ return "\x1b[" + strings.TrimSuffix(ret, ";") + "m"
+}
+
+func toAnsiString(color tui.Color, offset int) string {
+ col := int(color)
+ ret := ""
+ if col == -1 {
+ ret += strconv.Itoa(offset + 9)
+ } else if col < 8 {
+ ret += strconv.Itoa(offset + col)
+ } else if col < 16 {
+ ret += strconv.Itoa(offset - 30 + 90 + col - 8)
+ } else if col < 256 {
+ ret += strconv.Itoa(offset+8) + ";5;" + strconv.Itoa(col)
+ } else if col >= (1 << 24) {
+ r := strconv.Itoa((col >> 16) & 0xff)
+ g := strconv.Itoa((col >> 8) & 0xff)
+ b := strconv.Itoa(col & 0xff)
+ ret += strconv.Itoa(offset+8) + ";2;" + r + ";" + g + ";" + b
+ }
+ return ret + ";"
+}
+
+func isPrint(c uint8) bool {
+ return '\x20' <= c && c <= '\x7e'
+}
+
+func matchOperatingSystemCommand(s string) int {
+ // `\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)`
+ // ^ match starting here
+ //
+ i := 5 // prefix matched in nextAnsiEscapeSequence()
+ for ; i < len(s) && isPrint(s[i]); i++ {
+ }
+ if i < len(s) {
+ if s[i] == '\x07' {
+ return i + 1
+ }
+ if s[i] == '\x1b' && i < len(s)-1 && s[i+1] == '\\' {
+ return i + 2
+ }
+ }
+ return -1
+}
+
+func matchControlSequence(s string) int {
+ // `\x1b[\\[()][0-9;:?]*[a-zA-Z@]`
+ // ^ match starting here
+ //
+ i := 2 // prefix matched in nextAnsiEscapeSequence()
+ for ; i < len(s); i++ {
+ c := s[i]
+ switch c {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';', ':', '?':
+ // ok
+ default:
+ if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '@' {
+ return i + 1
+ }
+ return -1
+ }
+ }
+ return -1
+}
+
+func isCtrlSeqStart(c uint8) bool {
+ switch c {
+ case '\\', '[', '(', ')':
+ return true
+ }
+ return false
+}
+
+// nextAnsiEscapeSequence returns the ANSI escape sequence and is equivalent to
+// calling FindStringIndex() on the below regex (which was originally used):
+//
+// "(?:\x1b[\\[()][0-9;:?]*[a-zA-Z@]|\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)"
+func nextAnsiEscapeSequence(s string) (int, int) {
+ // fast check for ANSI escape sequences
+ i := 0
+ for ; i < len(s); i++ {
+ switch s[i] {
+ case '\x0e', '\x0f', '\x1b', '\x08':
+ // We ignore the fact that '\x08' cannot be the first char
+ // in the string and be an escape sequence for the sake of
+ // speed and simplicity.
+ goto Loop
+ }
+ }
+ return -1, -1
+
+Loop:
+ for ; i < len(s); i++ {
+ switch s[i] {
+ case '\x08':
+ // backtrack to match: `.\x08`
+ if i > 0 && s[i-1] != '\n' {
+ if s[i-1] < utf8.RuneSelf {
+ return i - 1, i + 1
+ }
+ _, n := utf8.DecodeLastRuneInString(s[:i])
+ return i - n, i + 1
+ }
+ case '\x1b':
+ // match: `\x1b[\\[()][0-9;:?]*[a-zA-Z@]`
+ if i+2 < len(s) && isCtrlSeqStart(s[i+1]) {
+ if j := matchControlSequence(s[i:]); j != -1 {
+ return i, i + j
+ }
+ }
+
+ // match: `\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)`
+ if i+5 < len(s) && s[i+1] == ']' && isNumeric(s[i+2]) &&
+ (s[i+3] == ';' || s[i+3] == ':') && isPrint(s[i+4]) {
+
+ if j := matchOperatingSystemCommand(s[i:]); j != -1 {
+ return i, i + j
+ }
+ }
+
+ // match: `\x1b.`
+ if i+1 < len(s) && s[i+1] != '\n' {
+ if s[i+1] < utf8.RuneSelf {
+ return i, i + 2
+ }
+ _, n := utf8.DecodeRuneInString(s[i+1:])
+ return i, i + n + 1
+ }
+ case '\x0e', '\x0f':
+ // match: `[\x0e\x0f]`
+ return i, i + 1
+ }
+ }
+ return -1, -1
+}
+
+func extractColor(str string, state *ansiState, proc func(string, *ansiState) bool) (string, *[]ansiOffset, *ansiState) {
+ // We append to a stack allocated variable that we'll
+ // later copy and return, to save on allocations.
+ offsets := make([]ansiOffset, 0, 32)
+
+ if state != nil {
+ offsets = append(offsets, ansiOffset{[2]int32{0, 0}, *state})
+ }
+
+ var (
+ pstate *ansiState // lazily allocated
+ output strings.Builder
+ prevIdx int
+ runeCount int
+ )
+ for idx := 0; idx < len(str); {
+ // Make sure that we found an ANSI code
+ start, end := nextAnsiEscapeSequence(str[idx:])
+ if start == -1 {
+ break
+ }
+ start += idx
+ idx += end
+
+ // Check if we should continue
+ prev := str[prevIdx:start]
+ if proc != nil && !proc(prev, state) {
+ return "", nil, nil
+ }
+ prevIdx = idx
+
+ if len(prev) != 0 {
+ runeCount += utf8.RuneCountInString(prev)
+ // Grow the buffer size to the maximum possible length (string length
+ // containing ansi codes) to avoid repetitive allocation
+ if output.Cap() == 0 {
+ output.Grow(len(str))
+ }
+ output.WriteString(prev)
+ }
+
+ newState := interpretCode(str[start:idx], state)
+ if !newState.equals(state) {
+ if state != nil {
+ // Update last offset
+ (&offsets[len(offsets)-1]).offset[1] = int32(runeCount)
+ }
+
+ if newState.colored() {
+ // Append new offset
+ if pstate == nil {
+ pstate = &ansiState{}
+ }
+ *pstate = newState
+ state = pstate
+ offsets = append(offsets, ansiOffset{
+ [2]int32{int32(runeCount), int32(runeCount)},
+ newState,
+ })
+ } else {
+ // Discard state
+ state = nil
+ }
+ }
+ }
+
+ var rest string
+ var trimmed string
+ if prevIdx == 0 {
+ // No ANSI code found
+ rest = str
+ trimmed = str
+ } else {
+ rest = str[prevIdx:]
+ output.WriteString(rest)
+ trimmed = output.String()
+ }
+ if proc != nil {
+ proc(rest, state)
+ }
+ if len(offsets) > 0 {
+ if len(rest) > 0 && state != nil {
+ // Update last offset
+ runeCount += utf8.RuneCountInString(rest)
+ (&offsets[len(offsets)-1]).offset[1] = int32(runeCount)
+ }
+ // Return a copy of the offsets slice
+ a := make([]ansiOffset, len(offsets))
+ copy(a, offsets)
+ return trimmed, &a, state
+ }
+ return trimmed, nil, state
+}
+
+func parseAnsiCode(s string, delimiter byte) (int, byte, string) {
+ var remaining string
+ i := -1
+ if delimiter == 0 {
+ // Faster than strings.IndexAny(";:")
+ i = strings.IndexByte(s, ';')
+ if i < 0 {
+ i = strings.IndexByte(s, ':')
+ }
+ } else {
+ i = strings.IndexByte(s, delimiter)
+ }
+ if i >= 0 {
+ delimiter = s[i]
+ remaining = s[i+1:]
+ s = s[:i]
+ }
+
+ if len(s) > 0 {
+ // Inlined version of strconv.Atoi() that only handles positive
+ // integers and does not allocate on error.
+ code := 0
+ for _, ch := range []byte(s) {
+ ch -= '0'
+ if ch > 9 {
+ return -1, delimiter, remaining
+ }
+ code = code*10 + int(ch)
+ }
+ return code, delimiter, remaining
+ }
+
+ return -1, delimiter, remaining
+}
+
+func interpretCode(ansiCode string, prevState *ansiState) ansiState {
+ var state ansiState
+ if prevState == nil {
+ state = ansiState{-1, -1, 0, -1}
+ } else {
+ state = ansiState{prevState.fg, prevState.bg, prevState.attr, prevState.lbg}
+ }
+ if ansiCode[0] != '\x1b' || ansiCode[1] != '[' || ansiCode[len(ansiCode)-1] != 'm' {
+ if prevState != nil && strings.HasSuffix(ansiCode, "0K") {
+ state.lbg = prevState.bg
+ }
+ return state
+ }
+
+ if len(ansiCode) <= 3 {
+ state.fg = -1
+ state.bg = -1
+ state.attr = 0
+ return state
+ }
+ ansiCode = ansiCode[2 : len(ansiCode)-1]
+
+ state256 := 0
+ ptr := &state.fg
+
+ var delimiter byte = 0
+ for len(ansiCode) != 0 {
+ var num int
+ if num, delimiter, ansiCode = parseAnsiCode(ansiCode, delimiter); num != -1 {
+ switch state256 {
+ case 0:
+ switch num {
+ case 38:
+ ptr = &state.fg
+ state256++
+ case 48:
+ ptr = &state.bg
+ state256++
+ case 39:
+ state.fg = -1
+ case 49:
+ state.bg = -1
+ case 1:
+ state.attr = state.attr | tui.Bold
+ case 2:
+ state.attr = state.attr | tui.Dim
+ case 3:
+ state.attr = state.attr | tui.Italic
+ case 4:
+ state.attr = state.attr | tui.Underline
+ case 5:
+ state.attr = state.attr | tui.Blink
+ case 7:
+ state.attr = state.attr | tui.Reverse
+ case 9:
+ state.attr = state.attr | tui.StrikeThrough
+ case 23: // tput rmso
+ state.attr = state.attr &^ tui.Italic
+ case 24: // tput rmul
+ state.attr = state.attr &^ tui.Underline
+ case 0:
+ state.fg = -1
+ state.bg = -1
+ state.attr = 0
+ state256 = 0
+ default:
+ if num >= 30 && num <= 37 {
+ state.fg = tui.Color(num - 30)
+ } else if num >= 40 && num <= 47 {
+ state.bg = tui.Color(num - 40)
+ } else if num >= 90 && num <= 97 {
+ state.fg = tui.Color(num - 90 + 8)
+ } else if num >= 100 && num <= 107 {
+ state.bg = tui.Color(num - 100 + 8)
+ }
+ }
+ case 1:
+ switch num {
+ case 2:
+ state256 = 10 // MAGIC
+ case 5:
+ state256++
+ default:
+ state256 = 0
+ }
+ case 2:
+ *ptr = tui.Color(num)
+ state256 = 0
+ case 10:
+ *ptr = tui.Color(1<<24) | tui.Color(num<<16)
+ state256++
+ case 11:
+ *ptr = *ptr | tui.Color(num<<8)
+ state256++
+ case 12:
+ *ptr = *ptr | tui.Color(num)
+ state256 = 0
+ }
+ }
+ }
+
+ if state256 > 0 {
+ *ptr = -1
+ }
+ return state
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/ansi_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/ansi_test.go
new file mode 100644
index 00000000..f352c99e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/ansi_test.go
@@ -0,0 +1,428 @@
+package fzf
+
+import (
+ "math/rand"
+ "regexp"
+ "strings"
+ "testing"
+ "unicode/utf8"
+
+ "github.com/junegunn/fzf/src/tui"
+)
+
+// The following regular expression will include not all but most of the
+// frequently used ANSI sequences. This regex is used as a reference for
+// testing nextAnsiEscapeSequence().
+//
+// References:
+// - https://github.com/gnachman/iTerm2
+// - https://web.archive.org/web/20090204053813/http://ascii-table.com/ansi-escape-sequences.php
+// (archived from http://ascii-table.com/ansi-escape-sequences.php)
+// - https://web.archive.org/web/20090227051140/http://ascii-table.com/ansi-escape-sequences-vt-100.php
+// (archived from http://ascii-table.com/ansi-escape-sequences-vt-100.php)
+// - http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html
+// - https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+var ansiRegexReference = regexp.MustCompile("(?:\x1b[\\[()][0-9;:]*[a-zA-Z@]|\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)")
+
+func testParserReference(t testing.TB, str string) {
+ t.Helper()
+
+ toSlice := func(start, end int) []int {
+ if start == -1 {
+ return nil
+ }
+ return []int{start, end}
+ }
+
+ s := str
+ for i := 0; ; i++ {
+ got := toSlice(nextAnsiEscapeSequence(s))
+ exp := ansiRegexReference.FindStringIndex(s)
+
+ equal := len(got) == len(exp)
+ if equal {
+ for i := 0; i < len(got); i++ {
+ if got[i] != exp[i] {
+ equal = false
+ break
+ }
+ }
+ }
+ if !equal {
+ var exps, gots []rune
+ if len(got) == 2 {
+ gots = []rune(s[got[0]:got[1]])
+ }
+ if len(exp) == 2 {
+ exps = []rune(s[exp[0]:exp[1]])
+ }
+ t.Errorf("%d: %q: got: %v (%q) want: %v (%q)", i, s, got, gots, exp, exps)
+ return
+ }
+ if len(exp) == 0 {
+ return
+ }
+ s = s[exp[1]:]
+ }
+}
+
+func TestNextAnsiEscapeSequence(t *testing.T) {
+ testStrs := []string{
+ "\x1b[0mhello world",
+ "\x1b[1mhello world",
+ "椙\x1b[1m椙",
+ "椙\x1b[1椙m椙",
+ "\x1b[1mhello \x1b[mw\x1b7o\x1b8r\x1b(Bl\x1b[2@d",
+ "\x1b[1mhello \x1b[Kworld",
+ "hello \x1b[34;45;1mworld",
+ "hello \x1b[34;45;1mwor\x1b[34;45;1mld",
+ "hello \x1b[34;45;1mwor\x1b[0mld",
+ "hello \x1b[34;48;5;233;1mwo\x1b[38;5;161mr\x1b[0ml\x1b[38;5;161md",
+ "hello \x1b[38;5;38;48;5;48;1mwor\x1b[38;5;48;48;5;38ml\x1b[0md",
+ "hello \x1b[32;1mworld",
+ "hello world",
+ "hello \x1b[0;38;5;200;48;5;100mworld",
+ "\x1b椙",
+ "椙\x08",
+ "\n\x08",
+ "X\x08",
+ "",
+ "\x1b]4;3;rgb:aa/bb/cc\x07 ",
+ "\x1b]4;3;rgb:aa/bb/cc\x1b\\ ",
+ ansiBenchmarkString,
+ }
+
+ for _, s := range testStrs {
+ testParserReference(t, s)
+ }
+}
+
+func TestNextAnsiEscapeSequence_Fuzz_Modified(t *testing.T) {
+ t.Parallel()
+ if testing.Short() {
+ t.Skip("short test")
+ }
+
+ testStrs := []string{
+ "\x1b[0mhello world",
+ "\x1b[1mhello world",
+ "椙\x1b[1m椙",
+ "椙\x1b[1椙m椙",
+ "\x1b[1mhello \x1b[mw\x1b7o\x1b8r\x1b(Bl\x1b[2@d",
+ "\x1b[1mhello \x1b[Kworld",
+ "hello \x1b[34;45;1mworld",
+ "hello \x1b[34;45;1mwor\x1b[34;45;1mld",
+ "hello \x1b[34;45;1mwor\x1b[0mld",
+ "hello \x1b[34;48;5;233;1mwo\x1b[38;5;161mr\x1b[0ml\x1b[38;5;161md",
+ "hello \x1b[38;5;38;48;5;48;1mwor\x1b[38;5;48;48;5;38ml\x1b[0md",
+ "hello \x1b[32;1mworld",
+ "hello world",
+ "hello \x1b[0;38;5;200;48;5;100mworld",
+ ansiBenchmarkString,
+ }
+
+ replacementBytes := [...]rune{'\x0e', '\x0f', '\x1b', '\x08'}
+
+ modifyString := func(s string, rr *rand.Rand) string {
+ n := rr.Intn(len(s))
+ b := []rune(s)
+ for ; n >= 0 && len(b) != 0; n-- {
+ i := rr.Intn(len(b))
+ switch x := rr.Intn(4); x {
+ case 0:
+ b = append(b[:i], b[i+1:]...)
+ case 1:
+ j := rr.Intn(len(replacementBytes) - 1)
+ b[i] = replacementBytes[j]
+ case 2:
+ x := rune(rr.Intn(utf8.MaxRune))
+ for !utf8.ValidRune(x) {
+ x = rune(rr.Intn(utf8.MaxRune))
+ }
+ b[i] = x
+ case 3:
+ b[i] = rune(rr.Intn(utf8.MaxRune)) // potentially invalid
+ default:
+ t.Fatalf("unsupported value: %d", x)
+ }
+ }
+ return string(b)
+ }
+
+ rr := rand.New(rand.NewSource(1))
+ for _, s := range testStrs {
+ for i := 1_000; i >= 0; i-- {
+ testParserReference(t, modifyString(s, rr))
+ }
+ }
+}
+
+func TestNextAnsiEscapeSequence_Fuzz_Random(t *testing.T) {
+ t.Parallel()
+
+ if testing.Short() {
+ t.Skip("short test")
+ }
+
+ randomString := func(rr *rand.Rand) string {
+ numChars := rand.Intn(50)
+ codePoints := make([]rune, numChars)
+ for i := 0; i < len(codePoints); i++ {
+ var r rune
+ for n := 0; n < 1000; n++ {
+ r = rune(rr.Intn(utf8.MaxRune))
+ // Allow 10% of runes to be invalid
+ if utf8.ValidRune(r) || rr.Float64() < 0.10 {
+ break
+ }
+ }
+ codePoints[i] = r
+ }
+ return string(codePoints)
+ }
+
+ rr := rand.New(rand.NewSource(1))
+ for i := 0; i < 100_000; i++ {
+ testParserReference(t, randomString(rr))
+ }
+}
+
+func TestExtractColor(t *testing.T) {
+ assert := func(offset ansiOffset, b int32, e int32, fg tui.Color, bg tui.Color, bold bool) {
+ var attr tui.Attr
+ if bold {
+ attr = tui.Bold
+ }
+ if offset.offset[0] != b || offset.offset[1] != e ||
+ offset.color.fg != fg || offset.color.bg != bg || offset.color.attr != attr {
+ t.Error(offset, b, e, fg, bg, attr)
+ }
+ }
+
+ src := "hello world"
+ var state *ansiState
+ clean := "\x1b[0m"
+ check := func(assertion func(ansiOffsets *[]ansiOffset, state *ansiState)) {
+ output, ansiOffsets, newState := extractColor(src, state, nil)
+ state = newState
+ if output != "hello world" {
+ t.Errorf("Invalid output: %s %v", output, []rune(output))
+ }
+ t.Log(src, ansiOffsets, clean)
+ assertion(ansiOffsets, state)
+ }
+
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if offsets != nil {
+ t.Fail()
+ }
+ })
+
+ state = nil
+ src = "\x1b[0mhello world"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if offsets != nil {
+ t.Fail()
+ }
+ })
+
+ state = nil
+ src = "\x1b[1mhello world"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 1 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 0, 11, -1, -1, true)
+ })
+
+ state = nil
+ src = "\x1b[1mhello \x1b[mw\x1b7o\x1b8r\x1b(Bl\x1b[2@d"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 1 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 0, 6, -1, -1, true)
+ })
+
+ state = nil
+ src = "\x1b[1mhello \x1b[Kworld"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 1 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 0, 11, -1, -1, true)
+ })
+
+ state = nil
+ src = "hello \x1b[34;45;1mworld"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 1 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 6, 11, 4, 5, true)
+ })
+
+ state = nil
+ src = "hello \x1b[34;45;1mwor\x1b[34;45;1mld"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 1 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 6, 11, 4, 5, true)
+ })
+
+ state = nil
+ src = "hello \x1b[34;45;1mwor\x1b[0mld"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 1 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 6, 9, 4, 5, true)
+ })
+
+ state = nil
+ src = "hello \x1b[34;48;5;233;1mwo\x1b[38;5;161mr\x1b[0ml\x1b[38;5;161md"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 3 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 6, 8, 4, 233, true)
+ assert((*offsets)[1], 8, 9, 161, 233, true)
+ assert((*offsets)[2], 10, 11, 161, -1, false)
+ })
+
+ // {38,48};5;{38,48}
+ state = nil
+ src = "hello \x1b[38;5;38;48;5;48;1mwor\x1b[38;5;48;48;5;38ml\x1b[0md"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 2 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 6, 9, 38, 48, true)
+ assert((*offsets)[1], 9, 10, 48, 38, true)
+ })
+
+ src = "hello \x1b[32;1mworld"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 1 {
+ t.Fail()
+ }
+ if state.fg != 2 || state.bg != -1 || state.attr == 0 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 6, 11, 2, -1, true)
+ })
+
+ src = "hello world"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 1 {
+ t.Fail()
+ }
+ if state.fg != 2 || state.bg != -1 || state.attr == 0 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 0, 11, 2, -1, true)
+ })
+
+ src = "hello \x1b[0;38;5;200;48;5;100mworld"
+ check(func(offsets *[]ansiOffset, state *ansiState) {
+ if len(*offsets) != 2 {
+ t.Fail()
+ }
+ if state.fg != 200 || state.bg != 100 || state.attr > 0 {
+ t.Fail()
+ }
+ assert((*offsets)[0], 0, 6, 2, -1, true)
+ assert((*offsets)[1], 6, 11, 200, 100, false)
+ })
+}
+
+func TestAnsiCodeStringConversion(t *testing.T) {
+ assert := func(code string, prevState *ansiState, expected string) {
+ state := interpretCode(code, prevState)
+ if expected != state.ToString() {
+ t.Errorf("expected: %s, actual: %s",
+ strings.Replace(expected, "\x1b[", "\\x1b[", -1),
+ strings.Replace(state.ToString(), "\x1b[", "\\x1b[", -1))
+ }
+ }
+ assert("\x1b[m", nil, "")
+ assert("\x1b[m", &ansiState{attr: tui.Blink, lbg: -1}, "")
+
+ assert("\x1b[31m", nil, "\x1b[31;49m")
+ assert("\x1b[41m", nil, "\x1b[39;41m")
+
+ assert("\x1b[92m", nil, "\x1b[92;49m")
+ assert("\x1b[102m", nil, "\x1b[39;102m")
+
+ assert("\x1b[31m", &ansiState{fg: 4, bg: 4, lbg: -1}, "\x1b[31;44m")
+ assert("\x1b[1;2;31m", &ansiState{fg: 2, bg: -1, attr: tui.Reverse, lbg: -1}, "\x1b[1;2;7;31;49m")
+ assert("\x1b[38;5;100;48;5;200m", nil, "\x1b[38;5;100;48;5;200m")
+ assert("\x1b[38:5:100:48:5:200m", nil, "\x1b[38;5;100;48;5;200m")
+ assert("\x1b[48;5;100;38;5;200m", nil, "\x1b[38;5;200;48;5;100m")
+ assert("\x1b[48;5;100;38;2;10;20;30;1m", nil, "\x1b[1;38;2;10;20;30;48;5;100m")
+ assert("\x1b[48;5;100;38;2;10;20;30;7m",
+ &ansiState{attr: tui.Dim | tui.Italic, fg: 1, bg: 1},
+ "\x1b[2;3;7;38;2;10;20;30;48;5;100m")
+}
+
+func TestParseAnsiCode(t *testing.T) {
+ tests := []struct {
+ In, Exp string
+ N int
+ }{
+ {"123", "", 123},
+ {"1a", "", -1},
+ {"1a;12", "12", -1},
+ {"12;a", "a", 12},
+ {"-2", "", -1},
+ }
+ for _, x := range tests {
+ n, _, s := parseAnsiCode(x.In, 0)
+ if n != x.N || s != x.Exp {
+ t.Fatalf("%q: got: (%d %q) want: (%d %q)", x.In, n, s, x.N, x.Exp)
+ }
+ }
+}
+
+// kernel/bpf/preload/iterators/README
+const ansiBenchmarkString = "\x1b[38;5;81m\x1b[01;31m\x1b[Kkernel/\x1b[0m\x1b[38:5:81mbpf/" +
+ "\x1b[0m\x1b[38:5:81mpreload/\x1b[0m\x1b[38;5;81miterators/" +
+ "\x1b[0m\x1b[38:5:149mMakefile\x1b[m\x1b[K\x1b[0m"
+
+func BenchmarkNextAnsiEscapeSequence(b *testing.B) {
+ b.SetBytes(int64(len(ansiBenchmarkString)))
+ for i := 0; i < b.N; i++ {
+ s := ansiBenchmarkString
+ for {
+ _, o := nextAnsiEscapeSequence(s)
+ if o == -1 {
+ break
+ }
+ s = s[o:]
+ }
+ }
+}
+
+// Baseline test to compare the speed of nextAnsiEscapeSequence() to the
+// previously used regex based implementation.
+func BenchmarkNextAnsiEscapeSequence_Regex(b *testing.B) {
+ b.SetBytes(int64(len(ansiBenchmarkString)))
+ for i := 0; i < b.N; i++ {
+ s := ansiBenchmarkString
+ for {
+ a := ansiRegexReference.FindStringIndex(s)
+ if len(a) == 0 {
+ break
+ }
+ s = s[a[1]:]
+ }
+ }
+}
+
+func BenchmarkExtractColor(b *testing.B) {
+ b.SetBytes(int64(len(ansiBenchmarkString)))
+ for i := 0; i < b.N; i++ {
+ extractColor(ansiBenchmarkString, nil, nil)
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/cache.go b/dot-oh-my-zsh/custom/plugins/fzf/src/cache.go
new file mode 100644
index 00000000..df1a6ab7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/cache.go
@@ -0,0 +1,81 @@
+package fzf
+
+import "sync"
+
+// queryCache associates strings to lists of items
+type queryCache map[string][]Result
+
+// ChunkCache associates Chunk and query string to lists of items
+type ChunkCache struct {
+ mutex sync.Mutex
+ cache map[*Chunk]*queryCache
+}
+
+// NewChunkCache returns a new ChunkCache
+func NewChunkCache() ChunkCache {
+ return ChunkCache{sync.Mutex{}, make(map[*Chunk]*queryCache)}
+}
+
+// Add adds the list to the cache
+func (cc *ChunkCache) Add(chunk *Chunk, key string, list []Result) {
+ if len(key) == 0 || !chunk.IsFull() || len(list) > queryCacheMax {
+ return
+ }
+
+ cc.mutex.Lock()
+ defer cc.mutex.Unlock()
+
+ qc, ok := cc.cache[chunk]
+ if !ok {
+ cc.cache[chunk] = &queryCache{}
+ qc = cc.cache[chunk]
+ }
+ (*qc)[key] = list
+}
+
+// Lookup is called to lookup ChunkCache
+func (cc *ChunkCache) Lookup(chunk *Chunk, key string) []Result {
+ if len(key) == 0 || !chunk.IsFull() {
+ return nil
+ }
+
+ cc.mutex.Lock()
+ defer cc.mutex.Unlock()
+
+ qc, ok := cc.cache[chunk]
+ if ok {
+ list, ok := (*qc)[key]
+ if ok {
+ return list
+ }
+ }
+ return nil
+}
+
+func (cc *ChunkCache) Search(chunk *Chunk, key string) []Result {
+ if len(key) == 0 || !chunk.IsFull() {
+ return nil
+ }
+
+ cc.mutex.Lock()
+ defer cc.mutex.Unlock()
+
+ qc, ok := cc.cache[chunk]
+ if !ok {
+ return nil
+ }
+
+ for idx := 1; idx < len(key); idx++ {
+ // [---------| ] | [ |---------]
+ // [--------| ] | [ |--------]
+ // [-------| ] | [ |-------]
+ prefix := key[:len(key)-idx]
+ suffix := key[idx:]
+ for _, substr := range [2]string{prefix, suffix} {
+ if cached, found := (*qc)[substr]; found {
+ return cached
+ }
+ }
+ }
+ return nil
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/cache_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/cache_test.go
new file mode 100644
index 00000000..02425345
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/cache_test.go
@@ -0,0 +1,39 @@
+package fzf
+
+import "testing"
+
+func TestChunkCache(t *testing.T) {
+ cache := NewChunkCache()
+ chunk1p := &Chunk{}
+ chunk2p := &Chunk{count: chunkSize}
+ items1 := []Result{{}}
+ items2 := []Result{{}, {}}
+ cache.Add(chunk1p, "foo", items1)
+ cache.Add(chunk2p, "foo", items1)
+ cache.Add(chunk2p, "bar", items2)
+
+ { // chunk1 is not full
+ cached := cache.Lookup(chunk1p, "foo")
+ if cached != nil {
+ t.Error("Cached disabled for non-empty chunks", cached)
+ }
+ }
+ {
+ cached := cache.Lookup(chunk2p, "foo")
+ if cached == nil || len(cached) != 1 {
+ t.Error("Expected 1 item cached", cached)
+ }
+ }
+ {
+ cached := cache.Lookup(chunk2p, "bar")
+ if cached == nil || len(cached) != 2 {
+ t.Error("Expected 2 items cached", cached)
+ }
+ }
+ {
+ cached := cache.Lookup(chunk1p, "foobar")
+ if cached != nil {
+ t.Error("Expected 0 item cached", cached)
+ }
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/chunklist.go b/dot-oh-my-zsh/custom/plugins/fzf/src/chunklist.go
new file mode 100644
index 00000000..cd635c25
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/chunklist.go
@@ -0,0 +1,89 @@
+package fzf
+
+import "sync"
+
+// Chunk is a list of Items whose size has the upper limit of chunkSize
+type Chunk struct {
+ items [chunkSize]Item
+ count int
+}
+
+// ItemBuilder is a closure type that builds Item object from byte array
+type ItemBuilder func(*Item, []byte) bool
+
+// ChunkList is a list of Chunks
+type ChunkList struct {
+ chunks []*Chunk
+ mutex sync.Mutex
+ trans ItemBuilder
+}
+
+// NewChunkList returns a new ChunkList
+func NewChunkList(trans ItemBuilder) *ChunkList {
+ return &ChunkList{
+ chunks: []*Chunk{},
+ mutex: sync.Mutex{},
+ trans: trans}
+}
+
+func (c *Chunk) push(trans ItemBuilder, data []byte) bool {
+ if trans(&c.items[c.count], data) {
+ c.count++
+ return true
+ }
+ return false
+}
+
+// IsFull returns true if the Chunk is full
+func (c *Chunk) IsFull() bool {
+ return c.count == chunkSize
+}
+
+func (cl *ChunkList) lastChunk() *Chunk {
+ return cl.chunks[len(cl.chunks)-1]
+}
+
+// CountItems returns the total number of Items
+func CountItems(cs []*Chunk) int {
+ if len(cs) == 0 {
+ return 0
+ }
+ return chunkSize*(len(cs)-1) + cs[len(cs)-1].count
+}
+
+// Push adds the item to the list
+func (cl *ChunkList) Push(data []byte) bool {
+ cl.mutex.Lock()
+
+ if len(cl.chunks) == 0 || cl.lastChunk().IsFull() {
+ cl.chunks = append(cl.chunks, &Chunk{})
+ }
+
+ ret := cl.lastChunk().push(cl.trans, data)
+ cl.mutex.Unlock()
+ return ret
+}
+
+// Clear clears the data
+func (cl *ChunkList) Clear() {
+ cl.mutex.Lock()
+ cl.chunks = nil
+ cl.mutex.Unlock()
+}
+
+// Snapshot returns immutable snapshot of the ChunkList
+func (cl *ChunkList) Snapshot() ([]*Chunk, int) {
+ cl.mutex.Lock()
+
+ ret := make([]*Chunk, len(cl.chunks))
+ copy(ret, cl.chunks)
+
+ // Duplicate the last chunk
+ if cnt := len(ret); cnt > 0 {
+ newChunk := *ret[cnt-1]
+ ret[cnt-1] = &newChunk
+ }
+
+ cl.mutex.Unlock()
+ return ret, CountItems(ret)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/chunklist_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/chunklist_test.go
new file mode 100644
index 00000000..6c1d09eb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/chunklist_test.go
@@ -0,0 +1,80 @@
+package fzf
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+func TestChunkList(t *testing.T) {
+ // FIXME global
+ sortCriteria = []criterion{byScore, byLength}
+
+ cl := NewChunkList(func(item *Item, s []byte) bool {
+ item.text = util.ToChars(s)
+ return true
+ })
+
+ // Snapshot
+ snapshot, count := cl.Snapshot()
+ if len(snapshot) > 0 || count > 0 {
+ t.Error("Snapshot should be empty now")
+ }
+
+ // Add some data
+ cl.Push([]byte("hello"))
+ cl.Push([]byte("world"))
+
+ // Previously created snapshot should remain the same
+ if len(snapshot) > 0 {
+ t.Error("Snapshot should not have changed")
+ }
+
+ // But the new snapshot should contain the added items
+ snapshot, count = cl.Snapshot()
+ if len(snapshot) != 1 && count != 2 {
+ t.Error("Snapshot should not be empty now")
+ }
+
+ // Check the content of the ChunkList
+ chunk1 := snapshot[0]
+ if chunk1.count != 2 {
+ t.Error("Snapshot should contain only two items")
+ }
+ if chunk1.items[0].text.ToString() != "hello" ||
+ chunk1.items[1].text.ToString() != "world" {
+ t.Error("Invalid data")
+ }
+ if chunk1.IsFull() {
+ t.Error("Chunk should not have been marked full yet")
+ }
+
+ // Add more data
+ for i := 0; i < chunkSize*2; i++ {
+ cl.Push([]byte(fmt.Sprintf("item %d", i)))
+ }
+
+ // Previous snapshot should remain the same
+ if len(snapshot) != 1 {
+ t.Error("Snapshot should stay the same")
+ }
+
+ // New snapshot
+ snapshot, count = cl.Snapshot()
+ if len(snapshot) != 3 || !snapshot[0].IsFull() ||
+ !snapshot[1].IsFull() || snapshot[2].IsFull() || count != chunkSize*2+2 {
+ t.Error("Expected two full chunks and one more chunk")
+ }
+ if snapshot[2].count != 2 {
+ t.Error("Unexpected number of items")
+ }
+
+ cl.Push([]byte("hello"))
+ cl.Push([]byte("world"))
+
+ lastChunkCount := snapshot[len(snapshot)-1].count
+ if lastChunkCount != 2 {
+ t.Error("Unexpected number of items:", lastChunkCount)
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/constants.go b/dot-oh-my-zsh/custom/plugins/fzf/src/constants.go
new file mode 100644
index 00000000..96d9821d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/constants.go
@@ -0,0 +1,85 @@
+package fzf
+
+import (
+ "math"
+ "os"
+ "time"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+const (
+ // Core
+ coordinatorDelayMax time.Duration = 100 * time.Millisecond
+ coordinatorDelayStep time.Duration = 10 * time.Millisecond
+
+ // Reader
+ readerBufferSize = 64 * 1024
+ readerPollIntervalMin = 10 * time.Millisecond
+ readerPollIntervalStep = 5 * time.Millisecond
+ readerPollIntervalMax = 50 * time.Millisecond
+
+ // Terminal
+ initialDelay = 20 * time.Millisecond
+ initialDelayTac = 100 * time.Millisecond
+ spinnerDuration = 100 * time.Millisecond
+ previewCancelWait = 500 * time.Millisecond
+ previewChunkDelay = 100 * time.Millisecond
+ previewDelayed = 500 * time.Millisecond
+ maxPatternLength = 300
+ maxMulti = math.MaxInt32
+
+ // Matcher
+ numPartitionsMultiplier = 8
+ maxPartitions = 32
+ progressMinDuration = 200 * time.Millisecond
+
+ // Capacity of each chunk
+ chunkSize int = 100
+
+ // Pre-allocated memory slices to minimize GC
+ slab16Size int = 100 * 1024 // 200KB * 32 = 12.8MB
+ slab32Size int = 2048 // 8KB * 32 = 256KB
+
+ // Do not cache results of low selectivity queries
+ queryCacheMax int = chunkSize / 5
+
+ // Not to cache mergers with large lists
+ mergerCacheMax int = 100000
+
+ // History
+ defaultHistoryMax int = 1000
+
+ // Jump labels
+ defaultJumpLabels string = "asdfghjklqwertyuiopzxcvbnm1234567890ASDFGHJKLQWERTYUIOPZXCVBNM`~;:,<.>/?'\"!@#$%^&*()[{]}-_=+"
+)
+
+var defaultCommand string
+
+func init() {
+ if !util.IsWindows() {
+ defaultCommand = `set -o pipefail; command find -L . -mindepth 1 \( -path '*/\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \) -prune -o -type f -print -o -type l -print 2> /dev/null | cut -b3-`
+ } else if os.Getenv("TERM") == "cygwin" {
+ defaultCommand = `sh -c "command find -L . -mindepth 1 -path '*/\.*' -prune -o -type f -print -o -type l -print 2> /dev/null | cut -b3-"`
+ }
+}
+
+// fzf events
+const (
+ EvtReadNew util.EventType = iota
+ EvtReadFin
+ EvtSearchNew
+ EvtSearchProgress
+ EvtSearchFin
+ EvtHeader
+ EvtReady
+ EvtQuit
+)
+
+const (
+ exitCancel = -1
+ exitOk = 0
+ exitNoMatch = 1
+ exitError = 2
+ exitInterrupt = 130
+)
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/core.go b/dot-oh-my-zsh/custom/plugins/fzf/src/core.go
new file mode 100644
index 00000000..ee55f1e3
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/core.go
@@ -0,0 +1,333 @@
+// Package fzf implements fzf, a command-line fuzzy finder.
+package fzf
+
+import (
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+/*
+Reader -> EvtReadFin
+Reader -> EvtReadNew -> Matcher (restart)
+Terminal -> EvtSearchNew:bool -> Matcher (restart)
+Matcher -> EvtSearchProgress -> Terminal (update info)
+Matcher -> EvtSearchFin -> Terminal (update list)
+Matcher -> EvtHeader -> Terminal (update header)
+*/
+
+// Run starts fzf
+func Run(opts *Options, version string, revision string) {
+ sort := opts.Sort > 0
+ sortCriteria = opts.Criteria
+
+ if opts.Version {
+ if len(revision) > 0 {
+ fmt.Printf("%s (%s)\n", version, revision)
+ } else {
+ fmt.Println(version)
+ }
+ os.Exit(exitOk)
+ }
+
+ // Event channel
+ eventBox := util.NewEventBox()
+
+ // ANSI code processor
+ ansiProcessor := func(data []byte) (util.Chars, *[]ansiOffset) {
+ return util.ToChars(data), nil
+ }
+
+ var lineAnsiState, prevLineAnsiState *ansiState
+ if opts.Ansi {
+ if opts.Theme.Colored {
+ ansiProcessor = func(data []byte) (util.Chars, *[]ansiOffset) {
+ prevLineAnsiState = lineAnsiState
+ trimmed, offsets, newState := extractColor(string(data), lineAnsiState, nil)
+ lineAnsiState = newState
+ return util.ToChars([]byte(trimmed)), offsets
+ }
+ } else {
+ // When color is disabled but ansi option is given,
+ // we simply strip out ANSI codes from the input
+ ansiProcessor = func(data []byte) (util.Chars, *[]ansiOffset) {
+ trimmed, _, _ := extractColor(string(data), nil, nil)
+ return util.ToChars([]byte(trimmed)), nil
+ }
+ }
+ }
+
+ // Chunk list
+ var chunkList *ChunkList
+ var itemIndex int32
+ header := make([]string, 0, opts.HeaderLines)
+ if len(opts.WithNth) == 0 {
+ chunkList = NewChunkList(func(item *Item, data []byte) bool {
+ if len(header) < opts.HeaderLines {
+ header = append(header, string(data))
+ eventBox.Set(EvtHeader, header)
+ return false
+ }
+ item.text, item.colors = ansiProcessor(data)
+ item.text.Index = itemIndex
+ itemIndex++
+ return true
+ })
+ } else {
+ chunkList = NewChunkList(func(item *Item, data []byte) bool {
+ tokens := Tokenize(string(data), opts.Delimiter)
+ if opts.Ansi && opts.Theme.Colored && len(tokens) > 1 {
+ var ansiState *ansiState
+ if prevLineAnsiState != nil {
+ ansiStateDup := *prevLineAnsiState
+ ansiState = &ansiStateDup
+ }
+ for _, token := range tokens {
+ prevAnsiState := ansiState
+ _, _, ansiState = extractColor(token.text.ToString(), ansiState, nil)
+ if prevAnsiState != nil {
+ token.text.Prepend("\x1b[m" + prevAnsiState.ToString())
+ } else {
+ token.text.Prepend("\x1b[m")
+ }
+ }
+ }
+ trans := Transform(tokens, opts.WithNth)
+ transformed := joinTokens(trans)
+ if len(header) < opts.HeaderLines {
+ header = append(header, transformed)
+ eventBox.Set(EvtHeader, header)
+ return false
+ }
+ item.text, item.colors = ansiProcessor([]byte(transformed))
+ item.text.TrimTrailingWhitespaces()
+ item.text.Index = itemIndex
+ item.origText = &data
+ itemIndex++
+ return true
+ })
+ }
+
+ // Reader
+ streamingFilter := opts.Filter != nil && !sort && !opts.Tac && !opts.Sync
+ var reader *Reader
+ if !streamingFilter {
+ reader = NewReader(func(data []byte) bool {
+ return chunkList.Push(data)
+ }, eventBox, opts.ReadZero, opts.Filter == nil)
+ go reader.ReadSource()
+ }
+
+ // Matcher
+ forward := true
+ withPos := false
+ for idx := len(opts.Criteria) - 1; idx > 0; idx-- {
+ switch opts.Criteria[idx] {
+ case byChunk:
+ withPos = true
+ case byEnd:
+ forward = false
+ case byBegin:
+ forward = true
+ }
+ }
+ patternBuilder := func(runes []rune) *Pattern {
+ return BuildPattern(
+ opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos,
+ opts.Filter == nil, opts.Nth, opts.Delimiter, runes)
+ }
+ matcher := NewMatcher(patternBuilder, sort, opts.Tac, eventBox)
+
+ // Filtering mode
+ if opts.Filter != nil {
+ if opts.PrintQuery {
+ opts.Printer(*opts.Filter)
+ }
+
+ pattern := patternBuilder([]rune(*opts.Filter))
+ matcher.sort = pattern.sortable
+
+ found := false
+ if streamingFilter {
+ slab := util.MakeSlab(slab16Size, slab32Size)
+ reader := NewReader(
+ func(runes []byte) bool {
+ item := Item{}
+ if chunkList.trans(&item, runes) {
+ if result, _, _ := pattern.MatchItem(&item, false, slab); result != nil {
+ opts.Printer(item.text.ToString())
+ found = true
+ }
+ }
+ return false
+ }, eventBox, opts.ReadZero, false)
+ reader.ReadSource()
+ } else {
+ eventBox.Unwatch(EvtReadNew)
+ eventBox.WaitFor(EvtReadFin)
+
+ snapshot, _ := chunkList.Snapshot()
+ merger, _ := matcher.scan(MatchRequest{
+ chunks: snapshot,
+ pattern: pattern})
+ for i := 0; i < merger.Length(); i++ {
+ opts.Printer(merger.Get(i).item.AsString(opts.Ansi))
+ found = true
+ }
+ }
+ if found {
+ os.Exit(exitOk)
+ }
+ os.Exit(exitNoMatch)
+ }
+
+ // Synchronous search
+ if opts.Sync {
+ eventBox.Unwatch(EvtReadNew)
+ eventBox.WaitFor(EvtReadFin)
+ }
+
+ // Go interactive
+ go matcher.Loop()
+
+ // Terminal I/O
+ terminal := NewTerminal(opts, eventBox)
+ deferred := opts.Select1 || opts.Exit0
+ go terminal.Loop()
+ if !deferred {
+ terminal.startChan <- true
+ }
+
+ // Event coordination
+ reading := true
+ clearCache := util.Once(false)
+ clearSelection := util.Once(false)
+ ticks := 0
+ var nextCommand *string
+ restart := func(command string) {
+ reading = true
+ clearCache = util.Once(true)
+ clearSelection = util.Once(true)
+ chunkList.Clear()
+ itemIndex = 0
+ header = make([]string, 0, opts.HeaderLines)
+ go reader.restart(command)
+ }
+ eventBox.Watch(EvtReadNew)
+ query := []rune{}
+ for {
+ delay := true
+ ticks++
+ input := func(reloaded bool) []rune {
+ paused, input := terminal.Input()
+ if reloaded && paused {
+ query = []rune{}
+ } else if !paused {
+ query = input
+ }
+ return query
+ }
+ eventBox.Wait(func(events *util.Events) {
+ if _, fin := (*events)[EvtReadFin]; fin {
+ delete(*events, EvtReadNew)
+ }
+ for evt, value := range *events {
+ switch evt {
+ case EvtQuit:
+ if reading {
+ reader.terminate()
+ }
+ os.Exit(value.(int))
+ case EvtReadNew, EvtReadFin:
+ if evt == EvtReadFin && nextCommand != nil {
+ restart(*nextCommand)
+ nextCommand = nil
+ break
+ } else {
+ reading = reading && evt == EvtReadNew
+ }
+ snapshot, count := chunkList.Snapshot()
+ terminal.UpdateCount(count, !reading, value.(*string))
+ if opts.Sync {
+ opts.Sync = false
+ terminal.UpdateList(PassMerger(&snapshot, opts.Tac), false)
+ }
+ reset := clearCache()
+ matcher.Reset(snapshot, input(reset), false, !reading, sort, reset)
+
+ case EvtSearchNew:
+ var command *string
+ switch val := value.(type) {
+ case searchRequest:
+ sort = val.sort
+ command = val.command
+ }
+ if command != nil {
+ if reading {
+ reader.terminate()
+ nextCommand = command
+ } else {
+ restart(*command)
+ }
+ break
+ }
+ snapshot, _ := chunkList.Snapshot()
+ reset := clearCache()
+ matcher.Reset(snapshot, input(reset), true, !reading, sort, reset)
+ delay = false
+
+ case EvtSearchProgress:
+ switch val := value.(type) {
+ case float32:
+ terminal.UpdateProgress(val)
+ }
+
+ case EvtHeader:
+ headerPadded := make([]string, opts.HeaderLines)
+ copy(headerPadded, value.([]string))
+ terminal.UpdateHeader(headerPadded)
+
+ case EvtSearchFin:
+ switch val := value.(type) {
+ case *Merger:
+ if deferred {
+ count := val.Length()
+ if opts.Select1 && count > 1 || opts.Exit0 && !opts.Select1 && count > 0 {
+ deferred = false
+ terminal.startChan <- true
+ } else if val.final {
+ if opts.Exit0 && count == 0 || opts.Select1 && count == 1 {
+ if opts.PrintQuery {
+ opts.Printer(opts.Query)
+ }
+ if len(opts.Expect) > 0 {
+ opts.Printer("")
+ }
+ for i := 0; i < count; i++ {
+ opts.Printer(val.Get(i).item.AsString(opts.Ansi))
+ }
+ if count > 0 {
+ os.Exit(exitOk)
+ }
+ os.Exit(exitNoMatch)
+ }
+ deferred = false
+ terminal.startChan <- true
+ }
+ }
+ terminal.UpdateList(val, clearSelection())
+ }
+ }
+ }
+ events.Clear()
+ })
+ if delay && reading {
+ dur := util.DurWithin(
+ time.Duration(ticks)*coordinatorDelayStep,
+ 0, coordinatorDelayMax)
+ time.Sleep(dur)
+ }
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/history.go b/dot-oh-my-zsh/custom/plugins/fzf/src/history.go
new file mode 100644
index 00000000..45728d40
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/history.go
@@ -0,0 +1,96 @@
+package fzf
+
+import (
+ "errors"
+ "io/ioutil"
+ "os"
+ "strings"
+)
+
+// History struct represents input history
+type History struct {
+ path string
+ lines []string
+ modified map[int]string
+ maxSize int
+ cursor int
+}
+
+// NewHistory returns the pointer to a new History struct
+func NewHistory(path string, maxSize int) (*History, error) {
+ fmtError := func(e error) error {
+ if os.IsPermission(e) {
+ return errors.New("permission denied: " + path)
+ }
+ return errors.New("invalid history file: " + e.Error())
+ }
+
+ // Read history file
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ // If it doesn't exist, check if we can create a file with the name
+ if os.IsNotExist(err) {
+ data = []byte{}
+ if err := ioutil.WriteFile(path, data, 0600); err != nil {
+ return nil, fmtError(err)
+ }
+ } else {
+ return nil, fmtError(err)
+ }
+ }
+ // Split lines and limit the maximum number of lines
+ lines := strings.Split(strings.Trim(string(data), "\n"), "\n")
+ if len(lines[len(lines)-1]) > 0 {
+ lines = append(lines, "")
+ }
+ return &History{
+ path: path,
+ maxSize: maxSize,
+ lines: lines,
+ modified: make(map[int]string),
+ cursor: len(lines) - 1}, nil
+}
+
+func (h *History) append(line string) error {
+ // We don't append empty lines
+ if len(line) == 0 {
+ return nil
+ }
+
+ lines := append(h.lines[:len(h.lines)-1], line)
+ if len(lines) > h.maxSize {
+ lines = lines[len(lines)-h.maxSize:]
+ }
+ h.lines = append(lines, "")
+ return ioutil.WriteFile(h.path, []byte(strings.Join(h.lines, "\n")), 0600)
+}
+
+func (h *History) override(str string) {
+ // You can update the history but they're not written to the file
+ if h.cursor == len(h.lines)-1 {
+ h.lines[h.cursor] = str
+ } else if h.cursor < len(h.lines)-1 {
+ h.modified[h.cursor] = str
+ }
+}
+
+func (h *History) current() string {
+ if str, prs := h.modified[h.cursor]; prs {
+ return str
+ }
+ return h.lines[h.cursor]
+}
+
+func (h *History) previous() string {
+ if h.cursor > 0 {
+ h.cursor--
+ }
+ return h.current()
+}
+
+func (h *History) next() string {
+ if h.cursor < len(h.lines)-1 {
+ h.cursor++
+ }
+ return h.current()
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/history_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/history_test.go
new file mode 100644
index 00000000..6294bde8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/history_test.go
@@ -0,0 +1,68 @@
+package fzf
+
+import (
+ "io/ioutil"
+ "os"
+ "runtime"
+ "testing"
+)
+
+func TestHistory(t *testing.T) {
+ maxHistory := 50
+
+ // Invalid arguments
+ var paths []string
+ if runtime.GOOS == "windows" {
+ // GOPATH should exist, so we shouldn't be able to override it
+ paths = []string{os.Getenv("GOPATH")}
+ } else {
+ paths = []string{"/etc", "/proc"}
+ }
+
+ for _, path := range paths {
+ if _, e := NewHistory(path, maxHistory); e == nil {
+ t.Error("Error expected for: " + path)
+ }
+ }
+
+ f, _ := ioutil.TempFile("", "fzf-history")
+ f.Close()
+
+ { // Append lines
+ h, _ := NewHistory(f.Name(), maxHistory)
+ for i := 0; i < maxHistory+10; i++ {
+ h.append("foobar")
+ }
+ }
+ { // Read lines
+ h, _ := NewHistory(f.Name(), maxHistory)
+ if len(h.lines) != maxHistory+1 {
+ t.Errorf("Expected: %d, actual: %d\n", maxHistory+1, len(h.lines))
+ }
+ for i := 0; i < maxHistory; i++ {
+ if h.lines[i] != "foobar" {
+ t.Error("Expected: foobar, actual: " + h.lines[i])
+ }
+ }
+ }
+ { // Append lines
+ h, _ := NewHistory(f.Name(), maxHistory)
+ h.append("barfoo")
+ h.append("")
+ h.append("foobarbaz")
+ }
+ { // Read lines again
+ h, _ := NewHistory(f.Name(), maxHistory)
+ if len(h.lines) != maxHistory+1 {
+ t.Errorf("Expected: %d, actual: %d\n", maxHistory+1, len(h.lines))
+ }
+ compare := func(idx int, exp string) {
+ if h.lines[idx] != exp {
+ t.Errorf("Expected: %s, actual: %s\n", exp, h.lines[idx])
+ }
+ }
+ compare(maxHistory-3, "foobar")
+ compare(maxHistory-2, "barfoo")
+ compare(maxHistory-1, "foobarbaz")
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/item.go b/dot-oh-my-zsh/custom/plugins/fzf/src/item.go
new file mode 100644
index 00000000..cb778cb9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/item.go
@@ -0,0 +1,44 @@
+package fzf
+
+import (
+ "github.com/junegunn/fzf/src/util"
+)
+
+// Item represents each input line. 56 bytes.
+type Item struct {
+ text util.Chars // 32 = 24 + 1 + 1 + 2 + 4
+ transformed *[]Token // 8
+ origText *[]byte // 8
+ colors *[]ansiOffset // 8
+}
+
+// Index returns ordinal index of the Item
+func (item *Item) Index() int32 {
+ return item.text.Index
+}
+
+var minItem = Item{text: util.Chars{Index: -1}}
+
+func (item *Item) TrimLength() uint16 {
+ return item.text.TrimLength()
+}
+
+// Colors returns ansiOffsets of the Item
+func (item *Item) Colors() []ansiOffset {
+ if item.colors == nil {
+ return []ansiOffset{}
+ }
+ return *item.colors
+}
+
+// AsString returns the original string
+func (item *Item) AsString(stripAnsi bool) string {
+ if item.origText != nil {
+ if stripAnsi {
+ trimmed, _, _ := extractColor(string(*item.origText), nil, nil)
+ return trimmed
+ }
+ return string(*item.origText)
+ }
+ return item.text.ToString()
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/item_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/item_test.go
new file mode 100644
index 00000000..1efb5f1d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/item_test.go
@@ -0,0 +1,23 @@
+package fzf
+
+import (
+ "testing"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+func TestStringPtr(t *testing.T) {
+ orig := []byte("\x1b[34mfoo")
+ text := []byte("\x1b[34mbar")
+ item := Item{origText: &orig, text: util.ToChars(text)}
+ if item.AsString(true) != "foo" || item.AsString(false) != string(orig) {
+ t.Fail()
+ }
+ if item.AsString(true) != "foo" {
+ t.Fail()
+ }
+ item.origText = nil
+ if item.AsString(true) != string(text) || item.AsString(false) != string(text) {
+ t.Fail()
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/matcher.go b/dot-oh-my-zsh/custom/plugins/fzf/src/matcher.go
new file mode 100644
index 00000000..22aa819c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/matcher.go
@@ -0,0 +1,235 @@
+package fzf
+
+import (
+ "fmt"
+ "runtime"
+ "sort"
+ "sync"
+ "time"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+// MatchRequest represents a search request
+type MatchRequest struct {
+ chunks []*Chunk
+ pattern *Pattern
+ final bool
+ sort bool
+ clearCache bool
+}
+
+// Matcher is responsible for performing search
+type Matcher struct {
+ patternBuilder func([]rune) *Pattern
+ sort bool
+ tac bool
+ eventBox *util.EventBox
+ reqBox *util.EventBox
+ partitions int
+ slab []*util.Slab
+ mergerCache map[string]*Merger
+}
+
+const (
+ reqRetry util.EventType = iota
+ reqReset
+)
+
+// NewMatcher returns a new Matcher
+func NewMatcher(patternBuilder func([]rune) *Pattern,
+ sort bool, tac bool, eventBox *util.EventBox) *Matcher {
+ partitions := util.Min(numPartitionsMultiplier*runtime.NumCPU(), maxPartitions)
+ return &Matcher{
+ patternBuilder: patternBuilder,
+ sort: sort,
+ tac: tac,
+ eventBox: eventBox,
+ reqBox: util.NewEventBox(),
+ partitions: partitions,
+ slab: make([]*util.Slab, partitions),
+ mergerCache: make(map[string]*Merger)}
+}
+
+// Loop puts Matcher in action
+func (m *Matcher) Loop() {
+ prevCount := 0
+
+ for {
+ var request MatchRequest
+
+ m.reqBox.Wait(func(events *util.Events) {
+ for _, val := range *events {
+ switch val := val.(type) {
+ case MatchRequest:
+ request = val
+ default:
+ panic(fmt.Sprintf("Unexpected type: %T", val))
+ }
+ }
+ events.Clear()
+ })
+
+ if request.sort != m.sort || request.clearCache {
+ m.sort = request.sort
+ m.mergerCache = make(map[string]*Merger)
+ clearChunkCache()
+ }
+
+ // Restart search
+ patternString := request.pattern.AsString()
+ var merger *Merger
+ cancelled := false
+ count := CountItems(request.chunks)
+
+ foundCache := false
+ if count == prevCount {
+ // Look up mergerCache
+ if cached, found := m.mergerCache[patternString]; found {
+ foundCache = true
+ merger = cached
+ }
+ } else {
+ // Invalidate mergerCache
+ prevCount = count
+ m.mergerCache = make(map[string]*Merger)
+ }
+
+ if !foundCache {
+ merger, cancelled = m.scan(request)
+ }
+
+ if !cancelled {
+ if merger.cacheable() {
+ m.mergerCache[patternString] = merger
+ }
+ merger.final = request.final
+ m.eventBox.Set(EvtSearchFin, merger)
+ }
+ }
+}
+
+func (m *Matcher) sliceChunks(chunks []*Chunk) [][]*Chunk {
+ partitions := m.partitions
+ perSlice := len(chunks) / partitions
+
+ if perSlice == 0 {
+ partitions = len(chunks)
+ perSlice = 1
+ }
+
+ slices := make([][]*Chunk, partitions)
+ for i := 0; i < partitions; i++ {
+ start := i * perSlice
+ end := start + perSlice
+ if i == partitions-1 {
+ end = len(chunks)
+ }
+ slices[i] = chunks[start:end]
+ }
+ return slices
+}
+
+type partialResult struct {
+ index int
+ matches []Result
+}
+
+func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
+ startedAt := time.Now()
+
+ numChunks := len(request.chunks)
+ if numChunks == 0 {
+ return EmptyMerger, false
+ }
+ pattern := request.pattern
+ if pattern.IsEmpty() {
+ return PassMerger(&request.chunks, m.tac), false
+ }
+
+ cancelled := util.NewAtomicBool(false)
+
+ slices := m.sliceChunks(request.chunks)
+ numSlices := len(slices)
+ resultChan := make(chan partialResult, numSlices)
+ countChan := make(chan int, numChunks)
+ waitGroup := sync.WaitGroup{}
+
+ for idx, chunks := range slices {
+ waitGroup.Add(1)
+ if m.slab[idx] == nil {
+ m.slab[idx] = util.MakeSlab(slab16Size, slab32Size)
+ }
+ go func(idx int, slab *util.Slab, chunks []*Chunk) {
+ defer func() { waitGroup.Done() }()
+ count := 0
+ allMatches := make([][]Result, len(chunks))
+ for idx, chunk := range chunks {
+ matches := request.pattern.Match(chunk, slab)
+ allMatches[idx] = matches
+ count += len(matches)
+ if cancelled.Get() {
+ return
+ }
+ countChan <- len(matches)
+ }
+ sliceMatches := make([]Result, 0, count)
+ for _, matches := range allMatches {
+ sliceMatches = append(sliceMatches, matches...)
+ }
+ if m.sort {
+ if m.tac {
+ sort.Sort(ByRelevanceTac(sliceMatches))
+ } else {
+ sort.Sort(ByRelevance(sliceMatches))
+ }
+ }
+ resultChan <- partialResult{idx, sliceMatches}
+ }(idx, m.slab[idx], chunks)
+ }
+
+ wait := func() bool {
+ cancelled.Set(true)
+ waitGroup.Wait()
+ return true
+ }
+
+ count := 0
+ matchCount := 0
+ for matchesInChunk := range countChan {
+ count++
+ matchCount += matchesInChunk
+
+ if count == numChunks {
+ break
+ }
+
+ if m.reqBox.Peek(reqReset) {
+ return nil, wait()
+ }
+
+ if time.Since(startedAt) > progressMinDuration {
+ m.eventBox.Set(EvtSearchProgress, float32(count)/float32(numChunks))
+ }
+ }
+
+ partialResults := make([][]Result, numSlices)
+ for range slices {
+ partialResult := <-resultChan
+ partialResults[partialResult.index] = partialResult.matches
+ }
+ return NewMerger(pattern, partialResults, m.sort, m.tac), false
+}
+
+// Reset is called to interrupt/signal the ongoing search
+func (m *Matcher) Reset(chunks []*Chunk, patternRunes []rune, cancel bool, final bool, sort bool, clearCache bool) {
+ pattern := m.patternBuilder(patternRunes)
+
+ var event util.EventType
+ if cancel {
+ event = reqReset
+ } else {
+ event = reqRetry
+ }
+ m.reqBox.Set(event, MatchRequest{chunks, pattern, final, sort && pattern.sortable, clearCache})
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/merger.go b/dot-oh-my-zsh/custom/plugins/fzf/src/merger.go
new file mode 100644
index 00000000..8e6a884c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/merger.go
@@ -0,0 +1,120 @@
+package fzf
+
+import "fmt"
+
+// EmptyMerger is a Merger with no data
+var EmptyMerger = NewMerger(nil, [][]Result{}, false, false)
+
+// Merger holds a set of locally sorted lists of items and provides the view of
+// a single, globally-sorted list
+type Merger struct {
+ pattern *Pattern
+ lists [][]Result
+ merged []Result
+ chunks *[]*Chunk
+ cursors []int
+ sorted bool
+ tac bool
+ final bool
+ count int
+}
+
+// PassMerger returns a new Merger that simply returns the items in the
+// original order
+func PassMerger(chunks *[]*Chunk, tac bool) *Merger {
+ mg := Merger{
+ pattern: nil,
+ chunks: chunks,
+ tac: tac,
+ count: 0}
+
+ for _, chunk := range *mg.chunks {
+ mg.count += chunk.count
+ }
+ return &mg
+}
+
+// NewMerger returns a new Merger
+func NewMerger(pattern *Pattern, lists [][]Result, sorted bool, tac bool) *Merger {
+ mg := Merger{
+ pattern: pattern,
+ lists: lists,
+ merged: []Result{},
+ chunks: nil,
+ cursors: make([]int, len(lists)),
+ sorted: sorted,
+ tac: tac,
+ final: false,
+ count: 0}
+
+ for _, list := range mg.lists {
+ mg.count += len(list)
+ }
+ return &mg
+}
+
+// Length returns the number of items
+func (mg *Merger) Length() int {
+ return mg.count
+}
+
+// Get returns the pointer to the Result object indexed by the given integer
+func (mg *Merger) Get(idx int) Result {
+ if mg.chunks != nil {
+ if mg.tac {
+ idx = mg.count - idx - 1
+ }
+ chunk := (*mg.chunks)[idx/chunkSize]
+ return Result{item: &chunk.items[idx%chunkSize]}
+ }
+
+ if mg.sorted {
+ return mg.mergedGet(idx)
+ }
+
+ if mg.tac {
+ idx = mg.count - idx - 1
+ }
+ for _, list := range mg.lists {
+ numItems := len(list)
+ if idx < numItems {
+ return list[idx]
+ }
+ idx -= numItems
+ }
+ panic(fmt.Sprintf("Index out of bounds (unsorted, %d/%d)", idx, mg.count))
+}
+
+func (mg *Merger) cacheable() bool {
+ return mg.count < mergerCacheMax
+}
+
+func (mg *Merger) mergedGet(idx int) Result {
+ for i := len(mg.merged); i <= idx; i++ {
+ minRank := minRank()
+ minIdx := -1
+ for listIdx, list := range mg.lists {
+ cursor := mg.cursors[listIdx]
+ if cursor < 0 || cursor == len(list) {
+ mg.cursors[listIdx] = -1
+ continue
+ }
+ if cursor >= 0 {
+ rank := list[cursor]
+ if minIdx < 0 || compareRanks(rank, minRank, mg.tac) {
+ minRank = rank
+ minIdx = listIdx
+ }
+ }
+ }
+
+ if minIdx >= 0 {
+ chosen := mg.lists[minIdx]
+ mg.merged = append(mg.merged, chosen[mg.cursors[minIdx]])
+ mg.cursors[minIdx]++
+ } else {
+ panic(fmt.Sprintf("Index out of bounds (sorted, %d/%d)", i, mg.count))
+ }
+ }
+ return mg.merged[idx]
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/merger_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/merger_test.go
new file mode 100644
index 00000000..c6af4f66
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/merger_test.go
@@ -0,0 +1,88 @@
+package fzf
+
+import (
+ "fmt"
+ "math/rand"
+ "sort"
+ "testing"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+func assert(t *testing.T, cond bool, msg ...string) {
+ if !cond {
+ t.Error(msg)
+ }
+}
+
+func randResult() Result {
+ str := fmt.Sprintf("%d", rand.Uint32())
+ chars := util.ToChars([]byte(str))
+ chars.Index = rand.Int31()
+ return Result{item: &Item{text: chars}}
+}
+
+func TestEmptyMerger(t *testing.T) {
+ assert(t, EmptyMerger.Length() == 0, "Not empty")
+ assert(t, EmptyMerger.count == 0, "Invalid count")
+ assert(t, len(EmptyMerger.lists) == 0, "Invalid lists")
+ assert(t, len(EmptyMerger.merged) == 0, "Invalid merged list")
+}
+
+func buildLists(partiallySorted bool) ([][]Result, []Result) {
+ numLists := 4
+ lists := make([][]Result, numLists)
+ cnt := 0
+ for i := 0; i < numLists; i++ {
+ numResults := rand.Int() % 20
+ cnt += numResults
+ lists[i] = make([]Result, numResults)
+ for j := 0; j < numResults; j++ {
+ item := randResult()
+ lists[i][j] = item
+ }
+ if partiallySorted {
+ sort.Sort(ByRelevance(lists[i]))
+ }
+ }
+ items := []Result{}
+ for _, list := range lists {
+ items = append(items, list...)
+ }
+ return lists, items
+}
+
+func TestMergerUnsorted(t *testing.T) {
+ lists, items := buildLists(false)
+ cnt := len(items)
+
+ // Not sorted: same order
+ mg := NewMerger(nil, lists, false, false)
+ assert(t, cnt == mg.Length(), "Invalid Length")
+ for i := 0; i < cnt; i++ {
+ assert(t, items[i] == mg.Get(i), "Invalid Get")
+ }
+}
+
+func TestMergerSorted(t *testing.T) {
+ lists, items := buildLists(true)
+ cnt := len(items)
+
+ // Sorted sorted order
+ mg := NewMerger(nil, lists, true, false)
+ assert(t, cnt == mg.Length(), "Invalid Length")
+ sort.Sort(ByRelevance(items))
+ for i := 0; i < cnt; i++ {
+ if items[i] != mg.Get(i) {
+ t.Error("Not sorted", items[i], mg.Get(i))
+ }
+ }
+
+ // Inverse order
+ mg2 := NewMerger(nil, lists, true, false)
+ for i := cnt - 1; i >= 0; i-- {
+ if items[i] != mg2.Get(i) {
+ t.Error("Not sorted", items[i], mg2.Get(i))
+ }
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/options.go b/dot-oh-my-zsh/custom/plugins/fzf/src/options.go
new file mode 100644
index 00000000..41782fa4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/options.go
@@ -0,0 +1,1806 @@
+package fzf
+
+import (
+ "fmt"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+ "unicode"
+
+ "github.com/junegunn/fzf/src/algo"
+ "github.com/junegunn/fzf/src/tui"
+
+ "github.com/mattn/go-runewidth"
+ "github.com/mattn/go-shellwords"
+)
+
+const usage = `usage: fzf [options]
+
+ Search
+ -x, --extended Extended-search mode
+ (enabled by default; +x or --no-extended to disable)
+ -e, --exact Enable Exact-match
+ -i Case-insensitive match (default: smart-case match)
+ +i Case-sensitive match
+ --scheme=SCHEME Scoring scheme [default|path|history]
+ --literal Do not normalize latin script letters before matching
+ -n, --nth=N[,..] Comma-separated list of field index expressions
+ for limiting search scope. Each can be a non-zero
+ integer or a range expression ([BEGIN]..[END]).
+ --with-nth=N[,..] Transform the presentation of each line using
+ field index expressions
+ -d, --delimiter=STR Field delimiter regex (default: AWK-style)
+ +s, --no-sort Do not sort the result
+ --tac Reverse the order of the input
+ --disabled Do not perform search
+ --tiebreak=CRI[,..] Comma-separated list of sort criteria to apply
+ when the scores are tied [length|chunk|begin|end|index]
+ (default: length)
+
+ Interface
+ -m, --multi[=MAX] Enable multi-select with tab/shift-tab
+ --no-mouse Disable mouse
+ --bind=KEYBINDS Custom key bindings. Refer to the man page.
+ --cycle Enable cyclic scroll
+ --keep-right Keep the right end of the line visible on overflow
+ --scroll-off=LINES Number of screen lines to keep above or below when
+ scrolling to the top or to the bottom (default: 0)
+ --no-hscroll Disable horizontal scroll
+ --hscroll-off=COLS Number of screen columns to keep to the right of the
+ highlighted substring (default: 10)
+ --filepath-word Make word-wise movements respect path separators
+ --jump-labels=CHARS Label characters for jump and jump-accept
+
+ Layout
+ --height=HEIGHT[%] Display fzf window below the cursor with the given
+ height instead of using fullscreen
+ --min-height=HEIGHT Minimum height when --height is given in percent
+ (default: 10)
+ --layout=LAYOUT Choose layout: [default|reverse|reverse-list]
+ --border[=STYLE] Draw border around the finder
+ [rounded|sharp|horizontal|vertical|
+ top|bottom|left|right|none] (default: rounded)
+ --margin=MARGIN Screen margin (TRBL | TB,RL | T,RL,B | T,R,B,L)
+ --padding=PADDING Padding inside border (TRBL | TB,RL | T,RL,B | T,R,B,L)
+ --info=STYLE Finder info style [default|inline|hidden]
+ --prompt=STR Input prompt (default: '> ')
+ --pointer=STR Pointer to the current line (default: '>')
+ --marker=STR Multi-select marker (default: '>')
+ --header=STR String to print as header
+ --header-lines=N The first N lines of the input are treated as header
+ --header-first Print header before the prompt line
+ --ellipsis=STR Ellipsis to show when line is truncated (default: '..')
+
+ Display
+ --ansi Enable processing of ANSI color codes
+ --tabstop=SPACES Number of spaces for a tab character (default: 8)
+ --color=COLSPEC Base scheme (dark|light|16|bw) and/or custom colors
+ --no-bold Do not use bold text
+
+ History
+ --history=FILE History file
+ --history-size=N Maximum number of history entries (default: 1000)
+
+ Preview
+ --preview=COMMAND Command to preview highlighted line ({})
+ --preview-window=OPT Preview window layout (default: right:50%)
+ [up|down|left|right][,SIZE[%]]
+ [,[no]wrap][,[no]cycle][,[no]follow][,[no]hidden]
+ [,border-BORDER_OPT]
+ [,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES]
+ [,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]
+
+ Scripting
+ -q, --query=STR Start the finder with the given query
+ -1, --select-1 Automatically select the only match
+ -0, --exit-0 Exit immediately when there's no match
+ -f, --filter=STR Filter mode. Do not start interactive finder.
+ --print-query Print query as the first line
+ --expect=KEYS Comma-separated list of keys to complete fzf
+ --read0 Read input delimited by ASCII NUL characters
+ --print0 Print output delimited by ASCII NUL characters
+ --sync Synchronous search for multi-staged filtering
+ --version Display version information and exit
+
+ Environment variables
+ FZF_DEFAULT_COMMAND Default command to use when input is tty
+ FZF_DEFAULT_OPTS Default options
+ (e.g. '--layout=reverse --inline-info')
+
+`
+
+// Case denotes case-sensitivity of search
+type Case int
+
+// Case-sensitivities
+const (
+ CaseSmart Case = iota
+ CaseIgnore
+ CaseRespect
+)
+
+// Sort criteria
+type criterion int
+
+const (
+ byScore criterion = iota
+ byChunk
+ byLength
+ byBegin
+ byEnd
+)
+
+type sizeSpec struct {
+ size float64
+ percent bool
+}
+
+func defaultMargin() [4]sizeSpec {
+ return [4]sizeSpec{}
+}
+
+type windowPosition int
+
+const (
+ posUp windowPosition = iota
+ posDown
+ posLeft
+ posRight
+)
+
+type layoutType int
+
+const (
+ layoutDefault layoutType = iota
+ layoutReverse
+ layoutReverseList
+)
+
+type infoStyle int
+
+const (
+ infoDefault infoStyle = iota
+ infoInline
+ infoHidden
+)
+
+type previewOpts struct {
+ command string
+ position windowPosition
+ size sizeSpec
+ scroll string
+ hidden bool
+ wrap bool
+ cycle bool
+ follow bool
+ border tui.BorderShape
+ headerLines int
+ threshold int
+ alternative *previewOpts
+}
+
+func (a previewOpts) sameLayout(b previewOpts) bool {
+ return a.size == b.size && a.position == b.position && a.border == b.border && a.hidden == b.hidden && a.threshold == b.threshold &&
+ (a.alternative != nil && b.alternative != nil && a.alternative.sameLayout(*b.alternative) ||
+ a.alternative == nil && b.alternative == nil)
+}
+
+func (a previewOpts) sameContentLayout(b previewOpts) bool {
+ return a.wrap == b.wrap && a.headerLines == b.headerLines
+}
+
+// Options stores the values of command-line options
+type Options struct {
+ Fuzzy bool
+ FuzzyAlgo algo.Algo
+ Scheme string
+ Extended bool
+ Phony bool
+ Case Case
+ Normalize bool
+ Nth []Range
+ WithNth []Range
+ Delimiter Delimiter
+ Sort int
+ Tac bool
+ Criteria []criterion
+ Multi int
+ Ansi bool
+ Mouse bool
+ Theme *tui.ColorTheme
+ Black bool
+ Bold bool
+ Height sizeSpec
+ MinHeight int
+ Layout layoutType
+ Cycle bool
+ KeepRight bool
+ Hscroll bool
+ HscrollOff int
+ ScrollOff int
+ FileWord bool
+ InfoStyle infoStyle
+ JumpLabels string
+ Prompt string
+ Pointer string
+ Marker string
+ Query string
+ Select1 bool
+ Exit0 bool
+ Filter *string
+ ToggleSort bool
+ Expect map[tui.Event]string
+ Keymap map[tui.Event][]*action
+ Preview previewOpts
+ PrintQuery bool
+ ReadZero bool
+ Printer func(string)
+ PrintSep string
+ Sync bool
+ History *History
+ Header []string
+ HeaderLines int
+ HeaderFirst bool
+ Ellipsis string
+ Margin [4]sizeSpec
+ Padding [4]sizeSpec
+ BorderShape tui.BorderShape
+ Unicode bool
+ Tabstop int
+ ClearOnExit bool
+ Version bool
+}
+
+func defaultPreviewOpts(command string) previewOpts {
+ return previewOpts{command, posRight, sizeSpec{50, true}, "", false, false, false, false, tui.BorderRounded, 0, 0, nil}
+}
+
+func defaultOptions() *Options {
+ return &Options{
+ Fuzzy: true,
+ FuzzyAlgo: algo.FuzzyMatchV2,
+ Scheme: "default",
+ Extended: true,
+ Phony: false,
+ Case: CaseSmart,
+ Normalize: true,
+ Nth: make([]Range, 0),
+ WithNth: make([]Range, 0),
+ Delimiter: Delimiter{},
+ Sort: 1000,
+ Tac: false,
+ Criteria: []criterion{byScore, byLength},
+ Multi: 0,
+ Ansi: false,
+ Mouse: true,
+ Theme: tui.EmptyTheme(),
+ Black: false,
+ Bold: true,
+ MinHeight: 10,
+ Layout: layoutDefault,
+ Cycle: false,
+ KeepRight: false,
+ Hscroll: true,
+ HscrollOff: 10,
+ ScrollOff: 0,
+ FileWord: false,
+ InfoStyle: infoDefault,
+ JumpLabels: defaultJumpLabels,
+ Prompt: "> ",
+ Pointer: ">",
+ Marker: ">",
+ Query: "",
+ Select1: false,
+ Exit0: false,
+ Filter: nil,
+ ToggleSort: false,
+ Expect: make(map[tui.Event]string),
+ Keymap: make(map[tui.Event][]*action),
+ Preview: defaultPreviewOpts(""),
+ PrintQuery: false,
+ ReadZero: false,
+ Printer: func(str string) { fmt.Println(str) },
+ PrintSep: "\n",
+ Sync: false,
+ History: nil,
+ Header: make([]string, 0),
+ HeaderLines: 0,
+ HeaderFirst: false,
+ Ellipsis: "..",
+ Margin: defaultMargin(),
+ Padding: defaultMargin(),
+ Unicode: true,
+ Tabstop: 8,
+ ClearOnExit: true,
+ Version: false}
+}
+
+func help(code int) {
+ os.Stdout.WriteString(usage)
+ os.Exit(code)
+}
+
+func errorExit(msg string) {
+ os.Stderr.WriteString(msg + "\n")
+ os.Exit(exitError)
+}
+
+func optString(arg string, prefixes ...string) (bool, string) {
+ for _, prefix := range prefixes {
+ if strings.HasPrefix(arg, prefix) {
+ return true, arg[len(prefix):]
+ }
+ }
+ return false, ""
+}
+
+func nextString(args []string, i *int, message string) string {
+ if len(args) > *i+1 {
+ *i++
+ } else {
+ errorExit(message)
+ }
+ return args[*i]
+}
+
+func optionalNextString(args []string, i *int) (bool, string) {
+ if len(args) > *i+1 && !strings.HasPrefix(args[*i+1], "-") && !strings.HasPrefix(args[*i+1], "+") {
+ *i++
+ return true, args[*i]
+ }
+ return false, ""
+}
+
+func atoi(str string) int {
+ num, err := strconv.Atoi(str)
+ if err != nil {
+ errorExit("not a valid integer: " + str)
+ }
+ return num
+}
+
+func atof(str string) float64 {
+ num, err := strconv.ParseFloat(str, 64)
+ if err != nil {
+ errorExit("not a valid number: " + str)
+ }
+ return num
+}
+
+func nextInt(args []string, i *int, message string) int {
+ if len(args) > *i+1 {
+ *i++
+ } else {
+ errorExit(message)
+ }
+ return atoi(args[*i])
+}
+
+func optionalNumeric(args []string, i *int, defaultValue int) int {
+ if len(args) > *i+1 {
+ if strings.IndexAny(args[*i+1], "0123456789") == 0 {
+ *i++
+ return atoi(args[*i])
+ }
+ }
+ return defaultValue
+}
+
+func splitNth(str string) []Range {
+ if match, _ := regexp.MatchString("^[0-9,-.]+$", str); !match {
+ errorExit("invalid format: " + str)
+ }
+
+ tokens := strings.Split(str, ",")
+ ranges := make([]Range, len(tokens))
+ for idx, s := range tokens {
+ r, ok := ParseRange(&s)
+ if !ok {
+ errorExit("invalid format: " + str)
+ }
+ ranges[idx] = r
+ }
+ return ranges
+}
+
+func delimiterRegexp(str string) Delimiter {
+ // Special handling of \t
+ str = strings.Replace(str, "\\t", "\t", -1)
+
+ // 1. Pattern does not contain any special character
+ if regexp.QuoteMeta(str) == str {
+ return Delimiter{str: &str}
+ }
+
+ rx, e := regexp.Compile(str)
+ // 2. Pattern is not a valid regular expression
+ if e != nil {
+ return Delimiter{str: &str}
+ }
+
+ // 3. Pattern as regular expression. Slow.
+ return Delimiter{regex: rx}
+}
+
+func isAlphabet(char uint8) bool {
+ return char >= 'a' && char <= 'z'
+}
+
+func isNumeric(char uint8) bool {
+ return char >= '0' && char <= '9'
+}
+
+func parseAlgo(str string) algo.Algo {
+ switch str {
+ case "v1":
+ return algo.FuzzyMatchV1
+ case "v2":
+ return algo.FuzzyMatchV2
+ default:
+ errorExit("invalid algorithm (expected: v1 or v2)")
+ }
+ return algo.FuzzyMatchV2
+}
+
+func processScheme(opts *Options) {
+ if !algo.Init(opts.Scheme) {
+ errorExit("invalid scoring scheme (expected: default|path|history)")
+ }
+ if opts.Scheme == "history" {
+ opts.Criteria = []criterion{byScore}
+ }
+}
+
+func parseBorder(str string, optional bool) tui.BorderShape {
+ switch str {
+ case "rounded":
+ return tui.BorderRounded
+ case "sharp":
+ return tui.BorderSharp
+ case "horizontal":
+ return tui.BorderHorizontal
+ case "vertical":
+ return tui.BorderVertical
+ case "top":
+ return tui.BorderTop
+ case "bottom":
+ return tui.BorderBottom
+ case "left":
+ return tui.BorderLeft
+ case "right":
+ return tui.BorderRight
+ case "none":
+ return tui.BorderNone
+ default:
+ if optional && str == "" {
+ return tui.BorderRounded
+ }
+ errorExit("invalid border style (expected: rounded|sharp|horizontal|vertical|top|bottom|left|right|none)")
+ }
+ return tui.BorderNone
+}
+
+func parseKeyChords(str string, message string) map[tui.Event]string {
+ if len(str) == 0 {
+ errorExit(message)
+ }
+
+ str = regexp.MustCompile("(?i)(alt-),").ReplaceAllString(str, "$1"+string([]rune{escapedComma}))
+ tokens := strings.Split(str, ",")
+ if str == "," || strings.HasPrefix(str, ",,") || strings.HasSuffix(str, ",,") || strings.Contains(str, ",,,") {
+ tokens = append(tokens, ",")
+ }
+
+ chords := make(map[tui.Event]string)
+ for _, key := range tokens {
+ if len(key) == 0 {
+ continue // ignore
+ }
+ key = strings.ReplaceAll(key, string([]rune{escapedComma}), ",")
+ lkey := strings.ToLower(key)
+ add := func(e tui.EventType) {
+ chords[e.AsEvent()] = key
+ }
+ switch lkey {
+ case "up":
+ add(tui.Up)
+ case "down":
+ add(tui.Down)
+ case "left":
+ add(tui.Left)
+ case "right":
+ add(tui.Right)
+ case "enter", "return":
+ add(tui.CtrlM)
+ case "space":
+ chords[tui.Key(' ')] = key
+ case "bspace", "bs":
+ add(tui.BSpace)
+ case "ctrl-space":
+ add(tui.CtrlSpace)
+ case "ctrl-^", "ctrl-6":
+ add(tui.CtrlCaret)
+ case "ctrl-/", "ctrl-_":
+ add(tui.CtrlSlash)
+ case "ctrl-\\":
+ add(tui.CtrlBackSlash)
+ case "ctrl-]":
+ add(tui.CtrlRightBracket)
+ case "change":
+ add(tui.Change)
+ case "backward-eof":
+ add(tui.BackwardEOF)
+ case "alt-enter", "alt-return":
+ chords[tui.CtrlAltKey('m')] = key
+ case "alt-space":
+ chords[tui.AltKey(' ')] = key
+ case "alt-bs", "alt-bspace":
+ add(tui.AltBS)
+ case "alt-up":
+ add(tui.AltUp)
+ case "alt-down":
+ add(tui.AltDown)
+ case "alt-left":
+ add(tui.AltLeft)
+ case "alt-right":
+ add(tui.AltRight)
+ case "tab":
+ add(tui.Tab)
+ case "btab", "shift-tab":
+ add(tui.BTab)
+ case "esc":
+ add(tui.ESC)
+ case "del":
+ add(tui.Del)
+ case "home":
+ add(tui.Home)
+ case "end":
+ add(tui.End)
+ case "insert":
+ add(tui.Insert)
+ case "pgup", "page-up":
+ add(tui.PgUp)
+ case "pgdn", "page-down":
+ add(tui.PgDn)
+ case "alt-shift-up", "shift-alt-up":
+ add(tui.AltSUp)
+ case "alt-shift-down", "shift-alt-down":
+ add(tui.AltSDown)
+ case "alt-shift-left", "shift-alt-left":
+ add(tui.AltSLeft)
+ case "alt-shift-right", "shift-alt-right":
+ add(tui.AltSRight)
+ case "shift-up":
+ add(tui.SUp)
+ case "shift-down":
+ add(tui.SDown)
+ case "shift-left":
+ add(tui.SLeft)
+ case "shift-right":
+ add(tui.SRight)
+ case "left-click":
+ add(tui.LeftClick)
+ case "right-click":
+ add(tui.RightClick)
+ case "double-click":
+ add(tui.DoubleClick)
+ case "f10":
+ add(tui.F10)
+ case "f11":
+ add(tui.F11)
+ case "f12":
+ add(tui.F12)
+ default:
+ runes := []rune(key)
+ if len(key) == 10 && strings.HasPrefix(lkey, "ctrl-alt-") && isAlphabet(lkey[9]) {
+ chords[tui.CtrlAltKey(rune(key[9]))] = key
+ } else if len(key) == 6 && strings.HasPrefix(lkey, "ctrl-") && isAlphabet(lkey[5]) {
+ add(tui.EventType(tui.CtrlA.Int() + int(lkey[5]) - 'a'))
+ } else if len(runes) == 5 && strings.HasPrefix(lkey, "alt-") {
+ r := runes[4]
+ switch r {
+ case escapedColon:
+ r = ':'
+ case escapedComma:
+ r = ','
+ case escapedPlus:
+ r = '+'
+ }
+ chords[tui.AltKey(r)] = key
+ } else if len(key) == 2 && strings.HasPrefix(lkey, "f") && key[1] >= '1' && key[1] <= '9' {
+ add(tui.EventType(tui.F1.Int() + int(key[1]) - '1'))
+ } else if len(runes) == 1 {
+ chords[tui.Key(runes[0])] = key
+ } else {
+ errorExit("unsupported key: " + key)
+ }
+ }
+ }
+ return chords
+}
+
+func parseTiebreak(str string) []criterion {
+ criteria := []criterion{byScore}
+ hasIndex := false
+ hasChunk := false
+ hasLength := false
+ hasBegin := false
+ hasEnd := false
+ check := func(notExpected *bool, name string) {
+ if *notExpected {
+ errorExit("duplicate sort criteria: " + name)
+ }
+ if hasIndex {
+ errorExit("index should be the last criterion")
+ }
+ *notExpected = true
+ }
+ for _, str := range strings.Split(strings.ToLower(str), ",") {
+ switch str {
+ case "index":
+ check(&hasIndex, "index")
+ case "chunk":
+ check(&hasChunk, "chunk")
+ criteria = append(criteria, byChunk)
+ case "length":
+ check(&hasLength, "length")
+ criteria = append(criteria, byLength)
+ case "begin":
+ check(&hasBegin, "begin")
+ criteria = append(criteria, byBegin)
+ case "end":
+ check(&hasEnd, "end")
+ criteria = append(criteria, byEnd)
+ default:
+ errorExit("invalid sort criterion: " + str)
+ }
+ }
+ if len(criteria) > 4 {
+ errorExit("at most 3 tiebreaks are allowed: " + str)
+ }
+ return criteria
+}
+
+func dupeTheme(theme *tui.ColorTheme) *tui.ColorTheme {
+ dupe := *theme
+ return &dupe
+}
+
+func parseTheme(defaultTheme *tui.ColorTheme, str string) *tui.ColorTheme {
+ theme := dupeTheme(defaultTheme)
+ rrggbb := regexp.MustCompile("^#[0-9a-fA-F]{6}$")
+ for _, str := range strings.Split(strings.ToLower(str), ",") {
+ switch str {
+ case "dark":
+ theme = dupeTheme(tui.Dark256)
+ case "light":
+ theme = dupeTheme(tui.Light256)
+ case "16":
+ theme = dupeTheme(tui.Default16)
+ case "bw", "no":
+ theme = tui.NoColorTheme()
+ default:
+ fail := func() {
+ errorExit("invalid color specification: " + str)
+ }
+ // Color is disabled
+ if theme == nil {
+ continue
+ }
+
+ components := strings.Split(str, ":")
+ if len(components) < 2 {
+ fail()
+ }
+
+ mergeAttr := func(cattr *tui.ColorAttr) {
+ for _, component := range components[1:] {
+ switch component {
+ case "regular":
+ cattr.Attr = tui.AttrRegular
+ case "bold", "strong":
+ cattr.Attr |= tui.Bold
+ case "dim":
+ cattr.Attr |= tui.Dim
+ case "italic":
+ cattr.Attr |= tui.Italic
+ case "underline":
+ cattr.Attr |= tui.Underline
+ case "blink":
+ cattr.Attr |= tui.Blink
+ case "reverse":
+ cattr.Attr |= tui.Reverse
+ case "strikethrough":
+ cattr.Attr |= tui.StrikeThrough
+ case "black":
+ cattr.Color = tui.Color(0)
+ case "red":
+ cattr.Color = tui.Color(1)
+ case "green":
+ cattr.Color = tui.Color(2)
+ case "yellow":
+ cattr.Color = tui.Color(3)
+ case "blue":
+ cattr.Color = tui.Color(4)
+ case "magenta":
+ cattr.Color = tui.Color(5)
+ case "cyan":
+ cattr.Color = tui.Color(6)
+ case "white":
+ cattr.Color = tui.Color(7)
+ case "bright-black", "gray", "grey":
+ cattr.Color = tui.Color(8)
+ case "bright-red":
+ cattr.Color = tui.Color(9)
+ case "bright-green":
+ cattr.Color = tui.Color(10)
+ case "bright-yellow":
+ cattr.Color = tui.Color(11)
+ case "bright-blue":
+ cattr.Color = tui.Color(12)
+ case "bright-magenta":
+ cattr.Color = tui.Color(13)
+ case "bright-cyan":
+ cattr.Color = tui.Color(14)
+ case "bright-white":
+ cattr.Color = tui.Color(15)
+ case "":
+ default:
+ if rrggbb.MatchString(component) {
+ cattr.Color = tui.HexToColor(component)
+ } else {
+ ansi32, err := strconv.Atoi(component)
+ if err != nil || ansi32 < -1 || ansi32 > 255 {
+ fail()
+ }
+ cattr.Color = tui.Color(ansi32)
+ }
+ }
+ }
+ }
+ switch components[0] {
+ case "query", "input":
+ mergeAttr(&theme.Input)
+ case "disabled":
+ mergeAttr(&theme.Disabled)
+ case "fg":
+ mergeAttr(&theme.Fg)
+ case "bg":
+ mergeAttr(&theme.Bg)
+ case "preview-fg":
+ mergeAttr(&theme.PreviewFg)
+ case "preview-bg":
+ mergeAttr(&theme.PreviewBg)
+ case "fg+":
+ mergeAttr(&theme.Current)
+ case "bg+":
+ mergeAttr(&theme.DarkBg)
+ case "gutter":
+ mergeAttr(&theme.Gutter)
+ case "hl":
+ mergeAttr(&theme.Match)
+ case "hl+":
+ mergeAttr(&theme.CurrentMatch)
+ case "border":
+ mergeAttr(&theme.Border)
+ case "prompt":
+ mergeAttr(&theme.Prompt)
+ case "spinner":
+ mergeAttr(&theme.Spinner)
+ case "info":
+ mergeAttr(&theme.Info)
+ case "pointer":
+ mergeAttr(&theme.Cursor)
+ case "marker":
+ mergeAttr(&theme.Selected)
+ case "header":
+ mergeAttr(&theme.Header)
+ default:
+ fail()
+ }
+ }
+ }
+ return theme
+}
+
+var executeRegexp *regexp.Regexp
+
+func firstKey(keymap map[tui.Event]string) tui.Event {
+ for k := range keymap {
+ return k
+ }
+ return tui.EventType(0).AsEvent()
+}
+
+const (
+ escapedColon = 0
+ escapedComma = 1
+ escapedPlus = 2
+)
+
+func init() {
+ // Backreferences are not supported.
+ // "~!@#$%^&*;/|".each_char.map { |c| Regexp.escape(c) }.map { |c| "#{c}[^#{c}]*#{c}" }.join('|')
+ executeRegexp = regexp.MustCompile(
+ `(?si)[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|(?:re|un)bind):.+|[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|(?:re|un)bind)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`)
+}
+
+func parseKeymap(keymap map[tui.Event][]*action, str string) {
+ masked := executeRegexp.ReplaceAllStringFunc(str, func(src string) string {
+ symbol := ":"
+ if strings.HasPrefix(src, "+") {
+ symbol = "+"
+ }
+ prefix := symbol + "execute"
+ if strings.HasPrefix(src[1:], "reload") {
+ prefix = symbol + "reload"
+ } else if strings.HasPrefix(src[1:], "change-preview-window") {
+ prefix = symbol + "change-preview-window"
+ } else if strings.HasPrefix(src[1:], "change-preview") {
+ prefix = symbol + "change-preview"
+ } else if strings.HasPrefix(src[1:], "preview") {
+ prefix = symbol + "preview"
+ } else if strings.HasPrefix(src[1:], "unbind") {
+ prefix = symbol + "unbind"
+ } else if strings.HasPrefix(src[1:], "rebind") {
+ prefix = symbol + "rebind"
+ } else if strings.HasPrefix(src[1:], "change-prompt") {
+ prefix = symbol + "change-prompt"
+ } else if src[len(prefix)] == '-' {
+ c := src[len(prefix)+1]
+ if c == 's' || c == 'S' {
+ prefix += "-silent"
+ } else {
+ prefix += "-multi"
+ }
+ }
+ return prefix + "(" + strings.Repeat(" ", len(src)-len(prefix)-2) + ")"
+ })
+ masked = strings.Replace(masked, "::", string([]rune{escapedColon, ':'}), -1)
+ masked = strings.Replace(masked, ",:", string([]rune{escapedComma, ':'}), -1)
+ masked = strings.Replace(masked, "+:", string([]rune{escapedPlus, ':'}), -1)
+
+ idx := 0
+ for _, pairStr := range strings.Split(masked, ",") {
+ origPairStr := str[idx : idx+len(pairStr)]
+ idx += len(pairStr) + 1
+
+ pair := strings.SplitN(pairStr, ":", 2)
+ if len(pair) < 2 {
+ errorExit("bind action not specified: " + origPairStr)
+ }
+ var key tui.Event
+ if len(pair[0]) == 1 && pair[0][0] == escapedColon {
+ key = tui.Key(':')
+ } else if len(pair[0]) == 1 && pair[0][0] == escapedComma {
+ key = tui.Key(',')
+ } else if len(pair[0]) == 1 && pair[0][0] == escapedPlus {
+ key = tui.Key('+')
+ } else {
+ keys := parseKeyChords(pair[0], "key name required")
+ key = firstKey(keys)
+ }
+
+ idx2 := len(pair[0]) + 1
+ specs := strings.Split(pair[1], "+")
+ actions := make([]*action, 0, len(specs))
+ appendAction := func(types ...actionType) {
+ actions = append(actions, toActions(types...)...)
+ }
+ prevSpec := ""
+ for specIndex, maskedSpec := range specs {
+ spec := origPairStr[idx2 : idx2+len(maskedSpec)]
+ idx2 += len(maskedSpec) + 1
+ spec = prevSpec + spec
+ specLower := strings.ToLower(spec)
+ switch specLower {
+ case "ignore":
+ appendAction(actIgnore)
+ case "beginning-of-line":
+ appendAction(actBeginningOfLine)
+ case "abort":
+ appendAction(actAbort)
+ case "accept":
+ appendAction(actAccept)
+ case "accept-non-empty":
+ appendAction(actAcceptNonEmpty)
+ case "print-query":
+ appendAction(actPrintQuery)
+ case "refresh-preview":
+ appendAction(actRefreshPreview)
+ case "replace-query":
+ appendAction(actReplaceQuery)
+ case "backward-char":
+ appendAction(actBackwardChar)
+ case "backward-delete-char":
+ appendAction(actBackwardDeleteChar)
+ case "backward-delete-char/eof":
+ appendAction(actBackwardDeleteCharEOF)
+ case "backward-word":
+ appendAction(actBackwardWord)
+ case "clear-screen":
+ appendAction(actClearScreen)
+ case "delete-char":
+ appendAction(actDeleteChar)
+ case "delete-char/eof":
+ appendAction(actDeleteCharEOF)
+ case "deselect":
+ appendAction(actDeselect)
+ case "end-of-line":
+ appendAction(actEndOfLine)
+ case "cancel":
+ appendAction(actCancel)
+ case "clear-query":
+ appendAction(actClearQuery)
+ case "clear-selection":
+ appendAction(actClearSelection)
+ case "forward-char":
+ appendAction(actForwardChar)
+ case "forward-word":
+ appendAction(actForwardWord)
+ case "jump":
+ appendAction(actJump)
+ case "jump-accept":
+ appendAction(actJumpAccept)
+ case "kill-line":
+ appendAction(actKillLine)
+ case "kill-word":
+ appendAction(actKillWord)
+ case "unix-line-discard", "line-discard":
+ appendAction(actUnixLineDiscard)
+ case "unix-word-rubout", "word-rubout":
+ appendAction(actUnixWordRubout)
+ case "yank":
+ appendAction(actYank)
+ case "backward-kill-word":
+ appendAction(actBackwardKillWord)
+ case "toggle-down":
+ appendAction(actToggle, actDown)
+ case "toggle-up":
+ appendAction(actToggle, actUp)
+ case "toggle-in":
+ appendAction(actToggleIn)
+ case "toggle-out":
+ appendAction(actToggleOut)
+ case "toggle-all":
+ appendAction(actToggleAll)
+ case "toggle-search":
+ appendAction(actToggleSearch)
+ case "select":
+ appendAction(actSelect)
+ case "select-all":
+ appendAction(actSelectAll)
+ case "deselect-all":
+ appendAction(actDeselectAll)
+ case "close":
+ appendAction(actClose)
+ case "toggle":
+ appendAction(actToggle)
+ case "down":
+ appendAction(actDown)
+ case "up":
+ appendAction(actUp)
+ case "first", "top":
+ appendAction(actFirst)
+ case "last":
+ appendAction(actLast)
+ case "page-up":
+ appendAction(actPageUp)
+ case "page-down":
+ appendAction(actPageDown)
+ case "half-page-up":
+ appendAction(actHalfPageUp)
+ case "half-page-down":
+ appendAction(actHalfPageDown)
+ case "previous-history":
+ appendAction(actPreviousHistory)
+ case "next-history":
+ appendAction(actNextHistory)
+ case "toggle-preview":
+ appendAction(actTogglePreview)
+ case "toggle-preview-wrap":
+ appendAction(actTogglePreviewWrap)
+ case "toggle-sort":
+ appendAction(actToggleSort)
+ case "preview-top":
+ appendAction(actPreviewTop)
+ case "preview-bottom":
+ appendAction(actPreviewBottom)
+ case "preview-up":
+ appendAction(actPreviewUp)
+ case "preview-down":
+ appendAction(actPreviewDown)
+ case "preview-page-up":
+ appendAction(actPreviewPageUp)
+ case "preview-page-down":
+ appendAction(actPreviewPageDown)
+ case "preview-half-page-up":
+ appendAction(actPreviewHalfPageUp)
+ case "preview-half-page-down":
+ appendAction(actPreviewHalfPageDown)
+ case "enable-search":
+ appendAction(actEnableSearch)
+ case "disable-search":
+ appendAction(actDisableSearch)
+ case "put":
+ if key.Type == tui.Rune && unicode.IsGraphic(key.Char) {
+ appendAction(actRune)
+ } else {
+ errorExit("unable to put non-printable character: " + pair[0])
+ }
+ default:
+ t := isExecuteAction(specLower)
+ if t == actIgnore {
+ if specIndex == 0 && specLower == "" {
+ actions = append(keymap[key], actions...)
+ } else {
+ errorExit("unknown action: " + spec)
+ }
+ } else {
+ var offset int
+ switch t {
+ case actReload:
+ offset = len("reload")
+ case actPreview:
+ offset = len("preview")
+ case actChangePreviewWindow:
+ offset = len("change-preview-window")
+ case actChangePreview:
+ offset = len("change-preview")
+ case actChangePrompt:
+ offset = len("change-prompt")
+ case actUnbind:
+ offset = len("unbind")
+ case actRebind:
+ offset = len("rebind")
+ case actExecuteSilent:
+ offset = len("execute-silent")
+ case actExecuteMulti:
+ offset = len("execute-multi")
+ default:
+ offset = len("execute")
+ }
+ var actionArg string
+ if spec[offset] == ':' {
+ if specIndex == len(specs)-1 {
+ actionArg = spec[offset+1:]
+ actions = append(actions, &action{t: t, a: actionArg})
+ } else {
+ prevSpec = spec + "+"
+ continue
+ }
+ } else {
+ actionArg = spec[offset+1 : len(spec)-1]
+ actions = append(actions, &action{t: t, a: actionArg})
+ }
+ if t == actUnbind || t == actRebind {
+ parseKeyChords(actionArg, spec[0:offset]+" target required")
+ } else if t == actChangePreviewWindow {
+ opts := previewOpts{}
+ for _, arg := range strings.Split(actionArg, "|") {
+ parsePreviewWindow(&opts, arg)
+ }
+ }
+ }
+ }
+ prevSpec = ""
+ }
+ keymap[key] = actions
+ }
+}
+
+func isExecuteAction(str string) actionType {
+ matches := executeRegexp.FindAllStringSubmatch(":"+str, -1)
+ if matches == nil || len(matches) != 1 {
+ return actIgnore
+ }
+ prefix := matches[0][1]
+ if len(prefix) == 0 {
+ prefix = matches[0][2]
+ }
+ switch prefix {
+ case "reload":
+ return actReload
+ case "unbind":
+ return actUnbind
+ case "rebind":
+ return actRebind
+ case "preview":
+ return actPreview
+ case "change-preview-window":
+ return actChangePreviewWindow
+ case "change-preview":
+ return actChangePreview
+ case "change-prompt":
+ return actChangePrompt
+ case "execute":
+ return actExecute
+ case "execute-silent":
+ return actExecuteSilent
+ case "execute-multi":
+ return actExecuteMulti
+ }
+ return actIgnore
+}
+
+func parseToggleSort(keymap map[tui.Event][]*action, str string) {
+ keys := parseKeyChords(str, "key name required")
+ if len(keys) != 1 {
+ errorExit("multiple keys specified")
+ }
+ keymap[firstKey(keys)] = toActions(actToggleSort)
+}
+
+func strLines(str string) []string {
+ return strings.Split(strings.TrimSuffix(str, "\n"), "\n")
+}
+
+func parseSize(str string, maxPercent float64, label string) sizeSpec {
+ var val float64
+ percent := strings.HasSuffix(str, "%")
+ if percent {
+ val = atof(str[:len(str)-1])
+ if val < 0 {
+ errorExit(label + " must be non-negative")
+ }
+ if val > maxPercent {
+ errorExit(fmt.Sprintf("%s too large (max: %d%%)", label, int(maxPercent)))
+ }
+ } else {
+ if strings.Contains(str, ".") {
+ errorExit(label + " (without %) must be a non-negative integer")
+ }
+
+ val = float64(atoi(str))
+ if val < 0 {
+ errorExit(label + " must be non-negative")
+ }
+ }
+ return sizeSpec{val, percent}
+}
+
+func parseHeight(str string) sizeSpec {
+ size := parseSize(str, 100, "height")
+ return size
+}
+
+func parseLayout(str string) layoutType {
+ switch str {
+ case "default":
+ return layoutDefault
+ case "reverse":
+ return layoutReverse
+ case "reverse-list":
+ return layoutReverseList
+ default:
+ errorExit("invalid layout (expected: default / reverse / reverse-list)")
+ }
+ return layoutDefault
+}
+
+func parseInfoStyle(str string) infoStyle {
+ switch str {
+ case "default":
+ return infoDefault
+ case "inline":
+ return infoInline
+ case "hidden":
+ return infoHidden
+ default:
+ errorExit("invalid info style (expected: default / inline / hidden)")
+ }
+ return infoDefault
+}
+
+func parsePreviewWindow(opts *previewOpts, input string) {
+ tokenRegex := regexp.MustCompile(`[:,]*(<([1-9][0-9]*)\(([^)<]+)\)|[^,:]+)`)
+ sizeRegex := regexp.MustCompile("^[0-9]+%?$")
+ offsetRegex := regexp.MustCompile(`^(\+{-?[0-9]+})?([+-][0-9]+)*(-?/[1-9][0-9]*)?$`)
+ headerRegex := regexp.MustCompile("^~(0|[1-9][0-9]*)$")
+ tokens := tokenRegex.FindAllStringSubmatch(input, -1)
+ var alternative string
+ for _, match := range tokens {
+ if len(match[2]) > 0 {
+ opts.threshold = atoi(match[2])
+ alternative = match[3]
+ continue
+ }
+ token := match[1]
+ switch token {
+ case "":
+ case "default":
+ *opts = defaultPreviewOpts(opts.command)
+ case "hidden":
+ opts.hidden = true
+ case "nohidden":
+ opts.hidden = false
+ case "wrap":
+ opts.wrap = true
+ case "nowrap":
+ opts.wrap = false
+ case "cycle":
+ opts.cycle = true
+ case "nocycle":
+ opts.cycle = false
+ case "up", "top":
+ opts.position = posUp
+ case "down", "bottom":
+ opts.position = posDown
+ case "left":
+ opts.position = posLeft
+ case "right":
+ opts.position = posRight
+ case "rounded", "border", "border-rounded":
+ opts.border = tui.BorderRounded
+ case "sharp", "border-sharp":
+ opts.border = tui.BorderSharp
+ case "noborder", "border-none":
+ opts.border = tui.BorderNone
+ case "border-horizontal":
+ opts.border = tui.BorderHorizontal
+ case "border-vertical":
+ opts.border = tui.BorderVertical
+ case "border-up", "border-top":
+ opts.border = tui.BorderTop
+ case "border-down", "border-bottom":
+ opts.border = tui.BorderBottom
+ case "border-left":
+ opts.border = tui.BorderLeft
+ case "border-right":
+ opts.border = tui.BorderRight
+ case "follow":
+ opts.follow = true
+ case "nofollow":
+ opts.follow = false
+ default:
+ if headerRegex.MatchString(token) {
+ opts.headerLines = atoi(token[1:])
+ } else if sizeRegex.MatchString(token) {
+ opts.size = parseSize(token, 99, "window size")
+ } else if offsetRegex.MatchString(token) {
+ opts.scroll = token
+ } else {
+ errorExit("invalid preview window option: " + token)
+ }
+ }
+ }
+ if len(alternative) > 0 {
+ alternativeOpts := *opts
+ opts.alternative = &alternativeOpts
+ opts.alternative.hidden = false
+ opts.alternative.alternative = nil
+ parsePreviewWindow(opts.alternative, alternative)
+ }
+}
+
+func parseMargin(opt string, margin string) [4]sizeSpec {
+ margins := strings.Split(margin, ",")
+ checked := func(str string) sizeSpec {
+ return parseSize(str, 49, opt)
+ }
+ switch len(margins) {
+ case 1:
+ m := checked(margins[0])
+ return [4]sizeSpec{m, m, m, m}
+ case 2:
+ tb := checked(margins[0])
+ rl := checked(margins[1])
+ return [4]sizeSpec{tb, rl, tb, rl}
+ case 3:
+ t := checked(margins[0])
+ rl := checked(margins[1])
+ b := checked(margins[2])
+ return [4]sizeSpec{t, rl, b, rl}
+ case 4:
+ return [4]sizeSpec{
+ checked(margins[0]), checked(margins[1]),
+ checked(margins[2]), checked(margins[3])}
+ default:
+ errorExit("invalid " + opt + ": " + margin)
+ }
+ return defaultMargin()
+}
+
+func parseOptions(opts *Options, allArgs []string) {
+ var historyMax int
+ if opts.History == nil {
+ historyMax = defaultHistoryMax
+ } else {
+ historyMax = opts.History.maxSize
+ }
+ setHistory := func(path string) {
+ h, e := NewHistory(path, historyMax)
+ if e != nil {
+ errorExit(e.Error())
+ }
+ opts.History = h
+ }
+ setHistoryMax := func(max int) {
+ historyMax = max
+ if historyMax < 1 {
+ errorExit("history max must be a positive integer")
+ }
+ if opts.History != nil {
+ opts.History.maxSize = historyMax
+ }
+ }
+ validateJumpLabels := false
+ validatePointer := false
+ validateMarker := false
+ for i := 0; i < len(allArgs); i++ {
+ arg := allArgs[i]
+ switch arg {
+ case "-h", "--help":
+ help(exitOk)
+ case "-x", "--extended":
+ opts.Extended = true
+ case "-e", "--exact":
+ opts.Fuzzy = false
+ case "--extended-exact":
+ // Note that we now don't have --no-extended-exact
+ opts.Fuzzy = false
+ opts.Extended = true
+ case "+x", "--no-extended":
+ opts.Extended = false
+ case "+e", "--no-exact":
+ opts.Fuzzy = true
+ case "-q", "--query":
+ opts.Query = nextString(allArgs, &i, "query string required")
+ case "-f", "--filter":
+ filter := nextString(allArgs, &i, "query string required")
+ opts.Filter = &filter
+ case "--literal":
+ opts.Normalize = false
+ case "--no-literal":
+ opts.Normalize = true
+ case "--algo":
+ opts.FuzzyAlgo = parseAlgo(nextString(allArgs, &i, "algorithm required (v1|v2)"))
+ case "--scheme":
+ opts.Scheme = strings.ToLower(nextString(allArgs, &i, "scoring scheme required (default|path|history)"))
+ case "--expect":
+ for k, v := range parseKeyChords(nextString(allArgs, &i, "key names required"), "key names required") {
+ opts.Expect[k] = v
+ }
+ case "--no-expect":
+ opts.Expect = make(map[tui.Event]string)
+ case "--enabled", "--no-phony":
+ opts.Phony = false
+ case "--disabled", "--phony":
+ opts.Phony = true
+ case "--tiebreak":
+ opts.Criteria = parseTiebreak(nextString(allArgs, &i, "sort criterion required"))
+ case "--bind":
+ parseKeymap(opts.Keymap, nextString(allArgs, &i, "bind expression required"))
+ case "--color":
+ _, spec := optionalNextString(allArgs, &i)
+ if len(spec) == 0 {
+ opts.Theme = tui.EmptyTheme()
+ } else {
+ opts.Theme = parseTheme(opts.Theme, spec)
+ }
+ case "--toggle-sort":
+ parseToggleSort(opts.Keymap, nextString(allArgs, &i, "key name required"))
+ case "-d", "--delimiter":
+ opts.Delimiter = delimiterRegexp(nextString(allArgs, &i, "delimiter required"))
+ case "-n", "--nth":
+ opts.Nth = splitNth(nextString(allArgs, &i, "nth expression required"))
+ case "--with-nth":
+ opts.WithNth = splitNth(nextString(allArgs, &i, "nth expression required"))
+ case "-s", "--sort":
+ opts.Sort = optionalNumeric(allArgs, &i, 1)
+ case "+s", "--no-sort":
+ opts.Sort = 0
+ case "--tac":
+ opts.Tac = true
+ case "--no-tac":
+ opts.Tac = false
+ case "-i":
+ opts.Case = CaseIgnore
+ case "+i":
+ opts.Case = CaseRespect
+ case "-m", "--multi":
+ opts.Multi = optionalNumeric(allArgs, &i, maxMulti)
+ case "+m", "--no-multi":
+ opts.Multi = 0
+ case "--ansi":
+ opts.Ansi = true
+ case "--no-ansi":
+ opts.Ansi = false
+ case "--no-mouse":
+ opts.Mouse = false
+ case "+c", "--no-color":
+ opts.Theme = tui.NoColorTheme()
+ case "+2", "--no-256":
+ opts.Theme = tui.Default16
+ case "--black":
+ opts.Black = true
+ case "--no-black":
+ opts.Black = false
+ case "--bold":
+ opts.Bold = true
+ case "--no-bold":
+ opts.Bold = false
+ case "--layout":
+ opts.Layout = parseLayout(
+ nextString(allArgs, &i, "layout required (default / reverse / reverse-list)"))
+ case "--reverse":
+ opts.Layout = layoutReverse
+ case "--no-reverse":
+ opts.Layout = layoutDefault
+ case "--cycle":
+ opts.Cycle = true
+ case "--no-cycle":
+ opts.Cycle = false
+ case "--keep-right":
+ opts.KeepRight = true
+ case "--no-keep-right":
+ opts.KeepRight = false
+ case "--hscroll":
+ opts.Hscroll = true
+ case "--no-hscroll":
+ opts.Hscroll = false
+ case "--hscroll-off":
+ opts.HscrollOff = nextInt(allArgs, &i, "hscroll offset required")
+ case "--scroll-off":
+ opts.ScrollOff = nextInt(allArgs, &i, "scroll offset required")
+ case "--filepath-word":
+ opts.FileWord = true
+ case "--no-filepath-word":
+ opts.FileWord = false
+ case "--info":
+ opts.InfoStyle = parseInfoStyle(
+ nextString(allArgs, &i, "info style required"))
+ case "--no-info":
+ opts.InfoStyle = infoHidden
+ case "--inline-info":
+ opts.InfoStyle = infoInline
+ case "--no-inline-info":
+ opts.InfoStyle = infoDefault
+ case "--jump-labels":
+ opts.JumpLabels = nextString(allArgs, &i, "label characters required")
+ validateJumpLabels = true
+ case "-1", "--select-1":
+ opts.Select1 = true
+ case "+1", "--no-select-1":
+ opts.Select1 = false
+ case "-0", "--exit-0":
+ opts.Exit0 = true
+ case "+0", "--no-exit-0":
+ opts.Exit0 = false
+ case "--read0":
+ opts.ReadZero = true
+ case "--no-read0":
+ opts.ReadZero = false
+ case "--print0":
+ opts.Printer = func(str string) { fmt.Print(str, "\x00") }
+ opts.PrintSep = "\x00"
+ case "--no-print0":
+ opts.Printer = func(str string) { fmt.Println(str) }
+ opts.PrintSep = "\n"
+ case "--print-query":
+ opts.PrintQuery = true
+ case "--no-print-query":
+ opts.PrintQuery = false
+ case "--prompt":
+ opts.Prompt = nextString(allArgs, &i, "prompt string required")
+ case "--pointer":
+ opts.Pointer = nextString(allArgs, &i, "pointer sign string required")
+ validatePointer = true
+ case "--marker":
+ opts.Marker = nextString(allArgs, &i, "selected sign string required")
+ validateMarker = true
+ case "--sync":
+ opts.Sync = true
+ case "--no-sync":
+ opts.Sync = false
+ case "--async":
+ opts.Sync = false
+ case "--no-history":
+ opts.History = nil
+ case "--history":
+ setHistory(nextString(allArgs, &i, "history file path required"))
+ case "--history-size":
+ setHistoryMax(nextInt(allArgs, &i, "history max size required"))
+ case "--no-header":
+ opts.Header = []string{}
+ case "--no-header-lines":
+ opts.HeaderLines = 0
+ case "--header":
+ opts.Header = strLines(nextString(allArgs, &i, "header string required"))
+ case "--header-lines":
+ opts.HeaderLines = atoi(
+ nextString(allArgs, &i, "number of header lines required"))
+ case "--header-first":
+ opts.HeaderFirst = true
+ case "--no-header-first":
+ opts.HeaderFirst = false
+ case "--ellipsis":
+ opts.Ellipsis = nextString(allArgs, &i, "ellipsis string required")
+ case "--preview":
+ opts.Preview.command = nextString(allArgs, &i, "preview command required")
+ case "--no-preview":
+ opts.Preview.command = ""
+ case "--preview-window":
+ parsePreviewWindow(&opts.Preview,
+ nextString(allArgs, &i, "preview window layout required: [up|down|left|right][,SIZE[%]][,border-BORDER_OPT][,wrap][,cycle][,hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default]"))
+ case "--height":
+ opts.Height = parseHeight(nextString(allArgs, &i, "height required: HEIGHT[%]"))
+ case "--min-height":
+ opts.MinHeight = nextInt(allArgs, &i, "height required: HEIGHT")
+ case "--no-height":
+ opts.Height = sizeSpec{}
+ case "--no-margin":
+ opts.Margin = defaultMargin()
+ case "--no-padding":
+ opts.Padding = defaultMargin()
+ case "--no-border":
+ opts.BorderShape = tui.BorderNone
+ case "--border":
+ hasArg, arg := optionalNextString(allArgs, &i)
+ opts.BorderShape = parseBorder(arg, !hasArg)
+ case "--no-unicode":
+ opts.Unicode = false
+ case "--unicode":
+ opts.Unicode = true
+ case "--margin":
+ opts.Margin = parseMargin(
+ "margin",
+ nextString(allArgs, &i, "margin required (TRBL / TB,RL / T,RL,B / T,R,B,L)"))
+ case "--padding":
+ opts.Padding = parseMargin(
+ "padding",
+ nextString(allArgs, &i, "padding required (TRBL / TB,RL / T,RL,B / T,R,B,L)"))
+ case "--tabstop":
+ opts.Tabstop = nextInt(allArgs, &i, "tab stop required")
+ case "--clear":
+ opts.ClearOnExit = true
+ case "--no-clear":
+ opts.ClearOnExit = false
+ case "--version":
+ opts.Version = true
+ case "--":
+ // Ignored
+ default:
+ if match, value := optString(arg, "--algo="); match {
+ opts.FuzzyAlgo = parseAlgo(value)
+ } else if match, value := optString(arg, "--scheme="); match {
+ opts.Scheme = strings.ToLower(value)
+ } else if match, value := optString(arg, "-q", "--query="); match {
+ opts.Query = value
+ } else if match, value := optString(arg, "-f", "--filter="); match {
+ opts.Filter = &value
+ } else if match, value := optString(arg, "-d", "--delimiter="); match {
+ opts.Delimiter = delimiterRegexp(value)
+ } else if match, value := optString(arg, "--border="); match {
+ opts.BorderShape = parseBorder(value, false)
+ } else if match, value := optString(arg, "--prompt="); match {
+ opts.Prompt = value
+ } else if match, value := optString(arg, "--pointer="); match {
+ opts.Pointer = value
+ validatePointer = true
+ } else if match, value := optString(arg, "--marker="); match {
+ opts.Marker = value
+ validateMarker = true
+ } else if match, value := optString(arg, "-n", "--nth="); match {
+ opts.Nth = splitNth(value)
+ } else if match, value := optString(arg, "--with-nth="); match {
+ opts.WithNth = splitNth(value)
+ } else if match, _ := optString(arg, "-s", "--sort="); match {
+ opts.Sort = 1 // Don't care
+ } else if match, value := optString(arg, "-m", "--multi="); match {
+ opts.Multi = atoi(value)
+ } else if match, value := optString(arg, "--height="); match {
+ opts.Height = parseHeight(value)
+ } else if match, value := optString(arg, "--min-height="); match {
+ opts.MinHeight = atoi(value)
+ } else if match, value := optString(arg, "--layout="); match {
+ opts.Layout = parseLayout(value)
+ } else if match, value := optString(arg, "--info="); match {
+ opts.InfoStyle = parseInfoStyle(value)
+ } else if match, value := optString(arg, "--toggle-sort="); match {
+ parseToggleSort(opts.Keymap, value)
+ } else if match, value := optString(arg, "--expect="); match {
+ for k, v := range parseKeyChords(value, "key names required") {
+ opts.Expect[k] = v
+ }
+ } else if match, value := optString(arg, "--tiebreak="); match {
+ opts.Criteria = parseTiebreak(value)
+ } else if match, value := optString(arg, "--color="); match {
+ opts.Theme = parseTheme(opts.Theme, value)
+ } else if match, value := optString(arg, "--bind="); match {
+ parseKeymap(opts.Keymap, value)
+ } else if match, value := optString(arg, "--history="); match {
+ setHistory(value)
+ } else if match, value := optString(arg, "--history-size="); match {
+ setHistoryMax(atoi(value))
+ } else if match, value := optString(arg, "--header="); match {
+ opts.Header = strLines(value)
+ } else if match, value := optString(arg, "--header-lines="); match {
+ opts.HeaderLines = atoi(value)
+ } else if match, value := optString(arg, "--ellipsis="); match {
+ opts.Ellipsis = value
+ } else if match, value := optString(arg, "--preview="); match {
+ opts.Preview.command = value
+ } else if match, value := optString(arg, "--preview-window="); match {
+ parsePreviewWindow(&opts.Preview, value)
+ } else if match, value := optString(arg, "--margin="); match {
+ opts.Margin = parseMargin("margin", value)
+ } else if match, value := optString(arg, "--padding="); match {
+ opts.Padding = parseMargin("padding", value)
+ } else if match, value := optString(arg, "--tabstop="); match {
+ opts.Tabstop = atoi(value)
+ } else if match, value := optString(arg, "--hscroll-off="); match {
+ opts.HscrollOff = atoi(value)
+ } else if match, value := optString(arg, "--scroll-off="); match {
+ opts.ScrollOff = atoi(value)
+ } else if match, value := optString(arg, "--jump-labels="); match {
+ opts.JumpLabels = value
+ validateJumpLabels = true
+ } else {
+ errorExit("unknown option: " + arg)
+ }
+ }
+ }
+
+ if opts.HeaderLines < 0 {
+ errorExit("header lines must be a non-negative integer")
+ }
+
+ if opts.HscrollOff < 0 {
+ errorExit("hscroll offset must be a non-negative integer")
+ }
+
+ if opts.ScrollOff < 0 {
+ errorExit("scroll offset must be a non-negative integer")
+ }
+
+ if opts.Tabstop < 1 {
+ errorExit("tab stop must be a positive integer")
+ }
+
+ if len(opts.JumpLabels) == 0 {
+ errorExit("empty jump labels")
+ }
+
+ if validateJumpLabels {
+ for _, r := range opts.JumpLabels {
+ if r < 32 || r > 126 {
+ errorExit("non-ascii jump labels are not allowed")
+ }
+ }
+ }
+
+ if validatePointer {
+ if err := validateSign(opts.Pointer, "pointer"); err != nil {
+ errorExit(err.Error())
+ }
+ }
+
+ if validateMarker {
+ if err := validateSign(opts.Marker, "marker"); err != nil {
+ errorExit(err.Error())
+ }
+ }
+}
+
+func validateSign(sign string, signOptName string) error {
+ if sign == "" {
+ return fmt.Errorf("%v cannot be empty", signOptName)
+ }
+ if runewidth.StringWidth(sign) > 2 {
+ return fmt.Errorf("%v display width should be up to 2", signOptName)
+ }
+ return nil
+}
+
+func postProcessOptions(opts *Options) {
+ if !opts.Version && !tui.IsLightRendererSupported() && opts.Height.size > 0 {
+ errorExit("--height option is currently not supported on this platform")
+ }
+ // Default actions for CTRL-N / CTRL-P when --history is set
+ if opts.History != nil {
+ if _, prs := opts.Keymap[tui.CtrlP.AsEvent()]; !prs {
+ opts.Keymap[tui.CtrlP.AsEvent()] = toActions(actPreviousHistory)
+ }
+ if _, prs := opts.Keymap[tui.CtrlN.AsEvent()]; !prs {
+ opts.Keymap[tui.CtrlN.AsEvent()] = toActions(actNextHistory)
+ }
+ }
+
+ // Extend the default key map
+ keymap := defaultKeymap()
+ for key, actions := range opts.Keymap {
+ var lastChangePreviewWindow *action
+ for _, act := range actions {
+ switch act.t {
+ case actToggleSort:
+ // To display "+S"/"-S" on info line
+ opts.ToggleSort = true
+ case actChangePreviewWindow:
+ lastChangePreviewWindow = act
+ }
+ }
+ // Re-organize actions so that we only keep the last change-preview-window
+ // and it comes first in the list.
+ // * change-preview-window(up,+10)+preview(sleep 3; cat {})+change-preview-window(up,+20)
+ // -> change-preview-window(up,+20)+preview(sleep 3; cat {})
+ if lastChangePreviewWindow != nil {
+ reordered := []*action{lastChangePreviewWindow}
+ for _, act := range actions {
+ if act.t != actChangePreviewWindow {
+ reordered = append(reordered, act)
+ }
+ }
+ actions = reordered
+ }
+ keymap[key] = actions
+ }
+ opts.Keymap = keymap
+
+ // If we're not using extended search mode, --nth option becomes irrelevant
+ // if it contains the whole range
+ if !opts.Extended || len(opts.Nth) == 1 {
+ for _, r := range opts.Nth {
+ if r.begin == rangeEllipsis && r.end == rangeEllipsis {
+ opts.Nth = make([]Range, 0)
+ return
+ }
+ }
+ }
+
+ if opts.Bold {
+ theme := opts.Theme
+ boldify := func(c tui.ColorAttr) tui.ColorAttr {
+ dup := c
+ if !theme.Colored {
+ dup.Attr |= tui.Bold
+ } else if (c.Attr & tui.AttrRegular) == 0 {
+ dup.Attr |= tui.Bold
+ }
+ return dup
+ }
+ theme.Current = boldify(theme.Current)
+ theme.CurrentMatch = boldify(theme.CurrentMatch)
+ theme.Prompt = boldify(theme.Prompt)
+ theme.Input = boldify(theme.Input)
+ theme.Cursor = boldify(theme.Cursor)
+ theme.Spinner = boldify(theme.Spinner)
+ }
+
+ if opts.Scheme != "default" {
+ processScheme(opts)
+ }
+}
+
+func expectsArbitraryString(opt string) bool {
+ switch opt {
+ case "-q", "--query", "-f", "--filter", "--header", "--prompt":
+ return true
+ }
+ return false
+}
+
+// ParseOptions parses command-line options
+func ParseOptions() *Options {
+ opts := defaultOptions()
+
+ for idx, arg := range os.Args[1:] {
+ if arg == "--version" && (idx == 0 || idx > 0 && !expectsArbitraryString(os.Args[idx])) {
+ opts.Version = true
+ return opts
+ }
+ }
+
+ // Options from Env var
+ words, _ := shellwords.Parse(os.Getenv("FZF_DEFAULT_OPTS"))
+ if len(words) > 0 {
+ parseOptions(opts, words)
+ }
+
+ // Options from command-line arguments
+ parseOptions(opts, os.Args[1:])
+
+ postProcessOptions(opts)
+ return opts
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/options_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/options_test.go
new file mode 100644
index 00000000..e9cb5922
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/options_test.go
@@ -0,0 +1,468 @@
+package fzf
+
+import (
+ "fmt"
+ "io/ioutil"
+ "testing"
+
+ "github.com/junegunn/fzf/src/tui"
+)
+
+func TestDelimiterRegex(t *testing.T) {
+ // Valid regex
+ delim := delimiterRegexp(".")
+ if delim.regex == nil || delim.str != nil {
+ t.Error(delim)
+ }
+ // Broken regex -> string
+ delim = delimiterRegexp("[0-9")
+ if delim.regex != nil || *delim.str != "[0-9" {
+ t.Error(delim)
+ }
+ // Valid regex
+ delim = delimiterRegexp("[0-9]")
+ if delim.regex.String() != "[0-9]" || delim.str != nil {
+ t.Error(delim)
+ }
+ // Tab character
+ delim = delimiterRegexp("\t")
+ if delim.regex != nil || *delim.str != "\t" {
+ t.Error(delim)
+ }
+ // Tab expression
+ delim = delimiterRegexp("\\t")
+ if delim.regex != nil || *delim.str != "\t" {
+ t.Error(delim)
+ }
+ // Tabs -> regex
+ delim = delimiterRegexp("\t+")
+ if delim.regex == nil || delim.str != nil {
+ t.Error(delim)
+ }
+}
+
+func TestDelimiterRegexString(t *testing.T) {
+ delim := delimiterRegexp("*")
+ tokens := Tokenize("-*--*---**---", delim)
+ if delim.regex != nil ||
+ tokens[0].text.ToString() != "-*" ||
+ tokens[1].text.ToString() != "--*" ||
+ tokens[2].text.ToString() != "---*" ||
+ tokens[3].text.ToString() != "*" ||
+ tokens[4].text.ToString() != "---" {
+ t.Errorf("%s %v %d", delim, tokens, len(tokens))
+ }
+}
+
+func TestDelimiterRegexRegex(t *testing.T) {
+ delim := delimiterRegexp("--\\*")
+ tokens := Tokenize("-*--*---**---", delim)
+ if delim.str != nil ||
+ tokens[0].text.ToString() != "-*--*" ||
+ tokens[1].text.ToString() != "---*" ||
+ tokens[2].text.ToString() != "*---" {
+ t.Errorf("%s %d", tokens, len(tokens))
+ }
+}
+
+func TestDelimiterRegexRegexCaret(t *testing.T) {
+ delim := delimiterRegexp(`(^\s*|\s+)`)
+ tokens := Tokenize("foo bar baz", delim)
+ if delim.str != nil ||
+ len(tokens) != 4 ||
+ tokens[0].text.ToString() != "" ||
+ tokens[1].text.ToString() != "foo " ||
+ tokens[2].text.ToString() != "bar " ||
+ tokens[3].text.ToString() != "baz" {
+ t.Errorf("%s %d", tokens, len(tokens))
+ }
+}
+
+func TestSplitNth(t *testing.T) {
+ {
+ ranges := splitNth("..")
+ if len(ranges) != 1 ||
+ ranges[0].begin != rangeEllipsis ||
+ ranges[0].end != rangeEllipsis {
+ t.Errorf("%v", ranges)
+ }
+ }
+ {
+ ranges := splitNth("..3,1..,2..3,4..-1,-3..-2,..,2,-2,2..-2,1..-1")
+ if len(ranges) != 10 ||
+ ranges[0].begin != rangeEllipsis || ranges[0].end != 3 ||
+ ranges[1].begin != rangeEllipsis || ranges[1].end != rangeEllipsis ||
+ ranges[2].begin != 2 || ranges[2].end != 3 ||
+ ranges[3].begin != 4 || ranges[3].end != rangeEllipsis ||
+ ranges[4].begin != -3 || ranges[4].end != -2 ||
+ ranges[5].begin != rangeEllipsis || ranges[5].end != rangeEllipsis ||
+ ranges[6].begin != 2 || ranges[6].end != 2 ||
+ ranges[7].begin != -2 || ranges[7].end != -2 ||
+ ranges[8].begin != 2 || ranges[8].end != -2 ||
+ ranges[9].begin != rangeEllipsis || ranges[9].end != rangeEllipsis {
+ t.Errorf("%v", ranges)
+ }
+ }
+}
+
+func TestIrrelevantNth(t *testing.T) {
+ {
+ opts := defaultOptions()
+ words := []string{"--nth", "..", "-x"}
+ parseOptions(opts, words)
+ postProcessOptions(opts)
+ if len(opts.Nth) != 0 {
+ t.Errorf("nth should be empty: %v", opts.Nth)
+ }
+ }
+ for _, words := range [][]string{{"--nth", "..,3", "+x"}, {"--nth", "3,1..", "+x"}, {"--nth", "..-1,1", "+x"}} {
+ {
+ opts := defaultOptions()
+ parseOptions(opts, words)
+ postProcessOptions(opts)
+ if len(opts.Nth) != 0 {
+ t.Errorf("nth should be empty: %v", opts.Nth)
+ }
+ }
+ {
+ opts := defaultOptions()
+ words = append(words, "-x")
+ parseOptions(opts, words)
+ postProcessOptions(opts)
+ if len(opts.Nth) != 2 {
+ t.Errorf("nth should not be empty: %v", opts.Nth)
+ }
+ }
+ }
+}
+
+func TestParseKeys(t *testing.T) {
+ pairs := parseKeyChords("ctrl-z,alt-z,f2,@,Alt-a,!,ctrl-G,J,g,ctrl-alt-a,ALT-enter,alt-SPACE", "")
+ checkEvent := func(e tui.Event, s string) {
+ if pairs[e] != s {
+ t.Errorf("%s != %s", pairs[e], s)
+ }
+ }
+ check := func(et tui.EventType, s string) {
+ checkEvent(et.AsEvent(), s)
+ }
+ if len(pairs) != 12 {
+ t.Error(12)
+ }
+ check(tui.CtrlZ, "ctrl-z")
+ check(tui.F2, "f2")
+ check(tui.CtrlG, "ctrl-G")
+ checkEvent(tui.AltKey('z'), "alt-z")
+ checkEvent(tui.Key('@'), "@")
+ checkEvent(tui.AltKey('a'), "Alt-a")
+ checkEvent(tui.Key('!'), "!")
+ checkEvent(tui.Key('J'), "J")
+ checkEvent(tui.Key('g'), "g")
+ checkEvent(tui.CtrlAltKey('a'), "ctrl-alt-a")
+ checkEvent(tui.CtrlAltKey('m'), "ALT-enter")
+ checkEvent(tui.AltKey(' '), "alt-SPACE")
+
+ // Synonyms
+ pairs = parseKeyChords("enter,Return,space,tab,btab,esc,up,down,left,right", "")
+ if len(pairs) != 9 {
+ t.Error(9)
+ }
+ check(tui.CtrlM, "Return")
+ checkEvent(tui.Key(' '), "space")
+ check(tui.Tab, "tab")
+ check(tui.BTab, "btab")
+ check(tui.ESC, "esc")
+ check(tui.Up, "up")
+ check(tui.Down, "down")
+ check(tui.Left, "left")
+ check(tui.Right, "right")
+
+ pairs = parseKeyChords("Tab,Ctrl-I,PgUp,page-up,pgdn,Page-Down,Home,End,Alt-BS,Alt-BSpace,shift-left,shift-right,btab,shift-tab,return,Enter,bspace", "")
+ if len(pairs) != 11 {
+ t.Error(11)
+ }
+ check(tui.Tab, "Ctrl-I")
+ check(tui.PgUp, "page-up")
+ check(tui.PgDn, "Page-Down")
+ check(tui.Home, "Home")
+ check(tui.End, "End")
+ check(tui.AltBS, "Alt-BSpace")
+ check(tui.SLeft, "shift-left")
+ check(tui.SRight, "shift-right")
+ check(tui.BTab, "shift-tab")
+ check(tui.CtrlM, "Enter")
+ check(tui.BSpace, "bspace")
+}
+
+func TestParseKeysWithComma(t *testing.T) {
+ checkN := func(a int, b int) {
+ if a != b {
+ t.Errorf("%d != %d", a, b)
+ }
+ }
+ check := func(pairs map[tui.Event]string, e tui.Event, s string) {
+ if pairs[e] != s {
+ t.Errorf("%s != %s", pairs[e], s)
+ }
+ }
+
+ pairs := parseKeyChords(",", "")
+ checkN(len(pairs), 1)
+ check(pairs, tui.Key(','), ",")
+
+ pairs = parseKeyChords(",,a,b", "")
+ checkN(len(pairs), 3)
+ check(pairs, tui.Key('a'), "a")
+ check(pairs, tui.Key('b'), "b")
+ check(pairs, tui.Key(','), ",")
+
+ pairs = parseKeyChords("a,b,,", "")
+ checkN(len(pairs), 3)
+ check(pairs, tui.Key('a'), "a")
+ check(pairs, tui.Key('b'), "b")
+ check(pairs, tui.Key(','), ",")
+
+ pairs = parseKeyChords("a,,,b", "")
+ checkN(len(pairs), 3)
+ check(pairs, tui.Key('a'), "a")
+ check(pairs, tui.Key('b'), "b")
+ check(pairs, tui.Key(','), ",")
+
+ pairs = parseKeyChords("a,,,b,c", "")
+ checkN(len(pairs), 4)
+ check(pairs, tui.Key('a'), "a")
+ check(pairs, tui.Key('b'), "b")
+ check(pairs, tui.Key('c'), "c")
+ check(pairs, tui.Key(','), ",")
+
+ pairs = parseKeyChords(",,,", "")
+ checkN(len(pairs), 1)
+ check(pairs, tui.Key(','), ",")
+
+ pairs = parseKeyChords(",ALT-,,", "")
+ checkN(len(pairs), 1)
+ check(pairs, tui.AltKey(','), "ALT-,")
+}
+
+func TestBind(t *testing.T) {
+ keymap := defaultKeymap()
+ check := func(event tui.Event, arg1 string, types ...actionType) {
+ if len(keymap[event]) != len(types) {
+ t.Errorf("invalid number of actions for %v (%d != %d)",
+ event, len(types), len(keymap[event]))
+ return
+ }
+ for idx, action := range keymap[event] {
+ if types[idx] != action.t {
+ t.Errorf("invalid action type (%d != %d)", types[idx], action.t)
+ }
+ }
+ if len(arg1) > 0 && keymap[event][0].a != arg1 {
+ t.Errorf("invalid action argument: (%s != %s)", arg1, keymap[event][0].a)
+ }
+ }
+ check(tui.CtrlA.AsEvent(), "", actBeginningOfLine)
+ parseKeymap(keymap,
+ "ctrl-a:kill-line,ctrl-b:toggle-sort+up+down,c:page-up,alt-z:page-down,"+
+ "f1:execute(ls {+})+abort+execute(echo {+})+select-all,f2:execute/echo {}, {}, {}/,f3:execute[echo '({})'],f4:execute;less {};,"+
+ "alt-a:execute-Multi@echo (,),[,],/,:,;,%,{}@,alt-b:execute;echo (,),[,],/,:,@,%,{};,"+
+ "x:Execute(foo+bar),X:execute/bar+baz/"+
+ ",f1:+first,f1:+top"+
+ ",,:abort,::accept,+:execute:++\nfoobar,Y:execute(baz)+up")
+ check(tui.CtrlA.AsEvent(), "", actKillLine)
+ check(tui.CtrlB.AsEvent(), "", actToggleSort, actUp, actDown)
+ check(tui.Key('c'), "", actPageUp)
+ check(tui.Key(','), "", actAbort)
+ check(tui.Key(':'), "", actAccept)
+ check(tui.AltKey('z'), "", actPageDown)
+ check(tui.F1.AsEvent(), "ls {+}", actExecute, actAbort, actExecute, actSelectAll, actFirst, actFirst)
+ check(tui.F2.AsEvent(), "echo {}, {}, {}", actExecute)
+ check(tui.F3.AsEvent(), "echo '({})'", actExecute)
+ check(tui.F4.AsEvent(), "less {}", actExecute)
+ check(tui.Key('x'), "foo+bar", actExecute)
+ check(tui.Key('X'), "bar+baz", actExecute)
+ check(tui.AltKey('a'), "echo (,),[,],/,:,;,%,{}", actExecuteMulti)
+ check(tui.AltKey('b'), "echo (,),[,],/,:,@,%,{}", actExecute)
+ check(tui.Key('+'), "++\nfoobar,Y:execute(baz)+up", actExecute)
+
+ for idx, char := range []rune{'~', '!', '@', '#', '$', '%', '^', '&', '*', '|', ';', '/'} {
+ parseKeymap(keymap, fmt.Sprintf("%d:execute%cfoobar%c", idx%10, char, char))
+ check(tui.Key([]rune(fmt.Sprintf("%d", idx%10))[0]), "foobar", actExecute)
+ }
+
+ parseKeymap(keymap, "f1:abort")
+ check(tui.F1.AsEvent(), "", actAbort)
+}
+
+func TestColorSpec(t *testing.T) {
+ theme := tui.Dark256
+ dark := parseTheme(theme, "dark")
+ if *dark != *theme {
+ t.Errorf("colors should be equivalent")
+ }
+ if dark == theme {
+ t.Errorf("point should not be equivalent")
+ }
+
+ light := parseTheme(theme, "dark,light")
+ if *light == *theme {
+ t.Errorf("should not be equivalent")
+ }
+ if *light != *tui.Light256 {
+ t.Errorf("colors should be equivalent")
+ }
+ if light == theme {
+ t.Errorf("point should not be equivalent")
+ }
+
+ customized := parseTheme(theme, "fg:231,bg:232")
+ if customized.Fg.Color != 231 || customized.Bg.Color != 232 {
+ t.Errorf("color not customized")
+ }
+ if *tui.Dark256 == *customized {
+ t.Errorf("colors should not be equivalent")
+ }
+ customized.Fg = tui.Dark256.Fg
+ customized.Bg = tui.Dark256.Bg
+ if *tui.Dark256 != *customized {
+ t.Errorf("colors should now be equivalent: %v, %v", tui.Dark256, customized)
+ }
+
+ customized = parseTheme(theme, "fg:231,dark,bg:232")
+ if customized.Fg != tui.Dark256.Fg || customized.Bg == tui.Dark256.Bg {
+ t.Errorf("color not customized")
+ }
+}
+
+func TestDefaultCtrlNP(t *testing.T) {
+ check := func(words []string, et tui.EventType, expected actionType) {
+ e := et.AsEvent()
+ opts := defaultOptions()
+ parseOptions(opts, words)
+ postProcessOptions(opts)
+ if opts.Keymap[e][0].t != expected {
+ t.Error()
+ }
+ }
+ check([]string{}, tui.CtrlN, actDown)
+ check([]string{}, tui.CtrlP, actUp)
+
+ check([]string{"--bind=ctrl-n:accept"}, tui.CtrlN, actAccept)
+ check([]string{"--bind=ctrl-p:accept"}, tui.CtrlP, actAccept)
+
+ f, _ := ioutil.TempFile("", "fzf-history")
+ f.Close()
+ hist := "--history=" + f.Name()
+ check([]string{hist}, tui.CtrlN, actNextHistory)
+ check([]string{hist}, tui.CtrlP, actPreviousHistory)
+
+ check([]string{hist, "--bind=ctrl-n:accept"}, tui.CtrlN, actAccept)
+ check([]string{hist, "--bind=ctrl-n:accept"}, tui.CtrlP, actPreviousHistory)
+
+ check([]string{hist, "--bind=ctrl-p:accept"}, tui.CtrlN, actNextHistory)
+ check([]string{hist, "--bind=ctrl-p:accept"}, tui.CtrlP, actAccept)
+}
+
+func optsFor(words ...string) *Options {
+ opts := defaultOptions()
+ parseOptions(opts, words)
+ postProcessOptions(opts)
+ return opts
+}
+
+func TestToggle(t *testing.T) {
+ opts := optsFor()
+ if opts.ToggleSort {
+ t.Error()
+ }
+
+ opts = optsFor("--bind=a:toggle-sort")
+ if !opts.ToggleSort {
+ t.Error()
+ }
+
+ opts = optsFor("--bind=a:toggle-sort", "--bind=a:up")
+ if opts.ToggleSort {
+ t.Error()
+ }
+}
+
+func TestPreviewOpts(t *testing.T) {
+ opts := optsFor()
+ if !(opts.Preview.command == "" &&
+ opts.Preview.hidden == false &&
+ opts.Preview.wrap == false &&
+ opts.Preview.position == posRight &&
+ opts.Preview.size.percent == true &&
+ opts.Preview.size.size == 50) {
+ t.Error()
+ }
+ opts = optsFor("--preview", "cat {}", "--preview-window=left:15,hidden,wrap:+{1}-/2")
+ if !(opts.Preview.command == "cat {}" &&
+ opts.Preview.hidden == true &&
+ opts.Preview.wrap == true &&
+ opts.Preview.position == posLeft &&
+ opts.Preview.scroll == "+{1}-/2" &&
+ opts.Preview.size.percent == false &&
+ opts.Preview.size.size == 15) {
+ t.Error(opts.Preview)
+ }
+ opts = optsFor("--preview-window=up,15,wrap,hidden,+{1}+3-1-2/2", "--preview-window=down", "--preview-window=cycle")
+ if !(opts.Preview.command == "" &&
+ opts.Preview.hidden == true &&
+ opts.Preview.wrap == true &&
+ opts.Preview.cycle == true &&
+ opts.Preview.position == posDown &&
+ opts.Preview.scroll == "+{1}+3-1-2/2" &&
+ opts.Preview.size.percent == false &&
+ opts.Preview.size.size == 15) {
+ t.Error(opts.Preview.size.size)
+ }
+ opts = optsFor("--preview-window=up:15:wrap:hidden")
+ if !(opts.Preview.command == "" &&
+ opts.Preview.hidden == true &&
+ opts.Preview.wrap == true &&
+ opts.Preview.position == posUp &&
+ opts.Preview.size.percent == false &&
+ opts.Preview.size.size == 15) {
+ t.Error(opts.Preview)
+ }
+ opts = optsFor("--preview=foo", "--preview-window=up", "--preview-window=default:70%")
+ if !(opts.Preview.command == "foo" &&
+ opts.Preview.position == posRight &&
+ opts.Preview.size.percent == true &&
+ opts.Preview.size.size == 70) {
+ t.Error(opts.Preview)
+ }
+}
+
+func TestAdditiveExpect(t *testing.T) {
+ opts := optsFor("--expect=a", "--expect", "b", "--expect=c")
+ if len(opts.Expect) != 3 {
+ t.Error(opts.Expect)
+ }
+}
+
+func TestValidateSign(t *testing.T) {
+ testCases := []struct {
+ inputSign string
+ isValid bool
+ }{
+ {"> ", true},
+ {"아", true},
+ {"😀", true},
+ {"", false},
+ {">>>", false},
+ }
+
+ for _, testCase := range testCases {
+ err := validateSign(testCase.inputSign, "")
+ if testCase.isValid && err != nil {
+ t.Errorf("Input sign `%s` caused error", testCase.inputSign)
+ }
+
+ if !testCase.isValid && err == nil {
+ t.Errorf("Input sign `%s` did not cause error", testCase.inputSign)
+ }
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/pattern.go b/dot-oh-my-zsh/custom/plugins/fzf/src/pattern.go
new file mode 100644
index 00000000..95f23556
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/pattern.go
@@ -0,0 +1,427 @@
+package fzf
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+
+ "github.com/junegunn/fzf/src/algo"
+ "github.com/junegunn/fzf/src/util"
+)
+
+// fuzzy
+// 'exact
+// ^prefix-exact
+// suffix-exact$
+// !inverse-exact
+// !'inverse-fuzzy
+// !^inverse-prefix-exact
+// !inverse-suffix-exact$
+
+type termType int
+
+const (
+ termFuzzy termType = iota
+ termExact
+ termPrefix
+ termSuffix
+ termEqual
+)
+
+type term struct {
+ typ termType
+ inv bool
+ text []rune
+ caseSensitive bool
+ normalize bool
+}
+
+// String returns the string representation of a term.
+func (t term) String() string {
+ return fmt.Sprintf("term{typ: %d, inv: %v, text: []rune(%q), caseSensitive: %v}", t.typ, t.inv, string(t.text), t.caseSensitive)
+}
+
+type termSet []term
+
+// Pattern represents search pattern
+type Pattern struct {
+ fuzzy bool
+ fuzzyAlgo algo.Algo
+ extended bool
+ caseSensitive bool
+ normalize bool
+ forward bool
+ withPos bool
+ text []rune
+ termSets []termSet
+ sortable bool
+ cacheable bool
+ cacheKey string
+ delimiter Delimiter
+ nth []Range
+ procFun map[termType]algo.Algo
+}
+
+var (
+ _patternCache map[string]*Pattern
+ _splitRegex *regexp.Regexp
+ _cache ChunkCache
+)
+
+func init() {
+ _splitRegex = regexp.MustCompile(" +")
+ clearPatternCache()
+ clearChunkCache()
+}
+
+func clearPatternCache() {
+ // We can uniquely identify the pattern for a given string since
+ // search mode and caseMode do not change while the program is running
+ _patternCache = make(map[string]*Pattern)
+}
+
+func clearChunkCache() {
+ _cache = NewChunkCache()
+}
+
+// BuildPattern builds Pattern object from the given arguments
+func BuildPattern(fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case, normalize bool, forward bool,
+ withPos bool, cacheable bool, nth []Range, delimiter Delimiter, runes []rune) *Pattern {
+
+ var asString string
+ if extended {
+ asString = strings.TrimLeft(string(runes), " ")
+ for strings.HasSuffix(asString, " ") && !strings.HasSuffix(asString, "\\ ") {
+ asString = asString[:len(asString)-1]
+ }
+ } else {
+ asString = string(runes)
+ }
+
+ cached, found := _patternCache[asString]
+ if found {
+ return cached
+ }
+
+ caseSensitive := true
+ sortable := true
+ termSets := []termSet{}
+
+ if extended {
+ termSets = parseTerms(fuzzy, caseMode, normalize, asString)
+ // We should not sort the result if there are only inverse search terms
+ sortable = false
+ Loop:
+ for _, termSet := range termSets {
+ for idx, term := range termSet {
+ if !term.inv {
+ sortable = true
+ }
+ // If the query contains inverse search terms or OR operators,
+ // we cannot cache the search scope
+ if !cacheable || idx > 0 || term.inv || fuzzy && term.typ != termFuzzy || !fuzzy && term.typ != termExact {
+ cacheable = false
+ if sortable {
+ // Can't break until we see at least one non-inverse term
+ break Loop
+ }
+ }
+ }
+ }
+ } else {
+ lowerString := strings.ToLower(asString)
+ normalize = normalize &&
+ lowerString == string(algo.NormalizeRunes([]rune(lowerString)))
+ caseSensitive = caseMode == CaseRespect ||
+ caseMode == CaseSmart && lowerString != asString
+ if !caseSensitive {
+ asString = lowerString
+ }
+ }
+
+ ptr := &Pattern{
+ fuzzy: fuzzy,
+ fuzzyAlgo: fuzzyAlgo,
+ extended: extended,
+ caseSensitive: caseSensitive,
+ normalize: normalize,
+ forward: forward,
+ withPos: withPos,
+ text: []rune(asString),
+ termSets: termSets,
+ sortable: sortable,
+ cacheable: cacheable,
+ nth: nth,
+ delimiter: delimiter,
+ procFun: make(map[termType]algo.Algo)}
+
+ ptr.cacheKey = ptr.buildCacheKey()
+ ptr.procFun[termFuzzy] = fuzzyAlgo
+ ptr.procFun[termEqual] = algo.EqualMatch
+ ptr.procFun[termExact] = algo.ExactMatchNaive
+ ptr.procFun[termPrefix] = algo.PrefixMatch
+ ptr.procFun[termSuffix] = algo.SuffixMatch
+
+ _patternCache[asString] = ptr
+ return ptr
+}
+
+func parseTerms(fuzzy bool, caseMode Case, normalize bool, str string) []termSet {
+ str = strings.Replace(str, "\\ ", "\t", -1)
+ tokens := _splitRegex.Split(str, -1)
+ sets := []termSet{}
+ set := termSet{}
+ switchSet := false
+ afterBar := false
+ for _, token := range tokens {
+ typ, inv, text := termFuzzy, false, strings.Replace(token, "\t", " ", -1)
+ lowerText := strings.ToLower(text)
+ caseSensitive := caseMode == CaseRespect ||
+ caseMode == CaseSmart && text != lowerText
+ normalizeTerm := normalize &&
+ lowerText == string(algo.NormalizeRunes([]rune(lowerText)))
+ if !caseSensitive {
+ text = lowerText
+ }
+ if !fuzzy {
+ typ = termExact
+ }
+
+ if len(set) > 0 && !afterBar && text == "|" {
+ switchSet = false
+ afterBar = true
+ continue
+ }
+ afterBar = false
+
+ if strings.HasPrefix(text, "!") {
+ inv = true
+ typ = termExact
+ text = text[1:]
+ }
+
+ if text != "$" && strings.HasSuffix(text, "$") {
+ typ = termSuffix
+ text = text[:len(text)-1]
+ }
+
+ if strings.HasPrefix(text, "'") {
+ // Flip exactness
+ if fuzzy && !inv {
+ typ = termExact
+ text = text[1:]
+ } else {
+ typ = termFuzzy
+ text = text[1:]
+ }
+ } else if strings.HasPrefix(text, "^") {
+ if typ == termSuffix {
+ typ = termEqual
+ } else {
+ typ = termPrefix
+ }
+ text = text[1:]
+ }
+
+ if len(text) > 0 {
+ if switchSet {
+ sets = append(sets, set)
+ set = termSet{}
+ }
+ textRunes := []rune(text)
+ if normalizeTerm {
+ textRunes = algo.NormalizeRunes(textRunes)
+ }
+ set = append(set, term{
+ typ: typ,
+ inv: inv,
+ text: textRunes,
+ caseSensitive: caseSensitive,
+ normalize: normalizeTerm})
+ switchSet = true
+ }
+ }
+ if len(set) > 0 {
+ sets = append(sets, set)
+ }
+ return sets
+}
+
+// IsEmpty returns true if the pattern is effectively empty
+func (p *Pattern) IsEmpty() bool {
+ if !p.extended {
+ return len(p.text) == 0
+ }
+ return len(p.termSets) == 0
+}
+
+// AsString returns the search query in string type
+func (p *Pattern) AsString() string {
+ return string(p.text)
+}
+
+func (p *Pattern) buildCacheKey() string {
+ if !p.extended {
+ return p.AsString()
+ }
+ cacheableTerms := []string{}
+ for _, termSet := range p.termSets {
+ if len(termSet) == 1 && !termSet[0].inv && (p.fuzzy || termSet[0].typ == termExact) {
+ cacheableTerms = append(cacheableTerms, string(termSet[0].text))
+ }
+ }
+ return strings.Join(cacheableTerms, "\t")
+}
+
+// CacheKey is used to build string to be used as the key of result cache
+func (p *Pattern) CacheKey() string {
+ return p.cacheKey
+}
+
+// Match returns the list of matches Items in the given Chunk
+func (p *Pattern) Match(chunk *Chunk, slab *util.Slab) []Result {
+ // ChunkCache: Exact match
+ cacheKey := p.CacheKey()
+ if p.cacheable {
+ if cached := _cache.Lookup(chunk, cacheKey); cached != nil {
+ return cached
+ }
+ }
+
+ // Prefix/suffix cache
+ space := _cache.Search(chunk, cacheKey)
+
+ matches := p.matchChunk(chunk, space, slab)
+
+ if p.cacheable {
+ _cache.Add(chunk, cacheKey, matches)
+ }
+ return matches
+}
+
+func (p *Pattern) matchChunk(chunk *Chunk, space []Result, slab *util.Slab) []Result {
+ matches := []Result{}
+
+ if space == nil {
+ for idx := 0; idx < chunk.count; idx++ {
+ if match, _, _ := p.MatchItem(&chunk.items[idx], p.withPos, slab); match != nil {
+ matches = append(matches, *match)
+ }
+ }
+ } else {
+ for _, result := range space {
+ if match, _, _ := p.MatchItem(result.item, p.withPos, slab); match != nil {
+ matches = append(matches, *match)
+ }
+ }
+ }
+ return matches
+}
+
+// MatchItem returns true if the Item is a match
+func (p *Pattern) MatchItem(item *Item, withPos bool, slab *util.Slab) (*Result, []Offset, *[]int) {
+ if p.extended {
+ if offsets, bonus, pos := p.extendedMatch(item, withPos, slab); len(offsets) == len(p.termSets) {
+ result := buildResult(item, offsets, bonus)
+ return &result, offsets, pos
+ }
+ return nil, nil, nil
+ }
+ offset, bonus, pos := p.basicMatch(item, withPos, slab)
+ if sidx := offset[0]; sidx >= 0 {
+ offsets := []Offset{offset}
+ result := buildResult(item, offsets, bonus)
+ return &result, offsets, pos
+ }
+ return nil, nil, nil
+}
+
+func (p *Pattern) basicMatch(item *Item, withPos bool, slab *util.Slab) (Offset, int, *[]int) {
+ var input []Token
+ if len(p.nth) == 0 {
+ input = []Token{{text: &item.text, prefixLength: 0}}
+ } else {
+ input = p.transformInput(item)
+ }
+ if p.fuzzy {
+ return p.iter(p.fuzzyAlgo, input, p.caseSensitive, p.normalize, p.forward, p.text, withPos, slab)
+ }
+ return p.iter(algo.ExactMatchNaive, input, p.caseSensitive, p.normalize, p.forward, p.text, withPos, slab)
+}
+
+func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Offset, int, *[]int) {
+ var input []Token
+ if len(p.nth) == 0 {
+ input = []Token{{text: &item.text, prefixLength: 0}}
+ } else {
+ input = p.transformInput(item)
+ }
+ offsets := []Offset{}
+ var totalScore int
+ var allPos *[]int
+ if withPos {
+ allPos = &[]int{}
+ }
+ for _, termSet := range p.termSets {
+ var offset Offset
+ var currentScore int
+ matched := false
+ for _, term := range termSet {
+ pfun := p.procFun[term.typ]
+ off, score, pos := p.iter(pfun, input, term.caseSensitive, term.normalize, p.forward, term.text, withPos, slab)
+ if sidx := off[0]; sidx >= 0 {
+ if term.inv {
+ continue
+ }
+ offset, currentScore = off, score
+ matched = true
+ if withPos {
+ if pos != nil {
+ *allPos = append(*allPos, *pos...)
+ } else {
+ for idx := off[0]; idx < off[1]; idx++ {
+ *allPos = append(*allPos, int(idx))
+ }
+ }
+ }
+ break
+ } else if term.inv {
+ offset, currentScore = Offset{0, 0}, 0
+ matched = true
+ continue
+ }
+ }
+ if matched {
+ offsets = append(offsets, offset)
+ totalScore += currentScore
+ }
+ }
+ return offsets, totalScore, allPos
+}
+
+func (p *Pattern) transformInput(item *Item) []Token {
+ if item.transformed != nil {
+ return *item.transformed
+ }
+
+ tokens := Tokenize(item.text.ToString(), p.delimiter)
+ ret := Transform(tokens, p.nth)
+ item.transformed = &ret
+ return ret
+}
+
+func (p *Pattern) iter(pfun algo.Algo, tokens []Token, caseSensitive bool, normalize bool, forward bool, pattern []rune, withPos bool, slab *util.Slab) (Offset, int, *[]int) {
+ for _, part := range tokens {
+ if res, pos := pfun(caseSensitive, normalize, forward, part.text, pattern, withPos, slab); res.Start >= 0 {
+ sidx := int32(res.Start) + part.prefixLength
+ eidx := int32(res.End) + part.prefixLength
+ if pos != nil {
+ for idx := range *pos {
+ (*pos)[idx] += int(part.prefixLength)
+ }
+ }
+ return Offset{sidx, eidx}, res.Score, pos
+ }
+ }
+ return Offset{-1, -1}, 0, nil
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/pattern_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/pattern_test.go
new file mode 100644
index 00000000..5eb5f6d7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/pattern_test.go
@@ -0,0 +1,209 @@
+package fzf
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/junegunn/fzf/src/algo"
+ "github.com/junegunn/fzf/src/util"
+)
+
+var slab *util.Slab
+
+func init() {
+ slab = util.MakeSlab(slab16Size, slab32Size)
+}
+
+func TestParseTermsExtended(t *testing.T) {
+ terms := parseTerms(true, CaseSmart, false,
+ "aaa 'bbb ^ccc ddd$ !eee !'fff !^ggg !hhh$ | ^iii$ ^xxx | 'yyy | zzz$ | !ZZZ |")
+ if len(terms) != 9 ||
+ terms[0][0].typ != termFuzzy || terms[0][0].inv ||
+ terms[1][0].typ != termExact || terms[1][0].inv ||
+ terms[2][0].typ != termPrefix || terms[2][0].inv ||
+ terms[3][0].typ != termSuffix || terms[3][0].inv ||
+ terms[4][0].typ != termExact || !terms[4][0].inv ||
+ terms[5][0].typ != termFuzzy || !terms[5][0].inv ||
+ terms[6][0].typ != termPrefix || !terms[6][0].inv ||
+ terms[7][0].typ != termSuffix || !terms[7][0].inv ||
+ terms[7][1].typ != termEqual || terms[7][1].inv ||
+ terms[8][0].typ != termPrefix || terms[8][0].inv ||
+ terms[8][1].typ != termExact || terms[8][1].inv ||
+ terms[8][2].typ != termSuffix || terms[8][2].inv ||
+ terms[8][3].typ != termExact || !terms[8][3].inv {
+ t.Errorf("%v", terms)
+ }
+ for _, termSet := range terms[:8] {
+ term := termSet[0]
+ if len(term.text) != 3 {
+ t.Errorf("%v", term)
+ }
+ }
+}
+
+func TestParseTermsExtendedExact(t *testing.T) {
+ terms := parseTerms(false, CaseSmart, false,
+ "aaa 'bbb ^ccc ddd$ !eee !'fff !^ggg !hhh$")
+ if len(terms) != 8 ||
+ terms[0][0].typ != termExact || terms[0][0].inv || len(terms[0][0].text) != 3 ||
+ terms[1][0].typ != termFuzzy || terms[1][0].inv || len(terms[1][0].text) != 3 ||
+ terms[2][0].typ != termPrefix || terms[2][0].inv || len(terms[2][0].text) != 3 ||
+ terms[3][0].typ != termSuffix || terms[3][0].inv || len(terms[3][0].text) != 3 ||
+ terms[4][0].typ != termExact || !terms[4][0].inv || len(terms[4][0].text) != 3 ||
+ terms[5][0].typ != termFuzzy || !terms[5][0].inv || len(terms[5][0].text) != 3 ||
+ terms[6][0].typ != termPrefix || !terms[6][0].inv || len(terms[6][0].text) != 3 ||
+ terms[7][0].typ != termSuffix || !terms[7][0].inv || len(terms[7][0].text) != 3 {
+ t.Errorf("%v", terms)
+ }
+}
+
+func TestParseTermsEmpty(t *testing.T) {
+ terms := parseTerms(true, CaseSmart, false, "' ^ !' !^")
+ if len(terms) != 0 {
+ t.Errorf("%v", terms)
+ }
+}
+
+func TestExact(t *testing.T) {
+ defer clearPatternCache()
+ clearPatternCache()
+ pattern := BuildPattern(true, algo.FuzzyMatchV2, true, CaseSmart, false, true, false, true,
+ []Range{}, Delimiter{}, []rune("'abc"))
+ chars := util.ToChars([]byte("aabbcc abc"))
+ res, pos := algo.ExactMatchNaive(
+ pattern.caseSensitive, pattern.normalize, pattern.forward, &chars, pattern.termSets[0][0].text, true, nil)
+ if res.Start != 7 || res.End != 10 {
+ t.Errorf("%v / %d / %d", pattern.termSets, res.Start, res.End)
+ }
+ if pos != nil {
+ t.Errorf("pos is expected to be nil")
+ }
+}
+
+func TestEqual(t *testing.T) {
+ defer clearPatternCache()
+ clearPatternCache()
+ pattern := BuildPattern(true, algo.FuzzyMatchV2, true, CaseSmart, false, true, false, true, []Range{}, Delimiter{}, []rune("^AbC$"))
+
+ match := func(str string, sidxExpected int, eidxExpected int) {
+ chars := util.ToChars([]byte(str))
+ res, pos := algo.EqualMatch(
+ pattern.caseSensitive, pattern.normalize, pattern.forward, &chars, pattern.termSets[0][0].text, true, nil)
+ if res.Start != sidxExpected || res.End != eidxExpected {
+ t.Errorf("%v / %d / %d", pattern.termSets, res.Start, res.End)
+ }
+ if pos != nil {
+ t.Errorf("pos is expected to be nil")
+ }
+ }
+ match("ABC", -1, -1)
+ match("AbC", 0, 3)
+ match("AbC ", 0, 3)
+ match(" AbC ", 1, 4)
+ match(" AbC", 2, 5)
+}
+
+func TestCaseSensitivity(t *testing.T) {
+ defer clearPatternCache()
+ clearPatternCache()
+ pat1 := BuildPattern(true, algo.FuzzyMatchV2, false, CaseSmart, false, true, false, true, []Range{}, Delimiter{}, []rune("abc"))
+ clearPatternCache()
+ pat2 := BuildPattern(true, algo.FuzzyMatchV2, false, CaseSmart, false, true, false, true, []Range{}, Delimiter{}, []rune("Abc"))
+ clearPatternCache()
+ pat3 := BuildPattern(true, algo.FuzzyMatchV2, false, CaseIgnore, false, true, false, true, []Range{}, Delimiter{}, []rune("abc"))
+ clearPatternCache()
+ pat4 := BuildPattern(true, algo.FuzzyMatchV2, false, CaseIgnore, false, true, false, true, []Range{}, Delimiter{}, []rune("Abc"))
+ clearPatternCache()
+ pat5 := BuildPattern(true, algo.FuzzyMatchV2, false, CaseRespect, false, true, false, true, []Range{}, Delimiter{}, []rune("abc"))
+ clearPatternCache()
+ pat6 := BuildPattern(true, algo.FuzzyMatchV2, false, CaseRespect, false, true, false, true, []Range{}, Delimiter{}, []rune("Abc"))
+
+ if string(pat1.text) != "abc" || pat1.caseSensitive != false ||
+ string(pat2.text) != "Abc" || pat2.caseSensitive != true ||
+ string(pat3.text) != "abc" || pat3.caseSensitive != false ||
+ string(pat4.text) != "abc" || pat4.caseSensitive != false ||
+ string(pat5.text) != "abc" || pat5.caseSensitive != true ||
+ string(pat6.text) != "Abc" || pat6.caseSensitive != true {
+ t.Error("Invalid case conversion")
+ }
+}
+
+func TestOrigTextAndTransformed(t *testing.T) {
+ pattern := BuildPattern(true, algo.FuzzyMatchV2, true, CaseSmart, false, true, false, true, []Range{}, Delimiter{}, []rune("jg"))
+ tokens := Tokenize("junegunn", Delimiter{})
+ trans := Transform(tokens, []Range{{1, 1}})
+
+ origBytes := []byte("junegunn.choi")
+ for _, extended := range []bool{false, true} {
+ chunk := Chunk{count: 1}
+ chunk.items[0] = Item{
+ text: util.ToChars([]byte("junegunn")),
+ origText: &origBytes,
+ transformed: &trans}
+ pattern.extended = extended
+ matches := pattern.matchChunk(&chunk, nil, slab) // No cache
+ if !(matches[0].item.text.ToString() == "junegunn" &&
+ string(*matches[0].item.origText) == "junegunn.choi" &&
+ reflect.DeepEqual(*matches[0].item.transformed, trans)) {
+ t.Error("Invalid match result", matches)
+ }
+
+ match, offsets, pos := pattern.MatchItem(&chunk.items[0], true, slab)
+ if !(match.item.text.ToString() == "junegunn" &&
+ string(*match.item.origText) == "junegunn.choi" &&
+ offsets[0][0] == 0 && offsets[0][1] == 5 &&
+ reflect.DeepEqual(*match.item.transformed, trans)) {
+ t.Error("Invalid match result", match, offsets, extended)
+ }
+ if !((*pos)[0] == 4 && (*pos)[1] == 0) {
+ t.Error("Invalid pos array", *pos)
+ }
+ }
+}
+
+func TestCacheKey(t *testing.T) {
+ test := func(extended bool, patStr string, expected string, cacheable bool) {
+ clearPatternCache()
+ pat := BuildPattern(true, algo.FuzzyMatchV2, extended, CaseSmart, false, true, false, true, []Range{}, Delimiter{}, []rune(patStr))
+ if pat.CacheKey() != expected {
+ t.Errorf("Expected: %s, actual: %s", expected, pat.CacheKey())
+ }
+ if pat.cacheable != cacheable {
+ t.Errorf("Expected: %t, actual: %t (%s)", cacheable, pat.cacheable, patStr)
+ }
+ clearPatternCache()
+ }
+ test(false, "foo !bar", "foo !bar", true)
+ test(false, "foo | bar !baz", "foo | bar !baz", true)
+ test(true, "foo bar baz", "foo\tbar\tbaz", true)
+ test(true, "foo !bar", "foo", false)
+ test(true, "foo !bar baz", "foo\tbaz", false)
+ test(true, "foo | bar baz", "baz", false)
+ test(true, "foo | bar | baz", "", false)
+ test(true, "foo | bar !baz", "", false)
+ test(true, "| | foo", "", false)
+ test(true, "| | | foo", "foo", false)
+}
+
+func TestCacheable(t *testing.T) {
+ test := func(fuzzy bool, str string, expected string, cacheable bool) {
+ clearPatternCache()
+ pat := BuildPattern(fuzzy, algo.FuzzyMatchV2, true, CaseSmart, true, true, false, true, []Range{}, Delimiter{}, []rune(str))
+ if pat.CacheKey() != expected {
+ t.Errorf("Expected: %s, actual: %s", expected, pat.CacheKey())
+ }
+ if cacheable != pat.cacheable {
+ t.Errorf("Invalid Pattern.cacheable for \"%s\": %v (expected: %v)", str, pat.cacheable, cacheable)
+ }
+ clearPatternCache()
+ }
+ test(true, "foo bar", "foo\tbar", true)
+ test(true, "foo 'bar", "foo\tbar", false)
+ test(true, "foo !bar", "foo", false)
+
+ test(false, "foo bar", "foo\tbar", true)
+ test(false, "foo 'bar", "foo", false)
+ test(false, "foo '", "foo", true)
+ test(false, "foo 'bar", "foo", false)
+ test(false, "foo !bar", "foo", false)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/protector/protector.go b/dot-oh-my-zsh/custom/plugins/fzf/src/protector/protector.go
new file mode 100644
index 00000000..fe84b388
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/protector/protector.go
@@ -0,0 +1,8 @@
+//go:build !openbsd
+
+package protector
+
+// Protect calls OS specific protections like pledge on OpenBSD
+func Protect() {
+ return
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/protector/protector_openbsd.go b/dot-oh-my-zsh/custom/plugins/fzf/src/protector/protector_openbsd.go
new file mode 100644
index 00000000..34784a6c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/protector/protector_openbsd.go
@@ -0,0 +1,10 @@
+//go:build openbsd
+
+package protector
+
+import "golang.org/x/sys/unix"
+
+// Protect calls OS specific protections like pledge on OpenBSD
+func Protect() {
+ unix.PledgePromises("stdio rpath tty proc exec")
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/reader.go b/dot-oh-my-zsh/custom/plugins/fzf/src/reader.go
new file mode 100644
index 00000000..06e9b734
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/reader.go
@@ -0,0 +1,201 @@
+package fzf
+
+import (
+ "bufio"
+ "context"
+ "io"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/junegunn/fzf/src/util"
+ "github.com/saracen/walker"
+)
+
+// Reader reads from command or standard input
+type Reader struct {
+ pusher func([]byte) bool
+ eventBox *util.EventBox
+ delimNil bool
+ event int32
+ finChan chan bool
+ mutex sync.Mutex
+ exec *exec.Cmd
+ command *string
+ killed bool
+ wait bool
+}
+
+// NewReader returns new Reader object
+func NewReader(pusher func([]byte) bool, eventBox *util.EventBox, delimNil bool, wait bool) *Reader {
+ return &Reader{pusher, eventBox, delimNil, int32(EvtReady), make(chan bool, 1), sync.Mutex{}, nil, nil, false, wait}
+}
+
+func (r *Reader) startEventPoller() {
+ go func() {
+ ptr := &r.event
+ pollInterval := readerPollIntervalMin
+ for {
+ if atomic.CompareAndSwapInt32(ptr, int32(EvtReadNew), int32(EvtReady)) {
+ r.eventBox.Set(EvtReadNew, (*string)(nil))
+ pollInterval = readerPollIntervalMin
+ } else if atomic.LoadInt32(ptr) == int32(EvtReadFin) {
+ if r.wait {
+ r.finChan <- true
+ }
+ return
+ } else {
+ pollInterval += readerPollIntervalStep
+ if pollInterval > readerPollIntervalMax {
+ pollInterval = readerPollIntervalMax
+ }
+ }
+ time.Sleep(pollInterval)
+ }
+ }()
+}
+
+func (r *Reader) fin(success bool) {
+ atomic.StoreInt32(&r.event, int32(EvtReadFin))
+ if r.wait {
+ <-r.finChan
+ }
+
+ r.mutex.Lock()
+ ret := r.command
+ if success || r.killed {
+ ret = nil
+ }
+ r.mutex.Unlock()
+
+ r.eventBox.Set(EvtReadFin, ret)
+}
+
+func (r *Reader) terminate() {
+ r.mutex.Lock()
+ defer func() { r.mutex.Unlock() }()
+
+ r.killed = true
+ if r.exec != nil && r.exec.Process != nil {
+ util.KillCommand(r.exec)
+ } else if defaultCommand != "" {
+ os.Stdin.Close()
+ }
+}
+
+func (r *Reader) restart(command string) {
+ r.event = int32(EvtReady)
+ r.startEventPoller()
+ success := r.readFromCommand(nil, command)
+ r.fin(success)
+}
+
+// ReadSource reads data from the default command or from standard input
+func (r *Reader) ReadSource() {
+ r.startEventPoller()
+ var success bool
+ if util.IsTty() {
+ // The default command for *nix requires bash
+ shell := "bash"
+ cmd := os.Getenv("FZF_DEFAULT_COMMAND")
+ if len(cmd) == 0 {
+ if defaultCommand != "" {
+ success = r.readFromCommand(&shell, defaultCommand)
+ } else {
+ success = r.readFiles()
+ }
+ } else {
+ success = r.readFromCommand(nil, cmd)
+ }
+ } else {
+ success = r.readFromStdin()
+ }
+ r.fin(success)
+}
+
+func (r *Reader) feed(src io.Reader) {
+ delim := byte('\n')
+ if r.delimNil {
+ delim = '\000'
+ }
+ reader := bufio.NewReaderSize(src, readerBufferSize)
+ for {
+ // ReadBytes returns err != nil if and only if the returned data does not
+ // end in delim.
+ bytea, err := reader.ReadBytes(delim)
+ byteaLen := len(bytea)
+ if byteaLen > 0 {
+ if err == nil {
+ // get rid of carriage return if under Windows:
+ if util.IsWindows() && byteaLen >= 2 && bytea[byteaLen-2] == byte('\r') {
+ bytea = bytea[:byteaLen-2]
+ } else {
+ bytea = bytea[:byteaLen-1]
+ }
+ }
+ if r.pusher(bytea) {
+ atomic.StoreInt32(&r.event, int32(EvtReadNew))
+ }
+ }
+ if err != nil {
+ break
+ }
+ }
+}
+
+func (r *Reader) readFromStdin() bool {
+ r.feed(os.Stdin)
+ return true
+}
+
+func (r *Reader) readFiles() bool {
+ r.killed = false
+ fn := func(path string, mode os.FileInfo) error {
+ path = filepath.Clean(path)
+ if path != "." {
+ isDir := mode.Mode().IsDir()
+ if isDir && filepath.Base(path)[0] == '.' {
+ return filepath.SkipDir
+ }
+ if !isDir && r.pusher([]byte(path)) {
+ atomic.StoreInt32(&r.event, int32(EvtReadNew))
+ }
+ }
+ r.mutex.Lock()
+ defer r.mutex.Unlock()
+ if r.killed {
+ return context.Canceled
+ }
+ return nil
+ }
+ cb := walker.WithErrorCallback(func(pathname string, err error) error {
+ return nil
+ })
+ return walker.Walk(".", fn, cb) == nil
+}
+
+func (r *Reader) readFromCommand(shell *string, command string) bool {
+ r.mutex.Lock()
+ r.killed = false
+ r.command = &command
+ if shell != nil {
+ r.exec = util.ExecCommandWith(*shell, command, true)
+ } else {
+ r.exec = util.ExecCommand(command, true)
+ }
+ out, err := r.exec.StdoutPipe()
+ if err != nil {
+ r.mutex.Unlock()
+ return false
+ }
+ err = r.exec.Start()
+ r.mutex.Unlock()
+ if err != nil {
+ return false
+ }
+ r.feed(out)
+ return r.exec.Wait() == nil
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/reader_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/reader_test.go
new file mode 100644
index 00000000..feb45fc5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/reader_test.go
@@ -0,0 +1,63 @@
+package fzf
+
+import (
+ "testing"
+ "time"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+func TestReadFromCommand(t *testing.T) {
+ strs := []string{}
+ eb := util.NewEventBox()
+ reader := NewReader(
+ func(s []byte) bool { strs = append(strs, string(s)); return true },
+ eb, false, true)
+
+ reader.startEventPoller()
+
+ // Check EventBox
+ if eb.Peek(EvtReadNew) {
+ t.Error("EvtReadNew should not be set yet")
+ }
+
+ // Normal command
+ reader.fin(reader.readFromCommand(nil, `echo abc&&echo def`))
+ if len(strs) != 2 || strs[0] != "abc" || strs[1] != "def" {
+ t.Errorf("%s", strs)
+ }
+
+ // Check EventBox again
+ eb.WaitFor(EvtReadFin)
+
+ // Wait should return immediately
+ eb.Wait(func(events *util.Events) {
+ events.Clear()
+ })
+
+ // EventBox is cleared
+ if eb.Peek(EvtReadNew) {
+ t.Error("EvtReadNew should not be set yet")
+ }
+
+ // Make sure that event poller is finished
+ time.Sleep(readerPollIntervalMax)
+
+ // Restart event poller
+ reader.startEventPoller()
+
+ // Failing command
+ reader.fin(reader.readFromCommand(nil, `no-such-command`))
+ strs = []string{}
+ if len(strs) > 0 {
+ t.Errorf("%s", strs)
+ }
+
+ // Check EventBox again
+ if eb.Peek(EvtReadNew) {
+ t.Error("Command failed. EvtReadNew should not be set")
+ }
+ if !eb.Peek(EvtReadFin) {
+ t.Error("EvtReadFin should be set")
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/result.go b/dot-oh-my-zsh/custom/plugins/fzf/src/result.go
new file mode 100644
index 00000000..c4acb5fa
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/result.go
@@ -0,0 +1,258 @@
+package fzf
+
+import (
+ "math"
+ "sort"
+ "unicode"
+
+ "github.com/junegunn/fzf/src/tui"
+ "github.com/junegunn/fzf/src/util"
+)
+
+// Offset holds two 32-bit integers denoting the offsets of a matched substring
+type Offset [2]int32
+
+type colorOffset struct {
+ offset [2]int32
+ color tui.ColorPair
+}
+
+type Result struct {
+ item *Item
+ points [4]uint16
+}
+
+func buildResult(item *Item, offsets []Offset, score int) Result {
+ if len(offsets) > 1 {
+ sort.Sort(ByOrder(offsets))
+ }
+
+ result := Result{item: item}
+ numChars := item.text.Length()
+ minBegin := math.MaxUint16
+ minEnd := math.MaxUint16
+ maxEnd := 0
+ validOffsetFound := false
+ for _, offset := range offsets {
+ b, e := int(offset[0]), int(offset[1])
+ if b < e {
+ minBegin = util.Min(b, minBegin)
+ minEnd = util.Min(e, minEnd)
+ maxEnd = util.Max(e, maxEnd)
+ validOffsetFound = true
+ }
+ }
+
+ for idx, criterion := range sortCriteria {
+ val := uint16(math.MaxUint16)
+ switch criterion {
+ case byScore:
+ // Higher is better
+ val = math.MaxUint16 - util.AsUint16(score)
+ case byChunk:
+ b := minBegin
+ e := maxEnd
+ l := item.text.Length()
+ for ; b >= 1; b-- {
+ if unicode.IsSpace(item.text.Get(b - 1)) {
+ break
+ }
+ }
+ for ; e < l; e++ {
+ if unicode.IsSpace(item.text.Get(e)) {
+ break
+ }
+ }
+ val = util.AsUint16(e - b)
+ case byLength:
+ val = item.TrimLength()
+ case byBegin, byEnd:
+ if validOffsetFound {
+ whitePrefixLen := 0
+ for idx := 0; idx < numChars; idx++ {
+ r := item.text.Get(idx)
+ whitePrefixLen = idx
+ if idx == minBegin || !unicode.IsSpace(r) {
+ break
+ }
+ }
+ if criterion == byBegin {
+ val = util.AsUint16(minEnd - whitePrefixLen)
+ } else {
+ val = util.AsUint16(math.MaxUint16 - math.MaxUint16*(maxEnd-whitePrefixLen)/int(item.TrimLength()))
+ }
+ }
+ }
+ result.points[3-idx] = val
+ }
+
+ return result
+}
+
+// Sort criteria to use. Never changes once fzf is started.
+var sortCriteria []criterion
+
+// Index returns ordinal index of the Item
+func (result *Result) Index() int32 {
+ return result.item.Index()
+}
+
+func minRank() Result {
+ return Result{item: &minItem, points: [4]uint16{math.MaxUint16, 0, 0, 0}}
+}
+
+func (result *Result) colorOffsets(matchOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, current bool) []colorOffset {
+ itemColors := result.item.Colors()
+
+ // No ANSI codes
+ if len(itemColors) == 0 {
+ var offsets []colorOffset
+ for _, off := range matchOffsets {
+ offsets = append(offsets, colorOffset{offset: [2]int32{off[0], off[1]}, color: colMatch})
+ }
+ return offsets
+ }
+
+ // Find max column
+ var maxCol int32
+ for _, off := range matchOffsets {
+ if off[1] > maxCol {
+ maxCol = off[1]
+ }
+ }
+ for _, ansi := range itemColors {
+ if ansi.offset[1] > maxCol {
+ maxCol = ansi.offset[1]
+ }
+ }
+
+ cols := make([]int, maxCol)
+ for colorIndex, ansi := range itemColors {
+ for i := ansi.offset[0]; i < ansi.offset[1]; i++ {
+ cols[i] = colorIndex + 1 // 1-based index of itemColors
+ }
+ }
+
+ for _, off := range matchOffsets {
+ for i := off[0]; i < off[1]; i++ {
+ // Negative of 1-based index of itemColors
+ // - The extra -1 means highlighted
+ cols[i] = cols[i]*-1 - 1
+ }
+ }
+
+ // sort.Sort(ByOrder(offsets))
+
+ // Merge offsets
+ // ------------ ---- -- ----
+ // ++++++++ ++++++++++
+ // --++++++++-- --++++++++++---
+ curr := 0
+ start := 0
+ ansiToColorPair := func(ansi ansiOffset, base tui.ColorPair) tui.ColorPair {
+ fg := ansi.color.fg
+ bg := ansi.color.bg
+ if fg == -1 {
+ if current {
+ fg = theme.Current.Color
+ } else {
+ fg = theme.Fg.Color
+ }
+ }
+ if bg == -1 {
+ if current {
+ bg = theme.DarkBg.Color
+ } else {
+ bg = theme.Bg.Color
+ }
+ }
+ return tui.NewColorPair(fg, bg, ansi.color.attr).MergeAttr(base)
+ }
+ var colors []colorOffset
+ add := func(idx int) {
+ if curr != 0 && idx > start {
+ if curr < 0 {
+ color := colMatch
+ if curr < -1 && theme.Colored {
+ origColor := ansiToColorPair(itemColors[-curr-2], colMatch)
+ // hl or hl+ only sets the foreground color, so colMatch is the
+ // combination of either [hl and bg] or [hl+ and bg+].
+ //
+ // If the original text already has background color, and the
+ // foreground color of colMatch is -1, we shouldn't only apply the
+ // background color of colMatch.
+ // e.g. echo -e "\x1b[32;7mfoo\x1b[mbar" | fzf --ansi --color bg+:1,hl+:-1:underline
+ // echo -e "\x1b[42mfoo\x1b[mbar" | fzf --ansi --color bg+:1,hl+:-1:underline
+ if color.Fg().IsDefault() && origColor.HasBg() {
+ color = origColor
+ } else {
+ color = origColor.MergeNonDefault(color)
+ }
+ }
+ colors = append(colors, colorOffset{
+ offset: [2]int32{int32(start), int32(idx)}, color: color})
+ } else {
+ ansi := itemColors[curr-1]
+ colors = append(colors, colorOffset{
+ offset: [2]int32{int32(start), int32(idx)},
+ color: ansiToColorPair(ansi, colBase)})
+ }
+ }
+ }
+ for idx, col := range cols {
+ if col != curr {
+ add(idx)
+ start = idx
+ curr = col
+ }
+ }
+ add(int(maxCol))
+ return colors
+}
+
+// ByOrder is for sorting substring offsets
+type ByOrder []Offset
+
+func (a ByOrder) Len() int {
+ return len(a)
+}
+
+func (a ByOrder) Swap(i, j int) {
+ a[i], a[j] = a[j], a[i]
+}
+
+func (a ByOrder) Less(i, j int) bool {
+ ioff := a[i]
+ joff := a[j]
+ return (ioff[0] < joff[0]) || (ioff[0] == joff[0]) && (ioff[1] <= joff[1])
+}
+
+// ByRelevance is for sorting Items
+type ByRelevance []Result
+
+func (a ByRelevance) Len() int {
+ return len(a)
+}
+
+func (a ByRelevance) Swap(i, j int) {
+ a[i], a[j] = a[j], a[i]
+}
+
+func (a ByRelevance) Less(i, j int) bool {
+ return compareRanks(a[i], a[j], false)
+}
+
+// ByRelevanceTac is for sorting Items
+type ByRelevanceTac []Result
+
+func (a ByRelevanceTac) Len() int {
+ return len(a)
+}
+
+func (a ByRelevanceTac) Swap(i, j int) {
+ a[i], a[j] = a[j], a[i]
+}
+
+func (a ByRelevanceTac) Less(i, j int) bool {
+ return compareRanks(a[i], a[j], true)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/result_others.go b/dot-oh-my-zsh/custom/plugins/fzf/src/result_others.go
new file mode 100644
index 00000000..0d9dcd7c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/result_others.go
@@ -0,0 +1,16 @@
+//go:build !386 && !amd64
+
+package fzf
+
+func compareRanks(irank Result, jrank Result, tac bool) bool {
+ for idx := 3; idx >= 0; idx-- {
+ left := irank.points[idx]
+ right := jrank.points[idx]
+ if left < right {
+ return true
+ } else if left > right {
+ return false
+ }
+ }
+ return (irank.item.Index() <= jrank.item.Index()) != tac
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/result_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/result_test.go
new file mode 100644
index 00000000..a930447a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/result_test.go
@@ -0,0 +1,174 @@
+package fzf
+
+import (
+ "math"
+ "sort"
+ "testing"
+
+ "github.com/junegunn/fzf/src/tui"
+ "github.com/junegunn/fzf/src/util"
+)
+
+func withIndex(i *Item, index int) *Item {
+ (*i).text.Index = int32(index)
+ return i
+}
+
+func TestOffsetSort(t *testing.T) {
+ offsets := []Offset{
+ {3, 5}, {2, 7},
+ {1, 3}, {2, 9}}
+ sort.Sort(ByOrder(offsets))
+
+ if offsets[0][0] != 1 || offsets[0][1] != 3 ||
+ offsets[1][0] != 2 || offsets[1][1] != 7 ||
+ offsets[2][0] != 2 || offsets[2][1] != 9 ||
+ offsets[3][0] != 3 || offsets[3][1] != 5 {
+ t.Error("Invalid order:", offsets)
+ }
+}
+
+func TestRankComparison(t *testing.T) {
+ rank := func(vals ...uint16) Result {
+ return Result{
+ points: [4]uint16{vals[0], vals[1], vals[2], vals[3]},
+ item: &Item{text: util.Chars{Index: int32(vals[4])}}}
+ }
+ if compareRanks(rank(3, 0, 0, 0, 5), rank(2, 0, 0, 0, 7), false) ||
+ !compareRanks(rank(3, 0, 0, 0, 5), rank(3, 0, 0, 0, 6), false) ||
+ !compareRanks(rank(1, 2, 0, 0, 3), rank(1, 3, 0, 0, 2), false) ||
+ !compareRanks(rank(0, 0, 0, 0, 0), rank(0, 0, 0, 0, 0), false) {
+ t.Error("Invalid order")
+ }
+
+ if compareRanks(rank(3, 0, 0, 0, 5), rank(2, 0, 0, 0, 7), true) ||
+ !compareRanks(rank(3, 0, 0, 0, 5), rank(3, 0, 0, 0, 6), false) ||
+ !compareRanks(rank(1, 2, 0, 0, 3), rank(1, 3, 0, 0, 2), true) ||
+ !compareRanks(rank(0, 0, 0, 0, 0), rank(0, 0, 0, 0, 0), false) {
+ t.Error("Invalid order (tac)")
+ }
+}
+
+// Match length, string length, index
+func TestResultRank(t *testing.T) {
+ // FIXME global
+ sortCriteria = []criterion{byScore, byLength}
+
+ str := []rune("foo")
+ item1 := buildResult(
+ withIndex(&Item{text: util.RunesToChars(str)}, 1), []Offset{}, 2)
+ if item1.points[3] != math.MaxUint16-2 || // Bonus
+ item1.points[2] != 3 || // Length
+ item1.points[1] != 0 || // Unused
+ item1.points[0] != 0 || // Unused
+ item1.item.Index() != 1 {
+ t.Error(item1)
+ }
+ // Only differ in index
+ item2 := buildResult(&Item{text: util.RunesToChars(str)}, []Offset{}, 2)
+
+ items := []Result{item1, item2}
+ sort.Sort(ByRelevance(items))
+ if items[0] != item2 || items[1] != item1 {
+ t.Error(items)
+ }
+
+ items = []Result{item2, item1, item1, item2}
+ sort.Sort(ByRelevance(items))
+ if items[0] != item2 || items[1] != item2 ||
+ items[2] != item1 || items[3] != item1 {
+ t.Error(items, item1, item1.item.Index(), item2, item2.item.Index())
+ }
+
+ // Sort by relevance
+ item3 := buildResult(
+ withIndex(&Item{}, 2), []Offset{{1, 3}, {5, 7}}, 3)
+ item4 := buildResult(
+ withIndex(&Item{}, 2), []Offset{{1, 2}, {6, 7}}, 4)
+ item5 := buildResult(
+ withIndex(&Item{}, 2), []Offset{{1, 3}, {5, 7}}, 5)
+ item6 := buildResult(
+ withIndex(&Item{}, 2), []Offset{{1, 2}, {6, 7}}, 6)
+ items = []Result{item1, item2, item3, item4, item5, item6}
+ sort.Sort(ByRelevance(items))
+ if !(items[0] == item6 && items[1] == item5 &&
+ items[2] == item4 && items[3] == item3 &&
+ items[4] == item2 && items[5] == item1) {
+ t.Error(items, item1, item2, item3, item4, item5, item6)
+ }
+}
+
+func TestChunkTiebreak(t *testing.T) {
+ // FIXME global
+ sortCriteria = []criterion{byScore, byChunk}
+
+ score := 100
+ test := func(input string, offset Offset, chunk string) {
+ item := buildResult(withIndex(&Item{text: util.RunesToChars([]rune(input))}, 1), []Offset{offset}, score)
+ if !(item.points[3] == math.MaxUint16-uint16(score) && item.points[2] == uint16(len(chunk))) {
+ t.Error(item.points)
+ }
+ }
+ test("hello foobar goodbye", Offset{8, 9}, "foobar")
+ test("hello foobar goodbye", Offset{7, 18}, "foobar goodbye")
+ test("hello foobar goodbye", Offset{0, 1}, "hello")
+ test("hello foobar goodbye", Offset{5, 7}, "hello foobar") // TBD
+}
+
+func TestColorOffset(t *testing.T) {
+ // ------------ 20 ---- -- ----
+ // ++++++++ ++++++++++
+ // --++++++++-- --++++++++++---
+
+ offsets := []Offset{{5, 15}, {25, 35}}
+ item := Result{
+ item: &Item{
+ colors: &[]ansiOffset{
+ {[2]int32{0, 20}, ansiState{1, 5, 0, -1}},
+ {[2]int32{22, 27}, ansiState{2, 6, tui.Bold, -1}},
+ {[2]int32{30, 32}, ansiState{3, 7, 0, -1}},
+ {[2]int32{33, 40}, ansiState{4, 8, tui.Bold, -1}}}}}
+
+ colBase := tui.NewColorPair(89, 189, tui.AttrUndefined)
+ colMatch := tui.NewColorPair(99, 199, tui.AttrUndefined)
+ colors := item.colorOffsets(offsets, tui.Dark256, colBase, colMatch, true)
+ assert := func(idx int, b int32, e int32, c tui.ColorPair) {
+ o := colors[idx]
+ if o.offset[0] != b || o.offset[1] != e || o.color != c {
+ t.Error(o, b, e, c)
+ }
+ }
+ // [{[0 5] {1 5 0}} {[5 15] {99 199 0}} {[15 20] {1 5 0}}
+ // {[22 25] {2 6 1}} {[25 27] {99 199 1}} {[27 30] {99 199 0}}
+ // {[30 32] {99 199 0}} {[32 33] {99 199 0}} {[33 35] {99 199 1}}
+ // {[35 40] {4 8 1}}]
+ assert(0, 0, 5, tui.NewColorPair(1, 5, tui.AttrUndefined))
+ assert(1, 5, 15, colMatch)
+ assert(2, 15, 20, tui.NewColorPair(1, 5, tui.AttrUndefined))
+ assert(3, 22, 25, tui.NewColorPair(2, 6, tui.Bold))
+ assert(4, 25, 27, colMatch.WithAttr(tui.Bold))
+ assert(5, 27, 30, colMatch)
+ assert(6, 30, 32, colMatch)
+ assert(7, 32, 33, colMatch) // TODO: Should we merge consecutive blocks?
+ assert(8, 33, 35, colMatch.WithAttr(tui.Bold))
+ assert(9, 35, 40, tui.NewColorPair(4, 8, tui.Bold))
+
+ colRegular := tui.NewColorPair(-1, -1, tui.AttrUndefined)
+ colUnderline := tui.NewColorPair(-1, -1, tui.Underline)
+ colors = item.colorOffsets(offsets, tui.Dark256, colRegular, colUnderline, true)
+
+ // [{[0 5] {1 5 0}} {[5 15] {1 5 8}} {[15 20] {1 5 0}}
+ // {[22 25] {2 6 1}} {[25 27] {2 6 9}} {[27 30] {-1 -1 8}}
+ // {[30 32] {3 7 8}} {[32 33] {-1 -1 8}} {[33 35] {4 8 9}}
+ // {[35 40] {4 8 1}}]
+ assert(0, 0, 5, tui.NewColorPair(1, 5, tui.AttrUndefined))
+ assert(1, 5, 15, tui.NewColorPair(1, 5, tui.Underline))
+ assert(2, 15, 20, tui.NewColorPair(1, 5, tui.AttrUndefined))
+ assert(3, 22, 25, tui.NewColorPair(2, 6, tui.Bold))
+ assert(4, 25, 27, tui.NewColorPair(2, 6, tui.Bold|tui.Underline))
+ assert(5, 27, 30, colUnderline)
+ assert(6, 30, 32, tui.NewColorPair(3, 7, tui.Underline))
+ assert(7, 32, 33, colUnderline)
+ assert(8, 33, 35, tui.NewColorPair(4, 8, tui.Bold|tui.Underline))
+ assert(9, 35, 40, tui.NewColorPair(4, 8, tui.Bold))
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/result_x86.go b/dot-oh-my-zsh/custom/plugins/fzf/src/result_x86.go
new file mode 100644
index 00000000..3e3fd58e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/result_x86.go
@@ -0,0 +1,16 @@
+//go:build 386 || amd64
+
+package fzf
+
+import "unsafe"
+
+func compareRanks(irank Result, jrank Result, tac bool) bool {
+ left := *(*uint64)(unsafe.Pointer(&irank.points[0]))
+ right := *(*uint64)(unsafe.Pointer(&jrank.points[0]))
+ if left < right {
+ return true
+ } else if left > right {
+ return false
+ }
+ return (irank.item.Index() <= jrank.item.Index()) != tac
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/terminal.go b/dot-oh-my-zsh/custom/plugins/fzf/src/terminal.go
new file mode 100644
index 00000000..981f13a4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/terminal.go
@@ -0,0 +1,2937 @@
+package fzf
+
+import (
+ "bufio"
+ "fmt"
+ "io/ioutil"
+ "math"
+ "os"
+ "os/signal"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+ "time"
+
+ "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
+
+ "github.com/junegunn/fzf/src/tui"
+ "github.com/junegunn/fzf/src/util"
+)
+
+// import "github.com/pkg/profile"
+
+/*
+Placeholder regex is used to extract placeholders from fzf's template
+strings. Acts as input validation for parsePlaceholder function.
+Describes the syntax, but it is fairly lenient.
+
+The following pseudo regex has been reverse engineered from the
+implementation. It is overly strict, but better describes whats possible.
+As such it is not useful for validation, but rather to generate test
+cases for example.
+
+ \\?(?: # escaped type
+ {\+?s?f?RANGE(?:,RANGE)*} # token type
+ |{q} # query type
+ |{\+?n?f?} # item type (notice no mandatory element inside brackets)
+ )
+ RANGE = (?:
+ (?:-?[0-9]+)?\.\.(?:-?[0-9]+)? # ellipsis syntax for token range (x..y)
+ |-?[0-9]+ # shorthand syntax (x..x)
+ )
+*/
+var placeholder *regexp.Regexp
+var whiteSuffix *regexp.Regexp
+var offsetComponentRegex *regexp.Regexp
+var offsetTrimCharsRegex *regexp.Regexp
+var activeTempFiles []string
+
+const clearCode string = "\x1b[2J"
+
+func init() {
+ placeholder = regexp.MustCompile(`\\?(?:{[+sf]*[0-9,-.]*}|{q}|{\+?f?nf?})`)
+ whiteSuffix = regexp.MustCompile(`\s*$`)
+ offsetComponentRegex = regexp.MustCompile(`([+-][0-9]+)|(-?/[1-9][0-9]*)`)
+ offsetTrimCharsRegex = regexp.MustCompile(`[^0-9/+-]`)
+ activeTempFiles = []string{}
+}
+
+type jumpMode int
+
+const (
+ jumpDisabled jumpMode = iota
+ jumpEnabled
+ jumpAcceptEnabled
+)
+
+type previewer struct {
+ version int64
+ lines []string
+ offset int
+ enabled bool
+ scrollable bool
+ final bool
+ following bool
+ spinner string
+}
+
+type previewed struct {
+ version int64
+ numLines int
+ offset int
+ filled bool
+}
+
+type eachLine struct {
+ line string
+ err error
+}
+
+type itemLine struct {
+ current bool
+ selected bool
+ label string
+ queryLen int
+ width int
+ result Result
+}
+
+var emptyLine = itemLine{}
+
+// Terminal represents terminal input/output
+type Terminal struct {
+ initDelay time.Duration
+ infoStyle infoStyle
+ spinner []string
+ prompt func()
+ promptLen int
+ pointer string
+ pointerLen int
+ pointerEmpty string
+ marker string
+ markerLen int
+ markerEmpty string
+ queryLen [2]int
+ layout layoutType
+ fullscreen bool
+ keepRight bool
+ hscroll bool
+ hscrollOff int
+ scrollOff int
+ wordRubout string
+ wordNext string
+ cx int
+ cy int
+ offset int
+ xoffset int
+ yanked []rune
+ input []rune
+ multi int
+ sort bool
+ toggleSort bool
+ delimiter Delimiter
+ expect map[tui.Event]string
+ keymap map[tui.Event][]*action
+ keymapOrg map[tui.Event][]*action
+ pressed string
+ printQuery bool
+ history *History
+ cycle bool
+ headerFirst bool
+ headerLines int
+ header []string
+ header0 []string
+ ellipsis string
+ ansi bool
+ tabstop int
+ margin [4]sizeSpec
+ padding [4]sizeSpec
+ strong tui.Attr
+ unicode bool
+ borderShape tui.BorderShape
+ cleanExit bool
+ paused bool
+ border tui.Window
+ window tui.Window
+ pborder tui.Window
+ pwindow tui.Window
+ count int
+ progress int
+ reading bool
+ running bool
+ failed *string
+ jumping jumpMode
+ jumpLabels string
+ printer func(string)
+ printsep string
+ merger *Merger
+ selected map[int32]selectedItem
+ version int64
+ reqBox *util.EventBox
+ initialPreviewOpts previewOpts
+ previewOpts previewOpts
+ previewer previewer
+ previewed previewed
+ previewBox *util.EventBox
+ eventBox *util.EventBox
+ mutex sync.Mutex
+ initFunc func()
+ prevLines []itemLine
+ suppress bool
+ sigstop bool
+ startChan chan bool
+ killChan chan int
+ slab *util.Slab
+ theme *tui.ColorTheme
+ tui tui.Renderer
+ executing *util.AtomicBool
+}
+
+type selectedItem struct {
+ at time.Time
+ item *Item
+}
+
+type byTimeOrder []selectedItem
+
+func (a byTimeOrder) Len() int {
+ return len(a)
+}
+
+func (a byTimeOrder) Swap(i, j int) {
+ a[i], a[j] = a[j], a[i]
+}
+
+func (a byTimeOrder) Less(i, j int) bool {
+ return a[i].at.Before(a[j].at)
+}
+
+const (
+ reqPrompt util.EventType = iota
+ reqInfo
+ reqHeader
+ reqList
+ reqJump
+ reqRefresh
+ reqReinit
+ reqRedraw
+ reqFullRedraw
+ reqClose
+ reqPrintQuery
+ reqPreviewEnqueue
+ reqPreviewDisplay
+ reqPreviewRefresh
+ reqPreviewDelayed
+ reqQuit
+)
+
+type action struct {
+ t actionType
+ a string
+}
+
+type actionType int
+
+const (
+ actIgnore actionType = iota
+ actInvalid
+ actRune
+ actMouse
+ actBeginningOfLine
+ actAbort
+ actAccept
+ actAcceptNonEmpty
+ actBackwardChar
+ actBackwardDeleteChar
+ actBackwardDeleteCharEOF
+ actBackwardWord
+ actCancel
+ actChangePrompt
+ actClearScreen
+ actClearQuery
+ actClearSelection
+ actClose
+ actDeleteChar
+ actDeleteCharEOF
+ actEndOfLine
+ actForwardChar
+ actForwardWord
+ actKillLine
+ actKillWord
+ actUnixLineDiscard
+ actUnixWordRubout
+ actYank
+ actBackwardKillWord
+ actSelectAll
+ actDeselectAll
+ actToggle
+ actToggleSearch
+ actToggleAll
+ actToggleDown
+ actToggleUp
+ actToggleIn
+ actToggleOut
+ actDown
+ actUp
+ actPageUp
+ actPageDown
+ actHalfPageUp
+ actHalfPageDown
+ actJump
+ actJumpAccept
+ actPrintQuery
+ actRefreshPreview
+ actReplaceQuery
+ actToggleSort
+ actTogglePreview
+ actTogglePreviewWrap
+ actPreview
+ actChangePreview
+ actChangePreviewWindow
+ actPreviewTop
+ actPreviewBottom
+ actPreviewUp
+ actPreviewDown
+ actPreviewPageUp
+ actPreviewPageDown
+ actPreviewHalfPageUp
+ actPreviewHalfPageDown
+ actPreviousHistory
+ actNextHistory
+ actExecute
+ actExecuteSilent
+ actExecuteMulti // Deprecated
+ actSigStop
+ actFirst
+ actLast
+ actReload
+ actDisableSearch
+ actEnableSearch
+ actSelect
+ actDeselect
+ actUnbind
+ actRebind
+)
+
+type placeholderFlags struct {
+ plus bool
+ preserveSpace bool
+ number bool
+ query bool
+ file bool
+}
+
+type searchRequest struct {
+ sort bool
+ command *string
+}
+
+type previewRequest struct {
+ template string
+ pwindow tui.Window
+ scrollOffset int
+ list []*Item
+}
+
+type previewResult struct {
+ version int64
+ lines []string
+ offset int
+ spinner string
+}
+
+func toActions(types ...actionType) []*action {
+ actions := make([]*action, len(types))
+ for idx, t := range types {
+ actions[idx] = &action{t: t, a: ""}
+ }
+ return actions
+}
+
+func defaultKeymap() map[tui.Event][]*action {
+ keymap := make(map[tui.Event][]*action)
+ add := func(e tui.EventType, a actionType) {
+ keymap[e.AsEvent()] = toActions(a)
+ }
+ addEvent := func(e tui.Event, a actionType) {
+ keymap[e] = toActions(a)
+ }
+
+ add(tui.Invalid, actInvalid)
+ add(tui.Resize, actClearScreen)
+ add(tui.CtrlA, actBeginningOfLine)
+ add(tui.CtrlB, actBackwardChar)
+ add(tui.CtrlC, actAbort)
+ add(tui.CtrlG, actAbort)
+ add(tui.CtrlQ, actAbort)
+ add(tui.ESC, actAbort)
+ add(tui.CtrlD, actDeleteCharEOF)
+ add(tui.CtrlE, actEndOfLine)
+ add(tui.CtrlF, actForwardChar)
+ add(tui.CtrlH, actBackwardDeleteChar)
+ add(tui.BSpace, actBackwardDeleteChar)
+ add(tui.Tab, actToggleDown)
+ add(tui.BTab, actToggleUp)
+ add(tui.CtrlJ, actDown)
+ add(tui.CtrlK, actUp)
+ add(tui.CtrlL, actClearScreen)
+ add(tui.CtrlM, actAccept)
+ add(tui.CtrlN, actDown)
+ add(tui.CtrlP, actUp)
+ add(tui.CtrlU, actUnixLineDiscard)
+ add(tui.CtrlW, actUnixWordRubout)
+ add(tui.CtrlY, actYank)
+ if !util.IsWindows() {
+ add(tui.CtrlZ, actSigStop)
+ }
+
+ addEvent(tui.AltKey('b'), actBackwardWord)
+ add(tui.SLeft, actBackwardWord)
+ addEvent(tui.AltKey('f'), actForwardWord)
+ add(tui.SRight, actForwardWord)
+ addEvent(tui.AltKey('d'), actKillWord)
+ add(tui.AltBS, actBackwardKillWord)
+
+ add(tui.Up, actUp)
+ add(tui.Down, actDown)
+ add(tui.Left, actBackwardChar)
+ add(tui.Right, actForwardChar)
+
+ add(tui.Home, actBeginningOfLine)
+ add(tui.End, actEndOfLine)
+ add(tui.Del, actDeleteChar)
+ add(tui.PgUp, actPageUp)
+ add(tui.PgDn, actPageDown)
+
+ add(tui.SUp, actPreviewUp)
+ add(tui.SDown, actPreviewDown)
+
+ add(tui.Mouse, actMouse)
+ add(tui.DoubleClick, actAccept)
+ add(tui.LeftClick, actIgnore)
+ add(tui.RightClick, actToggle)
+ return keymap
+}
+
+func trimQuery(query string) []rune {
+ return []rune(strings.Replace(query, "\t", " ", -1))
+}
+
+func hasPreviewAction(opts *Options) bool {
+ for _, actions := range opts.Keymap {
+ for _, action := range actions {
+ if action.t == actPreview || action.t == actChangePreview {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func makeSpinner(unicode bool) []string {
+ if unicode {
+ return []string{`⠋`, `⠙`, `⠹`, `⠸`, `⠼`, `⠴`, `⠦`, `⠧`, `⠇`, `⠏`}
+ }
+ return []string{`-`, `\`, `|`, `/`, `-`, `\`, `|`, `/`}
+}
+
+// NewTerminal returns new Terminal object
+func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
+ input := trimQuery(opts.Query)
+ var header []string
+ switch opts.Layout {
+ case layoutDefault, layoutReverseList:
+ header = reverseStringArray(opts.Header)
+ default:
+ header = opts.Header
+ }
+ var delay time.Duration
+ if opts.Tac {
+ delay = initialDelayTac
+ } else {
+ delay = initialDelay
+ }
+ var previewBox *util.EventBox
+ showPreviewWindow := len(opts.Preview.command) > 0 && !opts.Preview.hidden
+ if len(opts.Preview.command) > 0 || hasPreviewAction(opts) {
+ previewBox = util.NewEventBox()
+ }
+ strongAttr := tui.Bold
+ if !opts.Bold {
+ strongAttr = tui.AttrRegular
+ }
+ var renderer tui.Renderer
+ fullscreen := opts.Height.size == 0 || opts.Height.percent && opts.Height.size == 100
+ if fullscreen {
+ if tui.HasFullscreenRenderer() {
+ renderer = tui.NewFullscreenRenderer(opts.Theme, opts.Black, opts.Mouse)
+ } else {
+ renderer = tui.NewLightRenderer(opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit,
+ true, func(h int) int { return h })
+ }
+ } else {
+ maxHeightFunc := func(termHeight int) int {
+ var maxHeight int
+ if opts.Height.percent {
+ maxHeight = util.Max(int(opts.Height.size*float64(termHeight)/100.0), opts.MinHeight)
+ } else {
+ maxHeight = int(opts.Height.size)
+ }
+
+ effectiveMinHeight := minHeight
+ if previewBox != nil && (opts.Preview.position == posUp || opts.Preview.position == posDown) {
+ effectiveMinHeight *= 2
+ }
+ if opts.InfoStyle != infoDefault {
+ effectiveMinHeight--
+ }
+ if opts.BorderShape != tui.BorderNone {
+ effectiveMinHeight += 2
+ }
+ return util.Min(termHeight, util.Max(maxHeight, effectiveMinHeight))
+ }
+ renderer = tui.NewLightRenderer(opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, opts.ClearOnExit, false, maxHeightFunc)
+ }
+ wordRubout := "[^\\pL\\pN][\\pL\\pN]"
+ wordNext := "[\\pL\\pN][^\\pL\\pN]|(.$)"
+ if opts.FileWord {
+ sep := regexp.QuoteMeta(string(os.PathSeparator))
+ wordRubout = fmt.Sprintf("%s[^%s]", sep, sep)
+ wordNext = fmt.Sprintf("[^%s]%s|(.$)", sep, sep)
+ }
+ keymapCopy := make(map[tui.Event][]*action)
+ for key, action := range opts.Keymap {
+ keymapCopy[key] = action
+ }
+ t := Terminal{
+ initDelay: delay,
+ infoStyle: opts.InfoStyle,
+ spinner: makeSpinner(opts.Unicode),
+ queryLen: [2]int{0, 0},
+ layout: opts.Layout,
+ fullscreen: fullscreen,
+ keepRight: opts.KeepRight,
+ hscroll: opts.Hscroll,
+ hscrollOff: opts.HscrollOff,
+ scrollOff: opts.ScrollOff,
+ wordRubout: wordRubout,
+ wordNext: wordNext,
+ cx: len(input),
+ cy: 0,
+ offset: 0,
+ xoffset: 0,
+ yanked: []rune{},
+ input: input,
+ multi: opts.Multi,
+ sort: opts.Sort > 0,
+ toggleSort: opts.ToggleSort,
+ delimiter: opts.Delimiter,
+ expect: opts.Expect,
+ keymap: opts.Keymap,
+ keymapOrg: keymapCopy,
+ pressed: "",
+ printQuery: opts.PrintQuery,
+ history: opts.History,
+ margin: opts.Margin,
+ padding: opts.Padding,
+ unicode: opts.Unicode,
+ borderShape: opts.BorderShape,
+ cleanExit: opts.ClearOnExit,
+ paused: opts.Phony,
+ strong: strongAttr,
+ cycle: opts.Cycle,
+ headerFirst: opts.HeaderFirst,
+ headerLines: opts.HeaderLines,
+ header: header,
+ header0: header,
+ ellipsis: opts.Ellipsis,
+ ansi: opts.Ansi,
+ tabstop: opts.Tabstop,
+ reading: true,
+ running: true,
+ failed: nil,
+ jumping: jumpDisabled,
+ jumpLabels: opts.JumpLabels,
+ printer: opts.Printer,
+ printsep: opts.PrintSep,
+ merger: EmptyMerger,
+ selected: make(map[int32]selectedItem),
+ reqBox: util.NewEventBox(),
+ initialPreviewOpts: opts.Preview,
+ previewOpts: opts.Preview,
+ previewer: previewer{0, []string{}, 0, showPreviewWindow, false, true, false, ""},
+ previewed: previewed{0, 0, 0, false},
+ previewBox: previewBox,
+ eventBox: eventBox,
+ mutex: sync.Mutex{},
+ suppress: true,
+ sigstop: false,
+ slab: util.MakeSlab(slab16Size, slab32Size),
+ theme: opts.Theme,
+ startChan: make(chan bool, 1),
+ killChan: make(chan int),
+ tui: renderer,
+ initFunc: func() { renderer.Init() },
+ executing: util.NewAtomicBool(false)}
+ t.prompt, t.promptLen = t.parsePrompt(opts.Prompt)
+ t.pointer, t.pointerLen = t.processTabs([]rune(opts.Pointer), 0)
+ t.marker, t.markerLen = t.processTabs([]rune(opts.Marker), 0)
+ // Pre-calculated empty pointer and marker signs
+ t.pointerEmpty = strings.Repeat(" ", t.pointerLen)
+ t.markerEmpty = strings.Repeat(" ", t.markerLen)
+
+ return &t
+}
+
+func (t *Terminal) parsePrompt(prompt string) (func(), int) {
+ var state *ansiState
+ trimmed, colors, _ := extractColor(prompt, state, nil)
+ item := &Item{text: util.ToChars([]byte(trimmed)), colors: colors}
+
+ // "Prompt> "
+ // ------- // Do not apply ANSI attributes to the trailing whitespaces
+ // // unless the part has a non-default ANSI state
+ loc := whiteSuffix.FindStringIndex(trimmed)
+ if loc != nil {
+ blankState := ansiOffset{[2]int32{int32(loc[0]), int32(loc[1])}, ansiState{-1, -1, tui.AttrClear, -1}}
+ if item.colors != nil {
+ lastColor := (*item.colors)[len(*item.colors)-1]
+ if lastColor.offset[1] < int32(loc[1]) {
+ blankState.offset[0] = lastColor.offset[1]
+ colors := append(*item.colors, blankState)
+ item.colors = &colors
+ }
+ } else {
+ colors := []ansiOffset{blankState}
+ item.colors = &colors
+ }
+ }
+ output := func() {
+ t.printHighlighted(
+ Result{item: item}, tui.ColPrompt, tui.ColPrompt, false, false)
+ }
+ _, promptLen := t.processTabs([]rune(trimmed), 0)
+
+ return output, promptLen
+}
+
+func (t *Terminal) noInfoLine() bool {
+ return t.infoStyle != infoDefault
+}
+
+// Input returns current query string
+func (t *Terminal) Input() (bool, []rune) {
+ t.mutex.Lock()
+ defer t.mutex.Unlock()
+ return t.paused, copySlice(t.input)
+}
+
+// UpdateCount updates the count information
+func (t *Terminal) UpdateCount(cnt int, final bool, failedCommand *string) {
+ t.mutex.Lock()
+ t.count = cnt
+ t.reading = !final
+ t.failed = failedCommand
+ t.mutex.Unlock()
+ t.reqBox.Set(reqInfo, nil)
+ if final {
+ t.reqBox.Set(reqRefresh, nil)
+ }
+}
+
+func reverseStringArray(input []string) []string {
+ size := len(input)
+ reversed := make([]string, size)
+ for idx, str := range input {
+ reversed[size-idx-1] = str
+ }
+ return reversed
+}
+
+// UpdateHeader updates the header
+func (t *Terminal) UpdateHeader(header []string) {
+ t.mutex.Lock()
+ t.header = append(append([]string{}, t.header0...), header...)
+ t.mutex.Unlock()
+ t.reqBox.Set(reqHeader, nil)
+}
+
+// UpdateProgress updates the search progress
+func (t *Terminal) UpdateProgress(progress float32) {
+ t.mutex.Lock()
+ newProgress := int(progress * 100)
+ changed := t.progress != newProgress
+ t.progress = newProgress
+ t.mutex.Unlock()
+
+ if changed {
+ t.reqBox.Set(reqInfo, nil)
+ }
+}
+
+// UpdateList updates Merger to display the list
+func (t *Terminal) UpdateList(merger *Merger, reset bool) {
+ t.mutex.Lock()
+ t.progress = 100
+ t.merger = merger
+ if reset {
+ t.selected = make(map[int32]selectedItem)
+ t.version++
+ }
+ t.mutex.Unlock()
+ t.reqBox.Set(reqInfo, nil)
+ t.reqBox.Set(reqList, nil)
+}
+
+func (t *Terminal) output() bool {
+ if t.printQuery {
+ t.printer(string(t.input))
+ }
+ if len(t.expect) > 0 {
+ t.printer(t.pressed)
+ }
+ found := len(t.selected) > 0
+ if !found {
+ current := t.currentItem()
+ if current != nil {
+ t.printer(current.AsString(t.ansi))
+ found = true
+ }
+ } else {
+ for _, sel := range t.sortSelected() {
+ t.printer(sel.item.AsString(t.ansi))
+ }
+ }
+ return found
+}
+
+func (t *Terminal) sortSelected() []selectedItem {
+ sels := make([]selectedItem, 0, len(t.selected))
+ for _, sel := range t.selected {
+ sels = append(sels, sel)
+ }
+ sort.Sort(byTimeOrder(sels))
+ return sels
+}
+
+func (t *Terminal) displayWidth(runes []rune) int {
+ width, _ := util.RunesWidth(runes, 0, t.tabstop, math.MaxInt32)
+ return width
+}
+
+const (
+ minWidth = 4
+ minHeight = 4
+)
+
+func calculateSize(base int, size sizeSpec, occupied int, minSize int, pad int) int {
+ max := base - occupied
+ if size.percent {
+ return util.Constrain(int(float64(base)*0.01*size.size), minSize, max)
+ }
+ return util.Constrain(int(size.size)+pad, minSize, max)
+}
+
+func (t *Terminal) resizeWindows() {
+ screenWidth := t.tui.MaxX()
+ screenHeight := t.tui.MaxY()
+ t.prevLines = make([]itemLine, screenHeight)
+
+ marginInt := [4]int{} // TRBL
+ paddingInt := [4]int{} // TRBL
+ sizeSpecToInt := func(index int, spec sizeSpec) int {
+ if spec.percent {
+ var max float64
+ if index%2 == 0 {
+ max = float64(screenHeight)
+ } else {
+ max = float64(screenWidth)
+ }
+ return int(max * spec.size * 0.01)
+ }
+ return int(spec.size)
+ }
+ for idx, sizeSpec := range t.padding {
+ paddingInt[idx] = sizeSpecToInt(idx, sizeSpec)
+ }
+
+ extraMargin := [4]int{} // TRBL
+ for idx, sizeSpec := range t.margin {
+ switch t.borderShape {
+ case tui.BorderHorizontal:
+ extraMargin[idx] += 1 - idx%2
+ case tui.BorderVertical:
+ extraMargin[idx] += 2 * (idx % 2)
+ case tui.BorderTop:
+ if idx == 0 {
+ extraMargin[idx]++
+ }
+ case tui.BorderRight:
+ if idx == 1 {
+ extraMargin[idx] += 2
+ }
+ case tui.BorderBottom:
+ if idx == 2 {
+ extraMargin[idx]++
+ }
+ case tui.BorderLeft:
+ if idx == 3 {
+ extraMargin[idx] += 2
+ }
+ case tui.BorderRounded, tui.BorderSharp:
+ extraMargin[idx] += 1 + idx%2
+ }
+ marginInt[idx] = sizeSpecToInt(idx, sizeSpec) + extraMargin[idx]
+ }
+
+ adjust := func(idx1 int, idx2 int, max int, min int) {
+ if max >= min {
+ margin := marginInt[idx1] + marginInt[idx2] + paddingInt[idx1] + paddingInt[idx2]
+ if max-margin < min {
+ desired := max - min
+ paddingInt[idx1] = desired * paddingInt[idx1] / margin
+ paddingInt[idx2] = desired * paddingInt[idx2] / margin
+ marginInt[idx1] = util.Max(extraMargin[idx1], desired*marginInt[idx1]/margin)
+ marginInt[idx2] = util.Max(extraMargin[idx2], desired*marginInt[idx2]/margin)
+ }
+ }
+ }
+
+ previewVisible := t.isPreviewEnabled() && t.previewOpts.size.size > 0
+ minAreaWidth := minWidth
+ minAreaHeight := minHeight
+ if previewVisible {
+ switch t.previewOpts.position {
+ case posUp, posDown:
+ minAreaHeight *= 2
+ case posLeft, posRight:
+ minAreaWidth *= 2
+ }
+ }
+ adjust(1, 3, screenWidth, minAreaWidth)
+ adjust(0, 2, screenHeight, minAreaHeight)
+ if t.border != nil {
+ t.border.Close()
+ }
+ if t.window != nil {
+ t.window.Close()
+ t.window = nil
+ }
+ if t.pborder != nil {
+ t.pborder.Close()
+ t.pborder = nil
+ }
+ if t.pwindow != nil {
+ t.pwindow.Close()
+ t.pwindow = nil
+ }
+ // Reset preview version so that full redraw occurs
+ t.previewed.version = 0
+
+ width := screenWidth - marginInt[1] - marginInt[3]
+ height := screenHeight - marginInt[0] - marginInt[2]
+ switch t.borderShape {
+ case tui.BorderHorizontal:
+ t.border = t.tui.NewWindow(
+ marginInt[0]-1, marginInt[3], width, height+2,
+ false, tui.MakeBorderStyle(tui.BorderHorizontal, t.unicode))
+ case tui.BorderVertical:
+ t.border = t.tui.NewWindow(
+ marginInt[0], marginInt[3]-2, width+4, height,
+ false, tui.MakeBorderStyle(tui.BorderVertical, t.unicode))
+ case tui.BorderTop:
+ t.border = t.tui.NewWindow(
+ marginInt[0]-1, marginInt[3], width, height+1,
+ false, tui.MakeBorderStyle(tui.BorderTop, t.unicode))
+ case tui.BorderBottom:
+ t.border = t.tui.NewWindow(
+ marginInt[0], marginInt[3], width, height+1,
+ false, tui.MakeBorderStyle(tui.BorderBottom, t.unicode))
+ case tui.BorderLeft:
+ t.border = t.tui.NewWindow(
+ marginInt[0], marginInt[3]-2, width+2, height,
+ false, tui.MakeBorderStyle(tui.BorderLeft, t.unicode))
+ case tui.BorderRight:
+ t.border = t.tui.NewWindow(
+ marginInt[0], marginInt[3], width+2, height,
+ false, tui.MakeBorderStyle(tui.BorderRight, t.unicode))
+ case tui.BorderRounded, tui.BorderSharp:
+ t.border = t.tui.NewWindow(
+ marginInt[0]-1, marginInt[3]-2, width+4, height+2,
+ false, tui.MakeBorderStyle(t.borderShape, t.unicode))
+ }
+
+ // Add padding
+ for idx, val := range paddingInt {
+ marginInt[idx] += val
+ }
+ width = screenWidth - marginInt[1] - marginInt[3]
+ height = screenHeight - marginInt[0] - marginInt[2]
+
+ // Set up preview window
+ noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode)
+ if previewVisible {
+ var resizePreviewWindows func(previewOpts previewOpts)
+ resizePreviewWindows = func(previewOpts previewOpts) {
+ hasThreshold := previewOpts.threshold > 0 && previewOpts.alternative != nil
+ createPreviewWindow := func(y int, x int, w int, h int) {
+ pwidth := w
+ pheight := h
+ var previewBorder tui.BorderStyle
+ if previewOpts.border == tui.BorderNone {
+ previewBorder = tui.MakeTransparentBorder()
+ } else {
+ previewBorder = tui.MakeBorderStyle(previewOpts.border, t.unicode)
+ }
+ t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder)
+ switch previewOpts.border {
+ case tui.BorderSharp, tui.BorderRounded:
+ pwidth -= 4
+ pheight -= 2
+ x += 2
+ y += 1
+ case tui.BorderLeft:
+ pwidth -= 2
+ x += 2
+ case tui.BorderRight:
+ pwidth -= 2
+ case tui.BorderTop:
+ pheight -= 1
+ y += 1
+ case tui.BorderBottom:
+ pheight -= 1
+ case tui.BorderHorizontal:
+ pheight -= 2
+ y += 1
+ case tui.BorderVertical:
+ pwidth -= 4
+ x += 2
+ }
+ t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, true, noBorder)
+ }
+ verticalPad := 2
+ minPreviewHeight := 3
+ switch previewOpts.border {
+ case tui.BorderNone, tui.BorderVertical, tui.BorderLeft, tui.BorderRight:
+ verticalPad = 0
+ minPreviewHeight = 1
+ case tui.BorderTop, tui.BorderBottom:
+ verticalPad = 1
+ minPreviewHeight = 2
+ }
+ switch previewOpts.position {
+ case posUp, posDown:
+ pheight := calculateSize(height, previewOpts.size, minHeight, minPreviewHeight, verticalPad)
+ if hasThreshold && pheight < previewOpts.threshold {
+ if !previewOpts.alternative.hidden {
+ resizePreviewWindows(*previewOpts.alternative)
+ }
+ return
+ }
+ if previewOpts.position == posUp {
+ t.window = t.tui.NewWindow(
+ marginInt[0]+pheight, marginInt[3], width, height-pheight, false, noBorder)
+ createPreviewWindow(marginInt[0], marginInt[3], width, pheight)
+ } else {
+ t.window = t.tui.NewWindow(
+ marginInt[0], marginInt[3], width, height-pheight, false, noBorder)
+ createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight)
+ }
+ case posLeft, posRight:
+ pwidth := calculateSize(width, previewOpts.size, minWidth, 5, 4)
+ if hasThreshold && pwidth < previewOpts.threshold {
+ if !previewOpts.alternative.hidden {
+ resizePreviewWindows(*previewOpts.alternative)
+ }
+ return
+ }
+ if previewOpts.position == posLeft {
+ t.window = t.tui.NewWindow(
+ marginInt[0], marginInt[3]+pwidth, width-pwidth, height, false, noBorder)
+ createPreviewWindow(marginInt[0], marginInt[3], pwidth, height)
+ } else {
+ t.window = t.tui.NewWindow(
+ marginInt[0], marginInt[3], width-pwidth, height, false, noBorder)
+ createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height)
+ }
+ }
+ }
+ resizePreviewWindows(t.previewOpts)
+ }
+ if t.window == nil {
+ t.window = t.tui.NewWindow(
+ marginInt[0],
+ marginInt[3],
+ width,
+ height, false, noBorder)
+ }
+ for i := 0; i < t.window.Height(); i++ {
+ t.window.MoveAndClear(i, 0)
+ }
+}
+
+func (t *Terminal) move(y int, x int, clear bool) {
+ h := t.window.Height()
+
+ switch t.layout {
+ case layoutDefault:
+ y = h - y - 1
+ case layoutReverseList:
+ n := 2 + len(t.header)
+ if t.noInfoLine() {
+ n--
+ }
+ if y < n {
+ y = h - y - 1
+ } else {
+ y -= n
+ }
+ }
+
+ if clear {
+ t.window.MoveAndClear(y, x)
+ } else {
+ t.window.Move(y, x)
+ }
+}
+
+func (t *Terminal) truncateQuery() {
+ t.input, _ = t.trimRight(t.input, maxPatternLength)
+ t.cx = util.Constrain(t.cx, 0, len(t.input))
+}
+
+func (t *Terminal) updatePromptOffset() ([]rune, []rune) {
+ maxWidth := util.Max(1, t.window.Width()-t.promptLen-1)
+
+ _, overflow := t.trimLeft(t.input[:t.cx], maxWidth)
+ minOffset := int(overflow)
+ maxOffset := util.Min(util.Min(len(t.input), minOffset+maxWidth), t.cx)
+
+ t.xoffset = util.Constrain(t.xoffset, minOffset, maxOffset)
+ before, _ := t.trimLeft(t.input[t.xoffset:t.cx], maxWidth)
+ beforeLen := t.displayWidth(before)
+ after, _ := t.trimRight(t.input[t.cx:], maxWidth-beforeLen)
+ afterLen := t.displayWidth(after)
+ t.queryLen = [2]int{beforeLen, afterLen}
+ return before, after
+}
+
+func (t *Terminal) promptLine() int {
+ if t.headerFirst {
+ max := t.window.Height() - 1
+ if !t.noInfoLine() {
+ max--
+ }
+ return util.Min(len(t.header0)+t.headerLines, max)
+ }
+ return 0
+}
+
+func (t *Terminal) placeCursor() {
+ t.move(t.promptLine(), t.promptLen+t.queryLen[0], false)
+}
+
+func (t *Terminal) printPrompt() {
+ t.move(t.promptLine(), 0, true)
+ t.prompt()
+
+ before, after := t.updatePromptOffset()
+ color := tui.ColInput
+ if t.paused {
+ color = tui.ColDisabled
+ }
+ t.window.CPrint(color, string(before))
+ t.window.CPrint(color, string(after))
+}
+
+func (t *Terminal) trimMessage(message string, maxWidth int) string {
+ if len(message) <= maxWidth {
+ return message
+ }
+ runes, _ := t.trimRight([]rune(message), maxWidth-2)
+ return string(runes) + strings.Repeat(".", util.Constrain(maxWidth, 0, 2))
+}
+
+func (t *Terminal) printInfo() {
+ pos := 0
+ line := t.promptLine()
+ switch t.infoStyle {
+ case infoDefault:
+ t.move(line+1, 0, true)
+ if t.reading {
+ duration := int64(spinnerDuration)
+ idx := (time.Now().UnixNano() % (duration * int64(len(t.spinner)))) / duration
+ t.window.CPrint(tui.ColSpinner, t.spinner[idx])
+ }
+ t.move(line+1, 2, false)
+ pos = 2
+ case infoInline:
+ pos = t.promptLen + t.queryLen[0] + t.queryLen[1] + 1
+ if pos+len(" < ") > t.window.Width() {
+ return
+ }
+ t.move(line, pos, true)
+ if t.reading {
+ t.window.CPrint(tui.ColSpinner, " < ")
+ } else {
+ t.window.CPrint(tui.ColPrompt, " < ")
+ }
+ pos += len(" < ")
+ case infoHidden:
+ return
+ }
+
+ found := t.merger.Length()
+ total := util.Max(found, t.count)
+ output := fmt.Sprintf("%d/%d", found, total)
+ if t.toggleSort {
+ if t.sort {
+ output += " +S"
+ } else {
+ output += " -S"
+ }
+ }
+ if t.multi > 0 {
+ if t.multi == maxMulti {
+ output += fmt.Sprintf(" (%d)", len(t.selected))
+ } else {
+ output += fmt.Sprintf(" (%d/%d)", len(t.selected), t.multi)
+ }
+ }
+ if t.progress > 0 && t.progress < 100 {
+ output += fmt.Sprintf(" (%d%%)", t.progress)
+ }
+ if t.failed != nil && t.count == 0 {
+ output = fmt.Sprintf("[Command failed: %s]", *t.failed)
+ }
+ output = t.trimMessage(output, t.window.Width()-pos)
+ t.window.CPrint(tui.ColInfo, output)
+}
+
+func (t *Terminal) printHeader() {
+ if len(t.header) == 0 {
+ return
+ }
+ max := t.window.Height()
+ if t.headerFirst {
+ max--
+ if !t.noInfoLine() {
+ max--
+ }
+ }
+ var state *ansiState
+ for idx, lineStr := range t.header {
+ line := idx
+ if !t.headerFirst {
+ line++
+ if !t.noInfoLine() {
+ line++
+ }
+ }
+ if line >= max {
+ continue
+ }
+ trimmed, colors, newState := extractColor(lineStr, state, nil)
+ state = newState
+ item := &Item{
+ text: util.ToChars([]byte(trimmed)),
+ colors: colors}
+
+ t.move(line, 2, true)
+ t.printHighlighted(Result{item: item},
+ tui.ColHeader, tui.ColHeader, false, false)
+ }
+}
+
+func (t *Terminal) printList() {
+ t.constrain()
+
+ maxy := t.maxItems()
+ count := t.merger.Length() - t.offset
+ for j := 0; j < maxy; j++ {
+ i := j
+ if t.layout == layoutDefault {
+ i = maxy - 1 - j
+ }
+ line := i + 2 + len(t.header)
+ if t.noInfoLine() {
+ line--
+ }
+ if i < count {
+ t.printItem(t.merger.Get(i+t.offset), line, i, i == t.cy-t.offset)
+ } else if t.prevLines[i] != emptyLine {
+ t.prevLines[i] = emptyLine
+ t.move(line, 0, true)
+ }
+ }
+}
+
+func (t *Terminal) printItem(result Result, line int, i int, current bool) {
+ item := result.item
+ _, selected := t.selected[item.Index()]
+ label := ""
+ if t.jumping != jumpDisabled {
+ if i < len(t.jumpLabels) {
+ // Striped
+ current = i%2 == 0
+ label = t.jumpLabels[i:i+1] + strings.Repeat(" ", t.pointerLen-1)
+ }
+ } else if current {
+ label = t.pointer
+ }
+
+ // Avoid unnecessary redraw
+ newLine := itemLine{current: current, selected: selected, label: label,
+ result: result, queryLen: len(t.input), width: 0}
+ prevLine := t.prevLines[i]
+ if prevLine.current == newLine.current &&
+ prevLine.selected == newLine.selected &&
+ prevLine.label == newLine.label &&
+ prevLine.queryLen == newLine.queryLen &&
+ prevLine.result == newLine.result {
+ return
+ }
+
+ t.move(line, 0, false)
+ if current {
+ if len(label) == 0 {
+ t.window.CPrint(tui.ColCurrentCursorEmpty, t.pointerEmpty)
+ } else {
+ t.window.CPrint(tui.ColCurrentCursor, label)
+ }
+ if selected {
+ t.window.CPrint(tui.ColCurrentSelected, t.marker)
+ } else {
+ t.window.CPrint(tui.ColCurrentSelectedEmpty, t.markerEmpty)
+ }
+ newLine.width = t.printHighlighted(result, tui.ColCurrent, tui.ColCurrentMatch, true, true)
+ } else {
+ if len(label) == 0 {
+ t.window.CPrint(tui.ColCursorEmpty, t.pointerEmpty)
+ } else {
+ t.window.CPrint(tui.ColCursor, label)
+ }
+ if selected {
+ t.window.CPrint(tui.ColSelected, t.marker)
+ } else {
+ t.window.Print(t.markerEmpty)
+ }
+ newLine.width = t.printHighlighted(result, tui.ColNormal, tui.ColMatch, false, true)
+ }
+ fillSpaces := prevLine.width - newLine.width
+ if fillSpaces > 0 {
+ t.window.Print(strings.Repeat(" ", fillSpaces))
+ }
+ t.prevLines[i] = newLine
+}
+
+func (t *Terminal) trimRight(runes []rune, width int) ([]rune, bool) {
+ // We start from the beginning to handle tab characters
+ _, overflowIdx := util.RunesWidth(runes, 0, t.tabstop, width)
+ if overflowIdx >= 0 {
+ return runes[:overflowIdx], true
+ }
+ return runes, false
+}
+
+func (t *Terminal) displayWidthWithLimit(runes []rune, prefixWidth int, limit int) int {
+ width, _ := util.RunesWidth(runes, prefixWidth, t.tabstop, limit)
+ return width
+}
+
+func (t *Terminal) trimLeft(runes []rune, width int) ([]rune, int32) {
+ width = util.Max(0, width)
+ var trimmed int32
+ // Assume that each rune takes at least one column on screen
+ if len(runes) > width+2 {
+ diff := len(runes) - width - 2
+ trimmed = int32(diff)
+ runes = runes[diff:]
+ }
+
+ currentWidth := t.displayWidth(runes)
+
+ for currentWidth > width && len(runes) > 0 {
+ runes = runes[1:]
+ trimmed++
+ currentWidth = t.displayWidthWithLimit(runes, 2, width)
+ }
+ return runes, trimmed
+}
+
+func (t *Terminal) overflow(runes []rune, max int) bool {
+ return t.displayWidthWithLimit(runes, 0, max) > max
+}
+
+func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMatch tui.ColorPair, current bool, match bool) int {
+ item := result.item
+
+ // Overflow
+ text := make([]rune, item.text.Length())
+ copy(text, item.text.ToRunes())
+ matchOffsets := []Offset{}
+ var pos *[]int
+ if match && t.merger.pattern != nil {
+ _, matchOffsets, pos = t.merger.pattern.MatchItem(item, true, t.slab)
+ }
+ charOffsets := matchOffsets
+ if pos != nil {
+ charOffsets = make([]Offset, len(*pos))
+ for idx, p := range *pos {
+ offset := Offset{int32(p), int32(p + 1)}
+ charOffsets[idx] = offset
+ }
+ sort.Sort(ByOrder(charOffsets))
+ }
+ var maxe int
+ for _, offset := range charOffsets {
+ maxe = util.Max(maxe, int(offset[1]))
+ }
+
+ offsets := result.colorOffsets(charOffsets, t.theme, colBase, colMatch, current)
+ maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1)
+ ellipsis, ellipsisWidth := util.Truncate(t.ellipsis, maxWidth/2)
+ maxe = util.Constrain(maxe+util.Min(maxWidth/2-ellipsisWidth, t.hscrollOff), 0, len(text))
+ displayWidth := t.displayWidthWithLimit(text, 0, maxWidth)
+ if displayWidth > maxWidth {
+ transformOffsets := func(diff int32, rightTrim bool) {
+ for idx, offset := range offsets {
+ b, e := offset.offset[0], offset.offset[1]
+ el := int32(len(ellipsis))
+ b += el - diff
+ e += el - diff
+ b = util.Max32(b, el)
+ if rightTrim {
+ e = util.Min32(e, int32(maxWidth-ellipsisWidth))
+ }
+ offsets[idx].offset[0] = b
+ offsets[idx].offset[1] = util.Max32(b, e)
+ }
+ }
+ if t.hscroll {
+ if t.keepRight && pos == nil {
+ trimmed, diff := t.trimLeft(text, maxWidth-ellipsisWidth)
+ transformOffsets(diff, false)
+ text = append(ellipsis, trimmed...)
+ } else if !t.overflow(text[:maxe], maxWidth-ellipsisWidth) {
+ // Stri..
+ text, _ = t.trimRight(text, maxWidth-ellipsisWidth)
+ text = append(text, ellipsis...)
+ } else {
+ // Stri..
+ rightTrim := false
+ if t.overflow(text[maxe:], ellipsisWidth) {
+ text = append(text[:maxe], ellipsis...)
+ rightTrim = true
+ }
+ // ..ri..
+ var diff int32
+ text, diff = t.trimLeft(text, maxWidth-ellipsisWidth)
+
+ // Transform offsets
+ transformOffsets(diff, rightTrim)
+ text = append(ellipsis, text...)
+ }
+ } else {
+ text, _ = t.trimRight(text, maxWidth-ellipsisWidth)
+ text = append(text, ellipsis...)
+
+ for idx, offset := range offsets {
+ offsets[idx].offset[0] = util.Min32(offset.offset[0], int32(maxWidth-len(ellipsis)))
+ offsets[idx].offset[1] = util.Min32(offset.offset[1], int32(maxWidth))
+ }
+ }
+ displayWidth = t.displayWidthWithLimit(text, 0, displayWidth)
+ }
+
+ var index int32
+ var substr string
+ var prefixWidth int
+ maxOffset := int32(len(text))
+ for _, offset := range offsets {
+ b := util.Constrain32(offset.offset[0], index, maxOffset)
+ e := util.Constrain32(offset.offset[1], index, maxOffset)
+
+ substr, prefixWidth = t.processTabs(text[index:b], prefixWidth)
+ t.window.CPrint(colBase, substr)
+
+ if b < e {
+ substr, prefixWidth = t.processTabs(text[b:e], prefixWidth)
+ t.window.CPrint(offset.color, substr)
+ }
+
+ index = e
+ if index >= maxOffset {
+ break
+ }
+ }
+ if index < maxOffset {
+ substr, _ = t.processTabs(text[index:], prefixWidth)
+ t.window.CPrint(colBase, substr)
+ }
+ return displayWidth
+}
+
+func (t *Terminal) renderPreviewSpinner() {
+ numLines := len(t.previewer.lines)
+ spin := t.previewer.spinner
+ if len(spin) > 0 || t.previewer.scrollable {
+ maxWidth := t.pwindow.Width()
+ if !t.previewer.scrollable {
+ if maxWidth > 0 {
+ t.pwindow.Move(0, maxWidth-1)
+ t.pwindow.CPrint(tui.ColSpinner, spin)
+ }
+ } else {
+ offsetString := fmt.Sprintf("%d/%d", t.previewer.offset+1, numLines)
+ if len(spin) > 0 {
+ spin += " "
+ maxWidth -= 2
+ }
+ offsetRunes, _ := t.trimRight([]rune(offsetString), maxWidth)
+ pos := maxWidth - t.displayWidth(offsetRunes)
+ t.pwindow.Move(0, pos)
+ if maxWidth > 0 {
+ t.pwindow.CPrint(tui.ColSpinner, spin)
+ t.pwindow.CPrint(tui.ColInfo.WithAttr(tui.Reverse), string(offsetRunes))
+ }
+ }
+ }
+}
+
+func (t *Terminal) renderPreviewArea(unchanged bool) {
+ if unchanged {
+ t.pwindow.MoveAndClear(0, 0) // Clear scroll offset display
+ } else {
+ t.previewed.filled = false
+ t.pwindow.Erase()
+ }
+
+ height := t.pwindow.Height()
+ header := []string{}
+ body := t.previewer.lines
+ headerLines := t.previewOpts.headerLines
+ // Do not enable preview header lines if it's value is too large
+ if headerLines > 0 && headerLines < util.Min(len(body), height) {
+ header = t.previewer.lines[0:headerLines]
+ body = t.previewer.lines[headerLines:]
+ // Always redraw header
+ t.renderPreviewText(height, header, 0, false)
+ t.pwindow.MoveAndClear(t.pwindow.Y(), 0)
+ }
+ t.renderPreviewText(height, body, -t.previewer.offset+headerLines, unchanged)
+
+ if !unchanged {
+ t.pwindow.FinishFill()
+ }
+}
+
+func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unchanged bool) {
+ maxWidth := t.pwindow.Width()
+ var ansi *ansiState
+ for _, line := range lines {
+ var lbg tui.Color = -1
+ if ansi != nil {
+ ansi.lbg = -1
+ }
+ line = strings.TrimSuffix(line, "\n")
+ if lineNo >= height || t.pwindow.Y() == height-1 && t.pwindow.X() > 0 {
+ t.previewed.filled = true
+ t.previewer.scrollable = true
+ break
+ } else if lineNo >= 0 {
+ var fillRet tui.FillReturn
+ prefixWidth := 0
+ _, _, ansi = extractColor(line, ansi, func(str string, ansi *ansiState) bool {
+ trimmed := []rune(str)
+ isTrimmed := false
+ if !t.previewOpts.wrap {
+ trimmed, isTrimmed = t.trimRight(trimmed, maxWidth-t.pwindow.X())
+ }
+ str, width := t.processTabs(trimmed, prefixWidth)
+ prefixWidth += width
+ if t.theme.Colored && ansi != nil && ansi.colored() {
+ lbg = ansi.lbg
+ fillRet = t.pwindow.CFill(ansi.fg, ansi.bg, ansi.attr, str)
+ } else {
+ fillRet = t.pwindow.CFill(tui.ColPreview.Fg(), tui.ColPreview.Bg(), tui.AttrRegular, str)
+ }
+ return !isTrimmed &&
+ (fillRet == tui.FillContinue || t.previewOpts.wrap && fillRet == tui.FillNextLine)
+ })
+ t.previewer.scrollable = t.previewer.scrollable || t.pwindow.Y() == height-1 && t.pwindow.X() == t.pwindow.Width()
+ if fillRet == tui.FillNextLine {
+ continue
+ } else if fillRet == tui.FillSuspend {
+ t.previewed.filled = true
+ break
+ }
+ if unchanged && lineNo == 0 {
+ break
+ }
+ if lbg >= 0 {
+ t.pwindow.CFill(-1, lbg, tui.AttrRegular,
+ strings.Repeat(" ", t.pwindow.Width()-t.pwindow.X())+"\n")
+ } else {
+ t.pwindow.Fill("\n")
+ }
+ }
+ lineNo++
+ }
+}
+
+func (t *Terminal) printPreview() {
+ if !t.hasPreviewWindow() {
+ return
+ }
+ numLines := len(t.previewer.lines)
+ height := t.pwindow.Height()
+ unchanged := (t.previewed.filled || numLines == t.previewed.numLines) &&
+ t.previewer.version == t.previewed.version &&
+ t.previewer.offset == t.previewed.offset
+ t.previewer.scrollable = t.previewer.offset > 0 || numLines > height
+ t.renderPreviewArea(unchanged)
+ t.renderPreviewSpinner()
+ t.previewed.numLines = numLines
+ t.previewed.version = t.previewer.version
+ t.previewed.offset = t.previewer.offset
+}
+
+func (t *Terminal) printPreviewDelayed() {
+ if !t.hasPreviewWindow() || len(t.previewer.lines) > 0 && t.previewed.version == t.previewer.version {
+ return
+ }
+
+ t.previewer.scrollable = false
+ t.renderPreviewArea(true)
+
+ message := t.trimMessage("Loading ..", t.pwindow.Width())
+ pos := t.pwindow.Width() - len(message)
+ t.pwindow.Move(0, pos)
+ t.pwindow.CPrint(tui.ColInfo.WithAttr(tui.Reverse), message)
+}
+
+func (t *Terminal) processTabs(runes []rune, prefixWidth int) (string, int) {
+ var strbuf strings.Builder
+ l := prefixWidth
+ gr := uniseg.NewGraphemes(string(runes))
+ for gr.Next() {
+ rs := gr.Runes()
+ str := string(rs)
+ var w int
+ if len(rs) == 1 && rs[0] == '\t' {
+ w = t.tabstop - l%t.tabstop
+ strbuf.WriteString(strings.Repeat(" ", w))
+ } else {
+ w = runewidth.StringWidth(str)
+ strbuf.WriteString(str)
+ }
+ l += w
+ }
+ return strbuf.String(), l
+}
+
+func (t *Terminal) printAll() {
+ t.resizeWindows()
+ t.printList()
+ t.printPrompt()
+ t.printInfo()
+ t.printHeader()
+ t.printPreview()
+}
+
+func (t *Terminal) refresh() {
+ t.placeCursor()
+ if !t.suppress {
+ windows := make([]tui.Window, 0, 4)
+ if t.borderShape != tui.BorderNone {
+ windows = append(windows, t.border)
+ }
+ if t.hasPreviewWindow() {
+ if t.pborder != nil {
+ windows = append(windows, t.pborder)
+ }
+ windows = append(windows, t.pwindow)
+ }
+ windows = append(windows, t.window)
+ t.tui.RefreshWindows(windows)
+ }
+}
+
+func (t *Terminal) delChar() bool {
+ if len(t.input) > 0 && t.cx < len(t.input) {
+ t.input = append(t.input[:t.cx], t.input[t.cx+1:]...)
+ return true
+ }
+ return false
+}
+
+func findLastMatch(pattern string, str string) int {
+ rx, err := regexp.Compile(pattern)
+ if err != nil {
+ return -1
+ }
+ locs := rx.FindAllStringIndex(str, -1)
+ if locs == nil {
+ return -1
+ }
+ prefix := []rune(str[:locs[len(locs)-1][0]])
+ return len(prefix)
+}
+
+func findFirstMatch(pattern string, str string) int {
+ rx, err := regexp.Compile(pattern)
+ if err != nil {
+ return -1
+ }
+ loc := rx.FindStringIndex(str)
+ if loc == nil {
+ return -1
+ }
+ prefix := []rune(str[:loc[0]])
+ return len(prefix)
+}
+
+func copySlice(slice []rune) []rune {
+ ret := make([]rune, len(slice))
+ copy(ret, slice)
+ return ret
+}
+
+func (t *Terminal) rubout(pattern string) {
+ pcx := t.cx
+ after := t.input[t.cx:]
+ t.cx = findLastMatch(pattern, string(t.input[:t.cx])) + 1
+ t.yanked = copySlice(t.input[t.cx:pcx])
+ t.input = append(t.input[:t.cx], after...)
+}
+
+func keyMatch(key tui.Event, event tui.Event) bool {
+ return event.Type == key.Type && event.Char == key.Char ||
+ key.Type == tui.DoubleClick && event.Type == tui.Mouse && event.MouseEvent.Double
+}
+
+func parsePlaceholder(match string) (bool, string, placeholderFlags) {
+ flags := placeholderFlags{}
+
+ if match[0] == '\\' {
+ // Escaped placeholder pattern
+ return true, match[1:], flags
+ }
+
+ skipChars := 1
+ for _, char := range match[1:] {
+ switch char {
+ case '+':
+ flags.plus = true
+ skipChars++
+ case 's':
+ flags.preserveSpace = true
+ skipChars++
+ case 'n':
+ flags.number = true
+ skipChars++
+ case 'f':
+ flags.file = true
+ skipChars++
+ case 'q':
+ flags.query = true
+ // query flag is not skipped
+ default:
+ break
+ }
+ }
+
+ matchWithoutFlags := "{" + match[skipChars:]
+
+ return false, matchWithoutFlags, flags
+}
+
+func hasPreviewFlags(template string) (slot bool, plus bool, query bool) {
+ for _, match := range placeholder.FindAllString(template, -1) {
+ _, _, flags := parsePlaceholder(match)
+ if flags.plus {
+ plus = true
+ }
+ if flags.query {
+ query = true
+ }
+ slot = true
+ }
+ return
+}
+
+func writeTemporaryFile(data []string, printSep string) string {
+ f, err := ioutil.TempFile("", "fzf-preview-*")
+ if err != nil {
+ errorExit("Unable to create temporary file")
+ }
+ defer f.Close()
+
+ f.WriteString(strings.Join(data, printSep))
+ f.WriteString(printSep)
+ activeTempFiles = append(activeTempFiles, f.Name())
+ return f.Name()
+}
+
+func cleanTemporaryFiles() {
+ for _, filename := range activeTempFiles {
+ os.Remove(filename)
+ }
+ activeTempFiles = []string{}
+}
+
+func (t *Terminal) replacePlaceholder(template string, forcePlus bool, input string, list []*Item) string {
+ return replacePlaceholder(
+ template, t.ansi, t.delimiter, t.printsep, forcePlus, input, list)
+}
+
+func (t *Terminal) evaluateScrollOffset() int {
+ if t.pwindow == nil {
+ return 0
+ }
+
+ // We only need the current item to calculate the scroll offset
+ offsetExpr := offsetTrimCharsRegex.ReplaceAllString(
+ t.replacePlaceholder(t.previewOpts.scroll, false, "", []*Item{t.currentItem(), nil}), "")
+
+ atoi := func(s string) int {
+ n, e := strconv.Atoi(s)
+ if e != nil {
+ return 0
+ }
+ return n
+ }
+
+ base := -1
+ height := util.Max(0, t.pwindow.Height()-t.previewOpts.headerLines)
+ for _, component := range offsetComponentRegex.FindAllString(offsetExpr, -1) {
+ if strings.HasPrefix(component, "-/") {
+ component = component[1:]
+ }
+ if component[0] == '/' {
+ denom := atoi(component[1:])
+ if denom != 0 {
+ base -= height / denom
+ }
+ break
+ }
+ base += atoi(component)
+ }
+ return util.Max(0, base)
+}
+
+func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, printsep string, forcePlus bool, query string, allItems []*Item) string {
+ current := allItems[:1]
+ selected := allItems[1:]
+ if current[0] == nil {
+ current = []*Item{}
+ }
+ if selected[0] == nil {
+ selected = []*Item{}
+ }
+
+ // replace placeholders one by one
+ return placeholder.ReplaceAllStringFunc(template, func(match string) string {
+ escaped, match, flags := parsePlaceholder(match)
+
+ // this function implements the effects a placeholder has on items
+ var replace func(*Item) string
+
+ // placeholder types (escaped, query type, item type, token type)
+ switch {
+ case escaped:
+ return match
+ case match == "{q}":
+ return quoteEntry(query)
+ case match == "{}":
+ replace = func(item *Item) string {
+ switch {
+ case flags.number:
+ n := int(item.text.Index)
+ if n < 0 {
+ return ""
+ }
+ return strconv.Itoa(n)
+ case flags.file:
+ return item.AsString(stripAnsi)
+ default:
+ return quoteEntry(item.AsString(stripAnsi))
+ }
+ }
+ default:
+ // token type and also failover (below)
+ rangeExpressions := strings.Split(match[1:len(match)-1], ",")
+ ranges := make([]Range, len(rangeExpressions))
+ for idx, s := range rangeExpressions {
+ r, ok := ParseRange(&s) // ellipsis (x..y) and shorthand (x..x) range syntax
+ if !ok {
+ // Invalid expression, just return the original string in the template
+ return match
+ }
+ ranges[idx] = r
+ }
+
+ replace = func(item *Item) string {
+ tokens := Tokenize(item.AsString(stripAnsi), delimiter)
+ trans := Transform(tokens, ranges)
+ str := joinTokens(trans)
+
+ // trim the last delimiter
+ if delimiter.str != nil {
+ str = strings.TrimSuffix(str, *delimiter.str)
+ } else if delimiter.regex != nil {
+ delims := delimiter.regex.FindAllStringIndex(str, -1)
+ // make sure the delimiter is at the very end of the string
+ if len(delims) > 0 && delims[len(delims)-1][1] == len(str) {
+ str = str[:delims[len(delims)-1][0]]
+ }
+ }
+
+ if !flags.preserveSpace {
+ str = strings.TrimSpace(str)
+ }
+ if !flags.file {
+ str = quoteEntry(str)
+ }
+ return str
+ }
+ }
+
+ // apply 'replace' function over proper set of items and return result
+
+ items := current
+ if flags.plus || forcePlus {
+ items = selected
+ }
+ replacements := make([]string, len(items))
+
+ for idx, item := range items {
+ replacements[idx] = replace(item)
+ }
+
+ if flags.file {
+ return writeTemporaryFile(replacements, printsep)
+ }
+ return strings.Join(replacements, " ")
+ })
+}
+
+func (t *Terminal) redraw(clear bool) {
+ if clear {
+ t.tui.Clear()
+ }
+ t.tui.Refresh()
+ t.printAll()
+}
+
+func (t *Terminal) executeCommand(template string, forcePlus bool, background bool) {
+ valid, list := t.buildPlusList(template, forcePlus)
+ if !valid {
+ return
+ }
+ command := t.replacePlaceholder(template, forcePlus, string(t.input), list)
+ cmd := util.ExecCommand(command, false)
+ t.executing.Set(true)
+ if !background {
+ cmd.Stdin = tui.TtyIn()
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ t.tui.Pause(true)
+ cmd.Run()
+ t.tui.Resume(true, false)
+ t.redraw(true)
+ t.refresh()
+ } else {
+ t.tui.Pause(false)
+ cmd.Run()
+ t.tui.Resume(false, false)
+ }
+ t.executing.Set(false)
+ cleanTemporaryFiles()
+}
+
+func (t *Terminal) hasPreviewer() bool {
+ return t.previewBox != nil
+}
+
+func (t *Terminal) isPreviewEnabled() bool {
+ return t.hasPreviewer() && t.previewer.enabled
+}
+
+func (t *Terminal) hasPreviewWindow() bool {
+ return t.pwindow != nil && t.isPreviewEnabled()
+}
+
+func (t *Terminal) currentItem() *Item {
+ cnt := t.merger.Length()
+ if t.cy >= 0 && cnt > 0 && cnt > t.cy {
+ return t.merger.Get(t.cy).item
+ }
+ return nil
+}
+
+func (t *Terminal) buildPlusList(template string, forcePlus bool) (bool, []*Item) {
+ current := t.currentItem()
+ slot, plus, query := hasPreviewFlags(template)
+ if !(!slot || query && len(t.input) > 0 || (forcePlus || plus) && len(t.selected) > 0) {
+ return current != nil, []*Item{current, current}
+ }
+
+ // We would still want to update preview window even if there is no match if
+ // 1. command template contains {q} and the query string is not empty
+ // 2. or it contains {+} and we have more than one item already selected.
+ // To do so, we pass an empty Item instead of nil to trigger an update.
+ if current == nil {
+ current = &minItem
+ }
+
+ var sels []*Item
+ if len(t.selected) == 0 {
+ sels = []*Item{current, current}
+ } else {
+ sels = make([]*Item, len(t.selected)+1)
+ sels[0] = current
+ for i, sel := range t.sortSelected() {
+ sels[i+1] = sel.item
+ }
+ }
+ return true, sels
+}
+
+func (t *Terminal) selectItem(item *Item) bool {
+ if len(t.selected) >= t.multi {
+ return false
+ }
+ if _, found := t.selected[item.Index()]; found {
+ return true
+ }
+
+ t.selected[item.Index()] = selectedItem{time.Now(), item}
+ t.version++
+
+ return true
+}
+
+func (t *Terminal) selectItemChanged(item *Item) bool {
+ if _, found := t.selected[item.Index()]; found {
+ return false
+ }
+ return t.selectItem(item)
+}
+
+func (t *Terminal) deselectItem(item *Item) {
+ delete(t.selected, item.Index())
+ t.version++
+}
+
+func (t *Terminal) deselectItemChanged(item *Item) bool {
+ if _, found := t.selected[item.Index()]; found {
+ t.deselectItem(item)
+ return true
+ }
+ return false
+}
+
+func (t *Terminal) toggleItem(item *Item) bool {
+ if _, found := t.selected[item.Index()]; !found {
+ return t.selectItem(item)
+ }
+ t.deselectItem(item)
+ return true
+}
+
+func (t *Terminal) killPreview(code int) {
+ select {
+ case t.killChan <- code:
+ default:
+ if code != exitCancel {
+ t.eventBox.Set(EvtQuit, code)
+ }
+ }
+}
+
+func (t *Terminal) cancelPreview() {
+ t.killPreview(exitCancel)
+}
+
+// Loop is called to start Terminal I/O
+func (t *Terminal) Loop() {
+ // prof := profile.Start(profile.ProfilePath("/tmp/"))
+ <-t.startChan
+ { // Late initialization
+ intChan := make(chan os.Signal, 1)
+ signal.Notify(intChan, os.Interrupt, syscall.SIGTERM)
+ go func() {
+ for s := range intChan {
+ // Don't quit by SIGINT while executing because it should be for the executing command and not for fzf itself
+ if !(s == os.Interrupt && t.executing.Get()) {
+ t.reqBox.Set(reqQuit, nil)
+ }
+ }
+ }()
+
+ contChan := make(chan os.Signal, 1)
+ notifyOnCont(contChan)
+ go func() {
+ for {
+ <-contChan
+ t.reqBox.Set(reqReinit, nil)
+ }
+ }()
+
+ resizeChan := make(chan os.Signal, 1)
+ notifyOnResize(resizeChan) // Non-portable
+ go func() {
+ for {
+ <-resizeChan
+ t.reqBox.Set(reqFullRedraw, nil)
+ }
+ }()
+
+ t.mutex.Lock()
+ t.initFunc()
+ t.resizeWindows()
+ t.printPrompt()
+ t.printInfo()
+ t.printHeader()
+ t.refresh()
+ t.mutex.Unlock()
+ go func() {
+ timer := time.NewTimer(t.initDelay)
+ <-timer.C
+ t.reqBox.Set(reqRefresh, nil)
+ }()
+
+ // Keep the spinner spinning
+ go func() {
+ for {
+ t.mutex.Lock()
+ reading := t.reading
+ t.mutex.Unlock()
+ time.Sleep(spinnerDuration)
+ if reading {
+ t.reqBox.Set(reqInfo, nil)
+ }
+ }
+ }()
+ }
+
+ if t.hasPreviewer() {
+ go func() {
+ var version int64
+ for {
+ var items []*Item
+ var commandTemplate string
+ var pwindow tui.Window
+ initialOffset := 0
+ t.previewBox.Wait(func(events *util.Events) {
+ for req, value := range *events {
+ switch req {
+ case reqPreviewEnqueue:
+ request := value.(previewRequest)
+ commandTemplate = request.template
+ initialOffset = request.scrollOffset
+ items = request.list
+ pwindow = request.pwindow
+ }
+ }
+ events.Clear()
+ })
+ version++
+ // We don't display preview window if no match
+ if items[0] != nil {
+ _, query := t.Input()
+ command := t.replacePlaceholder(commandTemplate, false, string(query), items)
+ cmd := util.ExecCommand(command, true)
+ if pwindow != nil {
+ height := pwindow.Height()
+ env := os.Environ()
+ lines := fmt.Sprintf("LINES=%d", height)
+ columns := fmt.Sprintf("COLUMNS=%d", pwindow.Width())
+ env = append(env, lines)
+ env = append(env, "FZF_PREVIEW_"+lines)
+ env = append(env, columns)
+ env = append(env, "FZF_PREVIEW_"+columns)
+ cmd.Env = env
+ }
+
+ out, _ := cmd.StdoutPipe()
+ cmd.Stderr = cmd.Stdout
+ reader := bufio.NewReader(out)
+ eofChan := make(chan bool)
+ finishChan := make(chan bool, 1)
+ err := cmd.Start()
+ if err == nil {
+ reapChan := make(chan bool)
+ lineChan := make(chan eachLine)
+ // Goroutine 1 reads process output
+ go func() {
+ for {
+ line, err := reader.ReadString('\n')
+ lineChan <- eachLine{line, err}
+ if err != nil {
+ break
+ }
+ }
+ eofChan <- true
+ }()
+
+ // Goroutine 2 periodically requests rendering
+ rendered := util.NewAtomicBool(false)
+ go func(version int64) {
+ lines := []string{}
+ spinner := makeSpinner(t.unicode)
+ spinnerIndex := -1 // Delay initial rendering by an extra tick
+ ticker := time.NewTicker(previewChunkDelay)
+ offset := initialOffset
+ Loop:
+ for {
+ select {
+ case <-ticker.C:
+ if len(lines) > 0 && len(lines) >= initialOffset {
+ if spinnerIndex >= 0 {
+ spin := spinner[spinnerIndex%len(spinner)]
+ t.reqBox.Set(reqPreviewDisplay, previewResult{version, lines, offset, spin})
+ rendered.Set(true)
+ offset = -1
+ }
+ spinnerIndex++
+ }
+ case eachLine := <-lineChan:
+ line := eachLine.line
+ err := eachLine.err
+ if len(line) > 0 {
+ clearIndex := strings.Index(line, clearCode)
+ if clearIndex >= 0 {
+ lines = []string{}
+ line = line[clearIndex+len(clearCode):]
+ version--
+ offset = 0
+ }
+ lines = append(lines, line)
+ }
+ if err != nil {
+ t.reqBox.Set(reqPreviewDisplay, previewResult{version, lines, offset, ""})
+ rendered.Set(true)
+ break Loop
+ }
+ }
+ }
+ ticker.Stop()
+ reapChan <- true
+ }(version)
+
+ // Goroutine 3 is responsible for cancelling running preview command
+ go func(version int64) {
+ timer := time.NewTimer(previewDelayed)
+ Loop:
+ for {
+ select {
+ case <-timer.C:
+ t.reqBox.Set(reqPreviewDelayed, version)
+ case code := <-t.killChan:
+ if code != exitCancel {
+ util.KillCommand(cmd)
+ t.eventBox.Set(EvtQuit, code)
+ } else {
+ // We can immediately kill a long-running preview program
+ // once we started rendering its partial output
+ delay := previewCancelWait
+ if rendered.Get() {
+ delay = 0
+ }
+ timer := time.NewTimer(delay)
+ select {
+ case <-timer.C:
+ util.KillCommand(cmd)
+ case <-finishChan:
+ }
+ timer.Stop()
+ }
+ break Loop
+ case <-finishChan:
+ break Loop
+ }
+ }
+ timer.Stop()
+ reapChan <- true
+ }(version)
+
+ <-eofChan // Goroutine 1 finished
+ cmd.Wait() // NOTE: We should not call Wait before EOF
+ finishChan <- true // Tell Goroutine 3 to stop
+ <-reapChan // Goroutine 2 and 3 finished
+ <-reapChan
+ } else {
+ // Failed to start the command. Report the error immediately.
+ t.reqBox.Set(reqPreviewDisplay, previewResult{version, []string{err.Error()}, 0, ""})
+ }
+
+ cleanTemporaryFiles()
+ } else {
+ t.reqBox.Set(reqPreviewDisplay, previewResult{version, nil, 0, ""})
+ }
+ }
+ }()
+ }
+
+ refreshPreview := func(command string) {
+ if len(command) > 0 && t.isPreviewEnabled() {
+ _, list := t.buildPlusList(command, false)
+ t.cancelPreview()
+ t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.pwindow, t.evaluateScrollOffset(), list})
+ }
+ }
+
+ go func() {
+ var focusedIndex int32 = minItem.Index()
+ var version int64 = -1
+ running := true
+ code := exitError
+ exit := func(getCode func() int) {
+ t.tui.Close()
+ code = getCode()
+ if code <= exitNoMatch && t.history != nil {
+ t.history.append(string(t.input))
+ }
+ running = false
+ t.mutex.Unlock()
+ }
+
+ for running {
+ t.reqBox.Wait(func(events *util.Events) {
+ defer events.Clear()
+ t.mutex.Lock()
+ for req, value := range *events {
+ switch req {
+ case reqPrompt:
+ t.printPrompt()
+ if t.noInfoLine() {
+ t.printInfo()
+ }
+ case reqInfo:
+ t.printInfo()
+ case reqList:
+ t.printList()
+ var currentIndex int32 = minItem.Index()
+ currentItem := t.currentItem()
+ if currentItem != nil {
+ currentIndex = currentItem.Index()
+ }
+ if focusedIndex != currentIndex || version != t.version {
+ version = t.version
+ focusedIndex = currentIndex
+ refreshPreview(t.previewOpts.command)
+ }
+ case reqJump:
+ if t.merger.Length() == 0 {
+ t.jumping = jumpDisabled
+ }
+ t.printList()
+ case reqHeader:
+ t.printHeader()
+ case reqRefresh:
+ t.suppress = false
+ case reqReinit:
+ t.tui.Resume(t.fullscreen, t.sigstop)
+ t.redraw(true)
+ case reqRedraw:
+ t.redraw(false)
+ case reqFullRedraw:
+ t.redraw(true)
+ case reqClose:
+ exit(func() int {
+ if t.output() {
+ return exitOk
+ }
+ return exitNoMatch
+ })
+ return
+ case reqPreviewDisplay:
+ result := value.(previewResult)
+ if t.previewer.version != result.version {
+ t.previewer.version = result.version
+ t.previewer.following = t.previewOpts.follow
+ }
+ t.previewer.lines = result.lines
+ t.previewer.spinner = result.spinner
+ if t.previewer.following {
+ t.previewer.offset = len(t.previewer.lines) - t.pwindow.Height()
+ } else if result.offset >= 0 {
+ t.previewer.offset = util.Constrain(result.offset, t.previewOpts.headerLines, len(t.previewer.lines)-1)
+ }
+ t.printPreview()
+ case reqPreviewRefresh:
+ t.printPreview()
+ case reqPreviewDelayed:
+ t.previewer.version = value.(int64)
+ t.printPreviewDelayed()
+ case reqPrintQuery:
+ exit(func() int {
+ t.printer(string(t.input))
+ return exitOk
+ })
+ return
+ case reqQuit:
+ exit(func() int { return exitInterrupt })
+ return
+ }
+ }
+ t.refresh()
+ t.mutex.Unlock()
+ })
+ }
+ // prof.Stop()
+ t.killPreview(code)
+ }()
+
+ looping := true
+ for looping {
+ var newCommand *string
+ changed := false
+ beof := false
+ queryChanged := false
+
+ event := t.tui.GetChar()
+
+ t.mutex.Lock()
+ previousInput := t.input
+ previousCx := t.cx
+ events := []util.EventType{}
+ req := func(evts ...util.EventType) {
+ for _, event := range evts {
+ events = append(events, event)
+ if event == reqClose || event == reqQuit {
+ looping = false
+ }
+ }
+ }
+ togglePreview := func(enabled bool) bool {
+ if t.previewer.enabled != enabled {
+ t.previewer.enabled = enabled
+ // We need to immediately update t.pwindow so we don't use reqRedraw
+ t.resizeWindows()
+ req(reqPrompt, reqList, reqInfo, reqHeader)
+ return true
+ }
+ return false
+ }
+ toggle := func() bool {
+ current := t.currentItem()
+ if current != nil && t.toggleItem(current) {
+ req(reqInfo)
+ return true
+ }
+ return false
+ }
+ scrollPreviewTo := func(newOffset int) {
+ if !t.previewer.scrollable {
+ return
+ }
+ t.previewer.following = false
+ numLines := len(t.previewer.lines)
+ if t.previewOpts.cycle {
+ newOffset = (newOffset + numLines) % numLines
+ }
+ newOffset = util.Constrain(newOffset, t.previewOpts.headerLines, numLines-1)
+ if t.previewer.offset != newOffset {
+ t.previewer.offset = newOffset
+ req(reqPreviewRefresh)
+ }
+ }
+ scrollPreviewBy := func(amount int) {
+ scrollPreviewTo(t.previewer.offset + amount)
+ }
+ for key, ret := range t.expect {
+ if keyMatch(key, event) {
+ t.pressed = ret
+ t.reqBox.Set(reqClose, nil)
+ t.mutex.Unlock()
+ return
+ }
+ }
+
+ actionsFor := func(eventType tui.EventType) []*action {
+ return t.keymap[eventType.AsEvent()]
+ }
+
+ var doAction func(*action) bool
+ doActions := func(actions []*action) bool {
+ for _, action := range actions {
+ if !doAction(action) {
+ return false
+ }
+ }
+ return true
+ }
+ doAction = func(a *action) bool {
+ switch a.t {
+ case actIgnore:
+ case actExecute, actExecuteSilent:
+ t.executeCommand(a.a, false, a.t == actExecuteSilent)
+ case actExecuteMulti:
+ t.executeCommand(a.a, true, false)
+ case actInvalid:
+ t.mutex.Unlock()
+ return false
+ case actTogglePreview:
+ if t.hasPreviewer() {
+ togglePreview(!t.previewer.enabled)
+ if t.previewer.enabled {
+ valid, list := t.buildPlusList(t.previewOpts.command, false)
+ if valid {
+ t.cancelPreview()
+ t.previewBox.Set(reqPreviewEnqueue,
+ previewRequest{t.previewOpts.command, t.pwindow, t.evaluateScrollOffset(), list})
+ }
+ }
+ }
+ case actTogglePreviewWrap:
+ if t.hasPreviewWindow() {
+ t.previewOpts.wrap = !t.previewOpts.wrap
+ // Reset preview version so that full redraw occurs
+ t.previewed.version = 0
+ req(reqPreviewRefresh)
+ }
+ case actToggleSort:
+ t.sort = !t.sort
+ changed = true
+ case actPreviewTop:
+ if t.hasPreviewWindow() {
+ scrollPreviewTo(0)
+ }
+ case actPreviewBottom:
+ if t.hasPreviewWindow() {
+ scrollPreviewTo(len(t.previewer.lines) - t.pwindow.Height())
+ }
+ case actPreviewUp:
+ if t.hasPreviewWindow() {
+ scrollPreviewBy(-1)
+ }
+ case actPreviewDown:
+ if t.hasPreviewWindow() {
+ scrollPreviewBy(1)
+ }
+ case actPreviewPageUp:
+ if t.hasPreviewWindow() {
+ scrollPreviewBy(-t.pwindow.Height())
+ }
+ case actPreviewPageDown:
+ if t.hasPreviewWindow() {
+ scrollPreviewBy(t.pwindow.Height())
+ }
+ case actPreviewHalfPageUp:
+ if t.hasPreviewWindow() {
+ scrollPreviewBy(-t.pwindow.Height() / 2)
+ }
+ case actPreviewHalfPageDown:
+ if t.hasPreviewWindow() {
+ scrollPreviewBy(t.pwindow.Height() / 2)
+ }
+ case actBeginningOfLine:
+ t.cx = 0
+ case actBackwardChar:
+ if t.cx > 0 {
+ t.cx--
+ }
+ case actPrintQuery:
+ req(reqPrintQuery)
+ case actChangePrompt:
+ t.prompt, t.promptLen = t.parsePrompt(a.a)
+ req(reqPrompt)
+ case actPreview:
+ togglePreview(true)
+ refreshPreview(a.a)
+ case actRefreshPreview:
+ refreshPreview(t.previewOpts.command)
+ case actReplaceQuery:
+ current := t.currentItem()
+ if current != nil {
+ t.input = current.text.ToRunes()
+ t.cx = len(t.input)
+ }
+ case actAbort:
+ req(reqQuit)
+ case actDeleteChar:
+ t.delChar()
+ case actDeleteCharEOF:
+ if !t.delChar() && t.cx == 0 {
+ req(reqQuit)
+ }
+ case actEndOfLine:
+ t.cx = len(t.input)
+ case actCancel:
+ if len(t.input) == 0 {
+ req(reqQuit)
+ } else {
+ t.yanked = t.input
+ t.input = []rune{}
+ t.cx = 0
+ }
+ case actBackwardDeleteCharEOF:
+ if len(t.input) == 0 {
+ req(reqQuit)
+ } else if t.cx > 0 {
+ t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
+ t.cx--
+ }
+ case actForwardChar:
+ if t.cx < len(t.input) {
+ t.cx++
+ }
+ case actBackwardDeleteChar:
+ beof = len(t.input) == 0
+ if t.cx > 0 {
+ t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
+ t.cx--
+ }
+ case actSelectAll:
+ if t.multi > 0 {
+ for i := 0; i < t.merger.Length(); i++ {
+ if !t.selectItem(t.merger.Get(i).item) {
+ break
+ }
+ }
+ req(reqList, reqInfo)
+ }
+ case actDeselectAll:
+ if t.multi > 0 {
+ for i := 0; i < t.merger.Length() && len(t.selected) > 0; i++ {
+ t.deselectItem(t.merger.Get(i).item)
+ }
+ req(reqList, reqInfo)
+ }
+ case actClose:
+ if t.isPreviewEnabled() {
+ togglePreview(false)
+ } else {
+ req(reqQuit)
+ }
+ case actSelect:
+ current := t.currentItem()
+ if t.multi > 0 && current != nil && t.selectItemChanged(current) {
+ req(reqList, reqInfo)
+ }
+ case actDeselect:
+ current := t.currentItem()
+ if t.multi > 0 && current != nil && t.deselectItemChanged(current) {
+ req(reqList, reqInfo)
+ }
+ case actToggle:
+ if t.multi > 0 && t.merger.Length() > 0 && toggle() {
+ req(reqList)
+ }
+ case actToggleAll:
+ if t.multi > 0 {
+ prevIndexes := make(map[int]struct{})
+ for i := 0; i < t.merger.Length() && len(t.selected) > 0; i++ {
+ item := t.merger.Get(i).item
+ if _, found := t.selected[item.Index()]; found {
+ prevIndexes[i] = struct{}{}
+ t.deselectItem(item)
+ }
+ }
+
+ for i := 0; i < t.merger.Length(); i++ {
+ if _, found := prevIndexes[i]; !found {
+ item := t.merger.Get(i).item
+ if !t.selectItem(item) {
+ break
+ }
+ }
+ }
+ req(reqList, reqInfo)
+ }
+ case actToggleIn:
+ if t.layout != layoutDefault {
+ return doAction(&action{t: actToggleUp})
+ }
+ return doAction(&action{t: actToggleDown})
+ case actToggleOut:
+ if t.layout != layoutDefault {
+ return doAction(&action{t: actToggleDown})
+ }
+ return doAction(&action{t: actToggleUp})
+ case actToggleDown:
+ if t.multi > 0 && t.merger.Length() > 0 && toggle() {
+ t.vmove(-1, true)
+ req(reqList)
+ }
+ case actToggleUp:
+ if t.multi > 0 && t.merger.Length() > 0 && toggle() {
+ t.vmove(1, true)
+ req(reqList)
+ }
+ case actDown:
+ t.vmove(-1, true)
+ req(reqList)
+ case actUp:
+ t.vmove(1, true)
+ req(reqList)
+ case actAccept:
+ req(reqClose)
+ case actAcceptNonEmpty:
+ if len(t.selected) > 0 || t.merger.Length() > 0 || !t.reading && t.count == 0 {
+ req(reqClose)
+ }
+ case actClearScreen:
+ req(reqFullRedraw)
+ case actClearQuery:
+ t.input = []rune{}
+ t.cx = 0
+ case actClearSelection:
+ if t.multi > 0 {
+ t.selected = make(map[int32]selectedItem)
+ t.version++
+ req(reqList, reqInfo)
+ }
+ case actFirst:
+ t.vset(0)
+ req(reqList)
+ case actLast:
+ t.vset(t.merger.Length() - 1)
+ req(reqList)
+ case actUnixLineDiscard:
+ beof = len(t.input) == 0
+ if t.cx > 0 {
+ t.yanked = copySlice(t.input[:t.cx])
+ t.input = t.input[t.cx:]
+ t.cx = 0
+ }
+ case actUnixWordRubout:
+ beof = len(t.input) == 0
+ if t.cx > 0 {
+ t.rubout("\\s\\S")
+ }
+ case actBackwardKillWord:
+ beof = len(t.input) == 0
+ if t.cx > 0 {
+ t.rubout(t.wordRubout)
+ }
+ case actYank:
+ suffix := copySlice(t.input[t.cx:])
+ t.input = append(append(t.input[:t.cx], t.yanked...), suffix...)
+ t.cx += len(t.yanked)
+ case actPageUp:
+ t.vmove(t.maxItems()-1, false)
+ req(reqList)
+ case actPageDown:
+ t.vmove(-(t.maxItems() - 1), false)
+ req(reqList)
+ case actHalfPageUp:
+ t.vmove(t.maxItems()/2, false)
+ req(reqList)
+ case actHalfPageDown:
+ t.vmove(-(t.maxItems() / 2), false)
+ req(reqList)
+ case actJump:
+ t.jumping = jumpEnabled
+ req(reqJump)
+ case actJumpAccept:
+ t.jumping = jumpAcceptEnabled
+ req(reqJump)
+ case actBackwardWord:
+ t.cx = findLastMatch(t.wordRubout, string(t.input[:t.cx])) + 1
+ case actForwardWord:
+ t.cx += findFirstMatch(t.wordNext, string(t.input[t.cx:])) + 1
+ case actKillWord:
+ ncx := t.cx +
+ findFirstMatch(t.wordNext, string(t.input[t.cx:])) + 1
+ if ncx > t.cx {
+ t.yanked = copySlice(t.input[t.cx:ncx])
+ t.input = append(t.input[:t.cx], t.input[ncx:]...)
+ }
+ case actKillLine:
+ if t.cx < len(t.input) {
+ t.yanked = copySlice(t.input[t.cx:])
+ t.input = t.input[:t.cx]
+ }
+ case actRune:
+ prefix := copySlice(t.input[:t.cx])
+ t.input = append(append(prefix, event.Char), t.input[t.cx:]...)
+ t.cx++
+ case actPreviousHistory:
+ if t.history != nil {
+ t.history.override(string(t.input))
+ t.input = trimQuery(t.history.previous())
+ t.cx = len(t.input)
+ }
+ case actNextHistory:
+ if t.history != nil {
+ t.history.override(string(t.input))
+ t.input = trimQuery(t.history.next())
+ t.cx = len(t.input)
+ }
+ case actToggleSearch:
+ t.paused = !t.paused
+ changed = !t.paused
+ req(reqPrompt)
+ case actEnableSearch:
+ t.paused = false
+ changed = true
+ req(reqPrompt)
+ case actDisableSearch:
+ t.paused = true
+ req(reqPrompt)
+ case actSigStop:
+ p, err := os.FindProcess(os.Getpid())
+ if err == nil {
+ t.sigstop = true
+ t.tui.Clear()
+ t.tui.Pause(t.fullscreen)
+ notifyStop(p)
+ t.mutex.Unlock()
+ return false
+ }
+ case actMouse:
+ me := event.MouseEvent
+ mx, my := me.X, me.Y
+ if me.S != 0 {
+ // Scroll
+ if t.window.Enclose(my, mx) && t.merger.Length() > 0 {
+ if t.multi > 0 && me.Mod {
+ toggle()
+ }
+ t.vmove(me.S, true)
+ req(reqList)
+ } else if t.hasPreviewWindow() && t.pwindow.Enclose(my, mx) {
+ scrollPreviewBy(-me.S)
+ }
+ } else if t.window.Enclose(my, mx) {
+ mx -= t.window.Left()
+ my -= t.window.Top()
+ mx = util.Constrain(mx-t.promptLen, 0, len(t.input))
+ min := 2 + len(t.header)
+ if t.noInfoLine() {
+ min--
+ }
+ h := t.window.Height()
+ switch t.layout {
+ case layoutDefault:
+ my = h - my - 1
+ case layoutReverseList:
+ if my < h-min {
+ my += min
+ } else {
+ my = h - my - 1
+ }
+ }
+ if me.Double {
+ // Double-click
+ if my >= min {
+ if t.vset(t.offset+my-min) && t.cy < t.merger.Length() {
+ return doActions(actionsFor(tui.DoubleClick))
+ }
+ }
+ } else if me.Down {
+ if my == t.promptLine() && mx >= 0 {
+ // Prompt
+ t.cx = mx + t.xoffset
+ } else if my >= min {
+ // List
+ if t.vset(t.offset+my-min) && t.multi > 0 && me.Mod {
+ toggle()
+ }
+ req(reqList)
+ if me.Left {
+ return doActions(actionsFor(tui.LeftClick))
+ }
+ return doActions(actionsFor(tui.RightClick))
+ }
+ }
+ }
+ case actReload:
+ t.failed = nil
+
+ valid, list := t.buildPlusList(a.a, false)
+ if !valid {
+ // We run the command even when there's no match
+ // 1. If the template doesn't have any slots
+ // 2. If the template has {q}
+ slot, _, query := hasPreviewFlags(a.a)
+ valid = !slot || query
+ }
+ if valid {
+ command := t.replacePlaceholder(a.a, false, string(t.input), list)
+ newCommand = &command
+ t.reading = true
+ }
+ case actUnbind:
+ keys := parseKeyChords(a.a, "PANIC")
+ for key := range keys {
+ delete(t.keymap, key)
+ }
+ case actRebind:
+ keys := parseKeyChords(a.a, "PANIC")
+ for key := range keys {
+ if originalAction, found := t.keymapOrg[key]; found {
+ t.keymap[key] = originalAction
+ }
+ }
+ case actChangePreview:
+ if t.previewOpts.command != a.a {
+ togglePreview(len(a.a) > 0)
+ t.previewOpts.command = a.a
+ refreshPreview(t.previewOpts.command)
+ }
+ case actChangePreviewWindow:
+ currentPreviewOpts := t.previewOpts
+
+ // Reset preview options and apply the additional options
+ t.previewOpts = t.initialPreviewOpts
+
+ // Split window options
+ tokens := strings.Split(a.a, "|")
+ parsePreviewWindow(&t.previewOpts, tokens[0])
+ if len(tokens) > 1 {
+ a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
+ }
+
+ if t.previewOpts.hidden {
+ togglePreview(false)
+ } else {
+ // Full redraw
+ if !currentPreviewOpts.sameLayout(t.previewOpts) {
+ if togglePreview(true) {
+ refreshPreview(t.previewOpts.command)
+ } else {
+ req(reqRedraw)
+ }
+ } else if !currentPreviewOpts.sameContentLayout(t.previewOpts) {
+ t.previewed.version = 0
+ req(reqPreviewRefresh)
+ }
+
+ // Adjust scroll offset
+ if t.hasPreviewWindow() && currentPreviewOpts.scroll != t.previewOpts.scroll {
+ scrollPreviewTo(t.evaluateScrollOffset())
+ }
+ }
+ }
+ return true
+ }
+
+ if t.jumping == jumpDisabled {
+ actions := t.keymap[event.Comparable()]
+ if len(actions) == 0 && event.Type == tui.Rune {
+ doAction(&action{t: actRune})
+ } else if !doActions(actions) {
+ continue
+ }
+ t.truncateQuery()
+ queryChanged = string(previousInput) != string(t.input)
+ changed = changed || queryChanged
+ if onChanges, prs := t.keymap[tui.Change.AsEvent()]; queryChanged && prs {
+ if !doActions(onChanges) {
+ continue
+ }
+ }
+ if onEOFs, prs := t.keymap[tui.BackwardEOF.AsEvent()]; beof && prs {
+ if !doActions(onEOFs) {
+ continue
+ }
+ }
+ } else {
+ if event.Type == tui.Rune {
+ if idx := strings.IndexRune(t.jumpLabels, event.Char); idx >= 0 && idx < t.maxItems() && idx < t.merger.Length() {
+ t.cy = idx + t.offset
+ if t.jumping == jumpAcceptEnabled {
+ req(reqClose)
+ }
+ }
+ }
+ t.jumping = jumpDisabled
+ req(reqList)
+ }
+
+ if queryChanged {
+ if t.isPreviewEnabled() {
+ _, _, q := hasPreviewFlags(t.previewOpts.command)
+ if q {
+ t.version++
+ }
+ }
+ }
+
+ if queryChanged || t.cx != previousCx {
+ req(reqPrompt)
+ }
+
+ t.mutex.Unlock() // Must be unlocked before touching reqBox
+
+ if changed || newCommand != nil {
+ t.eventBox.Set(EvtSearchNew, searchRequest{sort: t.sort, command: newCommand})
+ }
+ for _, event := range events {
+ t.reqBox.Set(event, nil)
+ }
+ }
+}
+
+func (t *Terminal) constrain() {
+ // count of items to display allowed by filtering
+ count := t.merger.Length()
+ // count of lines can be displayed
+ height := t.maxItems()
+
+ t.cy = util.Constrain(t.cy, 0, count-1)
+
+ minOffset := util.Max(t.cy-height+1, 0)
+ maxOffset := util.Max(util.Min(count-height, t.cy), 0)
+ t.offset = util.Constrain(t.offset, minOffset, maxOffset)
+ if t.scrollOff == 0 {
+ return
+ }
+
+ scrollOff := util.Min(height/2, t.scrollOff)
+ for {
+ prevOffset := t.offset
+ if t.cy-t.offset < scrollOff {
+ t.offset = util.Max(minOffset, t.offset-1)
+ }
+ if t.cy-t.offset >= height-scrollOff {
+ t.offset = util.Min(maxOffset, t.offset+1)
+ }
+ if t.offset == prevOffset {
+ break
+ }
+ }
+}
+
+func (t *Terminal) vmove(o int, allowCycle bool) {
+ if t.layout != layoutDefault {
+ o *= -1
+ }
+ dest := t.cy + o
+ if t.cycle && allowCycle {
+ max := t.merger.Length() - 1
+ if dest > max {
+ if t.cy == max {
+ dest = 0
+ }
+ } else if dest < 0 {
+ if t.cy == 0 {
+ dest = max
+ }
+ }
+ }
+ t.vset(dest)
+}
+
+func (t *Terminal) vset(o int) bool {
+ t.cy = util.Constrain(o, 0, t.merger.Length()-1)
+ return t.cy == o
+}
+
+func (t *Terminal) maxItems() int {
+ max := t.window.Height() - 2 - len(t.header)
+ if t.noInfoLine() {
+ max++
+ }
+ return util.Max(max, 0)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/terminal_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/terminal_test.go
new file mode 100644
index 00000000..ebb6bda5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/terminal_test.go
@@ -0,0 +1,638 @@
+package fzf
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "regexp"
+ "strings"
+ "testing"
+ "text/template"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+func TestReplacePlaceholder(t *testing.T) {
+ item1 := newItem(" foo'bar \x1b[31mbaz\x1b[m")
+ items1 := []*Item{item1, item1}
+ items2 := []*Item{
+ newItem("foo'bar \x1b[31mbaz\x1b[m"),
+ newItem("foo'bar \x1b[31mbaz\x1b[m"),
+ newItem("FOO'BAR \x1b[31mBAZ\x1b[m")}
+
+ delim := "'"
+ var regex *regexp.Regexp
+
+ var result string
+ check := func(expected string) {
+ if result != expected {
+ t.Errorf("expected: %s, actual: %s", expected, result)
+ }
+ }
+ // helper function that converts template format into string and carries out the check()
+ checkFormat := func(format string) {
+ type quotes struct{ O, I, S string } // outer, inner quotes, print separator
+ unixStyle := quotes{`'`, `'\''`, "\n"}
+ windowsStyle := quotes{`^"`, `'`, "\n"}
+ var effectiveStyle quotes
+
+ if util.IsWindows() {
+ effectiveStyle = windowsStyle
+ } else {
+ effectiveStyle = unixStyle
+ }
+
+ expected := templateToString(format, effectiveStyle)
+ check(expected)
+ }
+ printsep := "\n"
+
+ /*
+ Test multiple placeholders and the function parameters.
+ */
+
+ // {}, preserve ansi
+ result = replacePlaceholder("echo {}", false, Delimiter{}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} foo{{.I}}bar \x1b[31mbaz\x1b[m{{.O}}")
+
+ // {}, strip ansi
+ result = replacePlaceholder("echo {}", true, Delimiter{}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} foo{{.I}}bar baz{{.O}}")
+
+ // {}, with multiple items
+ result = replacePlaceholder("echo {}", true, Delimiter{}, printsep, false, "query", items2)
+ checkFormat("echo {{.O}}foo{{.I}}bar baz{{.O}}")
+
+ // {..}, strip leading whitespaces, preserve ansi
+ result = replacePlaceholder("echo {..}", false, Delimiter{}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}}foo{{.I}}bar \x1b[31mbaz\x1b[m{{.O}}")
+
+ // {..}, strip leading whitespaces, strip ansi
+ result = replacePlaceholder("echo {..}", true, Delimiter{}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}}foo{{.I}}bar baz{{.O}}")
+
+ // {q}
+ result = replacePlaceholder("echo {} {q}", true, Delimiter{}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} foo{{.I}}bar baz{{.O}} {{.O}}query{{.O}}")
+
+ // {q}, multiple items
+ result = replacePlaceholder("echo {+}{q}{+}", true, Delimiter{}, printsep, false, "query 'string'", items2)
+ checkFormat("echo {{.O}}foo{{.I}}bar baz{{.O}} {{.O}}FOO{{.I}}BAR BAZ{{.O}}{{.O}}query {{.I}}string{{.I}}{{.O}}{{.O}}foo{{.I}}bar baz{{.O}} {{.O}}FOO{{.I}}BAR BAZ{{.O}}")
+
+ result = replacePlaceholder("echo {}{q}{}", true, Delimiter{}, printsep, false, "query 'string'", items2)
+ checkFormat("echo {{.O}}foo{{.I}}bar baz{{.O}}{{.O}}query {{.I}}string{{.I}}{{.O}}{{.O}}foo{{.I}}bar baz{{.O}}")
+
+ result = replacePlaceholder("echo {1}/{2}/{2,1}/{-1}/{-2}/{}/{..}/{n.t}/\\{}/\\{1}/\\{q}/{3}", true, Delimiter{}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}}foo{{.I}}bar{{.O}}/{{.O}}baz{{.O}}/{{.O}}bazfoo{{.I}}bar{{.O}}/{{.O}}baz{{.O}}/{{.O}}foo{{.I}}bar{{.O}}/{{.O}} foo{{.I}}bar baz{{.O}}/{{.O}}foo{{.I}}bar baz{{.O}}/{n.t}/{}/{1}/{q}/{{.O}}{{.O}}")
+
+ result = replacePlaceholder("echo {1}/{2}/{-1}/{-2}/{..}/{n.t}/\\{}/\\{1}/\\{q}/{3}", true, Delimiter{}, printsep, false, "query", items2)
+ checkFormat("echo {{.O}}foo{{.I}}bar{{.O}}/{{.O}}baz{{.O}}/{{.O}}baz{{.O}}/{{.O}}foo{{.I}}bar{{.O}}/{{.O}}foo{{.I}}bar baz{{.O}}/{n.t}/{}/{1}/{q}/{{.O}}{{.O}}")
+
+ result = replacePlaceholder("echo {+1}/{+2}/{+-1}/{+-2}/{+..}/{n.t}/\\{}/\\{1}/\\{q}/{+3}", true, Delimiter{}, printsep, false, "query", items2)
+ checkFormat("echo {{.O}}foo{{.I}}bar{{.O}} {{.O}}FOO{{.I}}BAR{{.O}}/{{.O}}baz{{.O}} {{.O}}BAZ{{.O}}/{{.O}}baz{{.O}} {{.O}}BAZ{{.O}}/{{.O}}foo{{.I}}bar{{.O}} {{.O}}FOO{{.I}}BAR{{.O}}/{{.O}}foo{{.I}}bar baz{{.O}} {{.O}}FOO{{.I}}BAR BAZ{{.O}}/{n.t}/{}/{1}/{q}/{{.O}}{{.O}} {{.O}}{{.O}}")
+
+ // forcePlus
+ result = replacePlaceholder("echo {1}/{2}/{-1}/{-2}/{..}/{n.t}/\\{}/\\{1}/\\{q}/{3}", true, Delimiter{}, printsep, true, "query", items2)
+ checkFormat("echo {{.O}}foo{{.I}}bar{{.O}} {{.O}}FOO{{.I}}BAR{{.O}}/{{.O}}baz{{.O}} {{.O}}BAZ{{.O}}/{{.O}}baz{{.O}} {{.O}}BAZ{{.O}}/{{.O}}foo{{.I}}bar{{.O}} {{.O}}FOO{{.I}}BAR{{.O}}/{{.O}}foo{{.I}}bar baz{{.O}} {{.O}}FOO{{.I}}BAR BAZ{{.O}}/{n.t}/{}/{1}/{q}/{{.O}}{{.O}} {{.O}}{{.O}}")
+
+ // Whitespace preserving flag with "'" delimiter
+ result = replacePlaceholder("echo {s1}", true, Delimiter{str: &delim}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} foo{{.O}}")
+
+ result = replacePlaceholder("echo {s2}", true, Delimiter{str: &delim}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}}bar baz{{.O}}")
+
+ result = replacePlaceholder("echo {s}", true, Delimiter{str: &delim}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} foo{{.I}}bar baz{{.O}}")
+
+ result = replacePlaceholder("echo {s..}", true, Delimiter{str: &delim}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} foo{{.I}}bar baz{{.O}}")
+
+ // Whitespace preserving flag with regex delimiter
+ regex = regexp.MustCompile(`\w+`)
+
+ result = replacePlaceholder("echo {s1}", true, Delimiter{regex: regex}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} {{.O}}")
+
+ result = replacePlaceholder("echo {s2}", true, Delimiter{regex: regex}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}}{{.I}}{{.O}}")
+
+ result = replacePlaceholder("echo {s3}", true, Delimiter{regex: regex}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} {{.O}}")
+
+ // No match
+ result = replacePlaceholder("echo {}/{+}", true, Delimiter{}, printsep, false, "query", []*Item{nil, nil})
+ check("echo /")
+
+ // No match, but with selections
+ result = replacePlaceholder("echo {}/{+}", true, Delimiter{}, printsep, false, "query", []*Item{nil, item1})
+ checkFormat("echo /{{.O}} foo{{.I}}bar baz{{.O}}")
+
+ // String delimiter
+ result = replacePlaceholder("echo {}/{1}/{2}", true, Delimiter{str: &delim}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} foo{{.I}}bar baz{{.O}}/{{.O}}foo{{.O}}/{{.O}}bar baz{{.O}}")
+
+ // Regex delimiter
+ regex = regexp.MustCompile("[oa]+")
+ // foo'bar baz
+ result = replacePlaceholder("echo {}/{1}/{3}/{2..3}", true, Delimiter{regex: regex}, printsep, false, "query", items1)
+ checkFormat("echo {{.O}} foo{{.I}}bar baz{{.O}}/{{.O}}f{{.O}}/{{.O}}r b{{.O}}/{{.O}}{{.I}}bar b{{.O}}")
+
+ /*
+ Test single placeholders, but focus on the placeholders' parameters (e.g. flags).
+ see: TestParsePlaceholder
+ */
+ items3 := []*Item{
+ // single line
+ newItem("1a 1b 1c 1d 1e 1f"),
+ // multi line
+ newItem("1a 1b 1c 1d 1e 1f"),
+ newItem("2a 2b 2c 2d 2e 2f"),
+ newItem("3a 3b 3c 3d 3e 3f"),
+ newItem("4a 4b 4c 4d 4e 4f"),
+ newItem("5a 5b 5c 5d 5e 5f"),
+ newItem("6a 6b 6c 6d 6e 6f"),
+ newItem("7a 7b 7c 7d 7e 7f"),
+ }
+ stripAnsi := false
+ printsep = "\n"
+ forcePlus := false
+ query := "sample query"
+
+ templateToOutput := make(map[string]string)
+ templateToFile := make(map[string]string) // same as above, but the file contents will be matched
+ // I. item type placeholder
+ templateToOutput[`{}`] = `{{.O}}1a 1b 1c 1d 1e 1f{{.O}}`
+ templateToOutput[`{+}`] = `{{.O}}1a 1b 1c 1d 1e 1f{{.O}} {{.O}}2a 2b 2c 2d 2e 2f{{.O}} {{.O}}3a 3b 3c 3d 3e 3f{{.O}} {{.O}}4a 4b 4c 4d 4e 4f{{.O}} {{.O}}5a 5b 5c 5d 5e 5f{{.O}} {{.O}}6a 6b 6c 6d 6e 6f{{.O}} {{.O}}7a 7b 7c 7d 7e 7f{{.O}}`
+ templateToOutput[`{n}`] = `0`
+ templateToOutput[`{+n}`] = `0 0 0 0 0 0 0`
+ templateToFile[`{f}`] = `1a 1b 1c 1d 1e 1f{{.S}}`
+ templateToFile[`{+f}`] = `1a 1b 1c 1d 1e 1f{{.S}}2a 2b 2c 2d 2e 2f{{.S}}3a 3b 3c 3d 3e 3f{{.S}}4a 4b 4c 4d 4e 4f{{.S}}5a 5b 5c 5d 5e 5f{{.S}}6a 6b 6c 6d 6e 6f{{.S}}7a 7b 7c 7d 7e 7f{{.S}}`
+ templateToFile[`{nf}`] = `0{{.S}}`
+ templateToFile[`{+nf}`] = `0{{.S}}0{{.S}}0{{.S}}0{{.S}}0{{.S}}0{{.S}}0{{.S}}`
+
+ // II. token type placeholders
+ templateToOutput[`{..}`] = templateToOutput[`{}`]
+ templateToOutput[`{1..}`] = templateToOutput[`{}`]
+ templateToOutput[`{..2}`] = `{{.O}}1a 1b{{.O}}`
+ templateToOutput[`{1..2}`] = templateToOutput[`{..2}`]
+ templateToOutput[`{-2..-1}`] = `{{.O}}1e 1f{{.O}}`
+ // shorthand for x..x range
+ templateToOutput[`{1}`] = `{{.O}}1a{{.O}}`
+ templateToOutput[`{1..1}`] = templateToOutput[`{1}`]
+ templateToOutput[`{-6}`] = templateToOutput[`{1}`]
+ // multiple ranges
+ templateToOutput[`{1,2}`] = templateToOutput[`{1..2}`]
+ templateToOutput[`{1,2,4}`] = `{{.O}}1a 1b 1d{{.O}}`
+ templateToOutput[`{1,2..4}`] = `{{.O}}1a 1b 1c 1d{{.O}}`
+ templateToOutput[`{1..2,-4..-3}`] = `{{.O}}1a 1b 1c 1d{{.O}}`
+ // flags
+ templateToOutput[`{+1}`] = `{{.O}}1a{{.O}} {{.O}}2a{{.O}} {{.O}}3a{{.O}} {{.O}}4a{{.O}} {{.O}}5a{{.O}} {{.O}}6a{{.O}} {{.O}}7a{{.O}}`
+ templateToOutput[`{+-1}`] = `{{.O}}1f{{.O}} {{.O}}2f{{.O}} {{.O}}3f{{.O}} {{.O}}4f{{.O}} {{.O}}5f{{.O}} {{.O}}6f{{.O}} {{.O}}7f{{.O}}`
+ templateToOutput[`{s1}`] = `{{.O}}1a {{.O}}`
+ templateToFile[`{f1}`] = `1a{{.S}}`
+ templateToOutput[`{+s1..2}`] = `{{.O}}1a 1b {{.O}} {{.O}}2a 2b {{.O}} {{.O}}3a 3b {{.O}} {{.O}}4a 4b {{.O}} {{.O}}5a 5b {{.O}} {{.O}}6a 6b {{.O}} {{.O}}7a 7b {{.O}}`
+ templateToFile[`{+sf1..2}`] = `1a 1b {{.S}}2a 2b {{.S}}3a 3b {{.S}}4a 4b {{.S}}5a 5b {{.S}}6a 6b {{.S}}7a 7b {{.S}}`
+
+ // III. query type placeholder
+ // query flag is not removed after parsing, so it gets doubled
+ // while the double q is invalid, it is useful here for testing purposes
+ templateToOutput[`{q}`] = "{{.O}}" + query + "{{.O}}"
+
+ // IV. escaping placeholder
+ templateToOutput[`\{}`] = `{}`
+ templateToOutput[`\{++}`] = `{++}`
+ templateToOutput[`{++}`] = templateToOutput[`{+}`]
+
+ for giveTemplate, wantOutput := range templateToOutput {
+ result = replacePlaceholder(giveTemplate, stripAnsi, Delimiter{}, printsep, forcePlus, query, items3)
+ checkFormat(wantOutput)
+ }
+ for giveTemplate, wantOutput := range templateToFile {
+ path := replacePlaceholder(giveTemplate, stripAnsi, Delimiter{}, printsep, forcePlus, query, items3)
+
+ data, err := readFile(path)
+ if err != nil {
+ t.Errorf("Cannot read the content of the temp file %s.", path)
+ }
+ result = string(data)
+
+ checkFormat(wantOutput)
+ }
+}
+
+func TestQuoteEntry(t *testing.T) {
+ type quotes struct{ E, O, SQ, DQ, BS string } // standalone escape, outer, single and double quotes, backslash
+ unixStyle := quotes{``, `'`, `'\''`, `"`, `\`}
+ windowsStyle := quotes{`^`, `^"`, `'`, `\^"`, `\\`}
+ var effectiveStyle quotes
+
+ if util.IsWindows() {
+ effectiveStyle = windowsStyle
+ } else {
+ effectiveStyle = unixStyle
+ }
+
+ tests := map[string]string{
+ `'`: `{{.O}}{{.SQ}}{{.O}}`,
+ `"`: `{{.O}}{{.DQ}}{{.O}}`,
+ `\`: `{{.O}}{{.BS}}{{.O}}`,
+ `\"`: `{{.O}}{{.BS}}{{.DQ}}{{.O}}`,
+ `"\\\"`: `{{.O}}{{.DQ}}{{.BS}}{{.BS}}{{.BS}}{{.DQ}}{{.O}}`,
+
+ `$`: `{{.O}}${{.O}}`,
+ `$HOME`: `{{.O}}$HOME{{.O}}`,
+ `'$HOME'`: `{{.O}}{{.SQ}}$HOME{{.SQ}}{{.O}}`,
+
+ `&`: `{{.O}}{{.E}}&{{.O}}`,
+ `|`: `{{.O}}{{.E}}|{{.O}}`,
+ `<`: `{{.O}}{{.E}}<{{.O}}`,
+ `>`: `{{.O}}{{.E}}>{{.O}}`,
+ `(`: `{{.O}}{{.E}}({{.O}}`,
+ `)`: `{{.O}}{{.E}}){{.O}}`,
+ `@`: `{{.O}}{{.E}}@{{.O}}`,
+ `^`: `{{.O}}{{.E}}^{{.O}}`,
+ `%`: `{{.O}}{{.E}}%{{.O}}`,
+ `!`: `{{.O}}{{.E}}!{{.O}}`,
+ `%USERPROFILE%`: `{{.O}}{{.E}}%USERPROFILE{{.E}}%{{.O}}`,
+ `C:\Program Files (x86)\`: `{{.O}}C:{{.BS}}Program Files {{.E}}(x86{{.E}}){{.BS}}{{.O}}`,
+ `"C:\Program Files"`: `{{.O}}{{.DQ}}C:{{.BS}}Program Files{{.DQ}}{{.O}}`,
+ }
+
+ for input, expected := range tests {
+ escaped := quoteEntry(input)
+ expected = templateToString(expected, effectiveStyle)
+ if escaped != expected {
+ t.Errorf("Input: %s, expected: %s, actual %s", input, expected, escaped)
+ }
+ }
+}
+
+// purpose of this test is to demonstrate some shortcomings of fzf's templating system on Unix
+func TestUnixCommands(t *testing.T) {
+ if util.IsWindows() {
+ t.SkipNow()
+ }
+ tests := []testCase{
+ // reference: give{template, query, items}, want{output OR match}
+
+ // 1) working examples
+
+ // paths that does not have to evaluated will work fine, when quoted
+ {give{`grep foo {}`, ``, newItems(`test`)}, want{output: `grep foo 'test'`}},
+ {give{`grep foo {}`, ``, newItems(`/home/user/test`)}, want{output: `grep foo '/home/user/test'`}},
+ {give{`grep foo {}`, ``, newItems(`./test`)}, want{output: `grep foo './test'`}},
+
+ // only placeholders are escaped as data, this will lookup tilde character in a test file in your home directory
+ // quoting the tilde is required (to be treated as string)
+ {give{`grep {} ~/test`, ``, newItems(`~`)}, want{output: `grep '~' ~/test`}},
+
+ // 2) problematic examples
+ // (not necessarily unexpected)
+
+ // paths that need to expand some part of it won't work (special characters and variables)
+ {give{`cat {}`, ``, newItems(`~/test`)}, want{output: `cat '~/test'`}},
+ {give{`cat {}`, ``, newItems(`$HOME/test`)}, want{output: `cat '$HOME/test'`}},
+ }
+ testCommands(t, tests)
+}
+
+// purpose of this test is to demonstrate some shortcomings of fzf's templating system on Windows
+func TestWindowsCommands(t *testing.T) {
+ if !util.IsWindows() {
+ t.SkipNow()
+ }
+ tests := []testCase{
+ // reference: give{template, query, items}, want{output OR match}
+
+ // 1) working examples
+
+ // example of redundantly escaped backslash in the output, besides looking bit ugly, it won't cause any issue
+ {give{`type {}`, ``, newItems(`C:\test.txt`)}, want{output: `type ^"C:\\test.txt^"`}},
+ {give{`rg -- "package" {}`, ``, newItems(`.\test.go`)}, want{output: `rg -- "package" ^".\\test.go^"`}},
+ // example of mandatorily escaped backslash in the output, otherwise `rg -- "C:\test.txt"` is matching for tabulator
+ {give{`rg -- {}`, ``, newItems(`C:\test.txt`)}, want{output: `rg -- ^"C:\\test.txt^"`}},
+ // example of mandatorily escaped double quote in the output, otherwise `rg -- ""C:\\test.txt""` is not matching for the double quotes around the path
+ {give{`rg -- {}`, ``, newItems(`"C:\test.txt"`)}, want{output: `rg -- ^"\^"C:\\test.txt\^"^"`}},
+
+ // 2) problematic examples
+ // (not necessarily unexpected)
+
+ // notepad++'s parser can't handle `-n"12"` generate by fzf, expects `-n12`
+ {give{`notepad++ -n{1} {2}`, ``, newItems(`12 C:\Work\Test Folder\File.txt`)}, want{output: `notepad++ -n^"12^" ^"C:\\Work\\Test Folder\\File.txt^"`}},
+
+ // cat is parsing `\"` as a part of the file path, double quote is illegal character for paths on Windows
+ // cat: "C:\\test.txt: Invalid argument
+ {give{`cat {}`, ``, newItems(`"C:\test.txt"`)}, want{output: `cat ^"\^"C:\\test.txt\^"^"`}},
+ // cat: "C:\\test.txt": Invalid argument
+ {give{`cmd /c {}`, ``, newItems(`cat "C:\test.txt"`)}, want{output: `cmd /c ^"cat \^"C:\\test.txt\^"^"`}},
+
+ // the "file" flag in the pattern won't create *.bat or *.cmd file so the command in the output tries to edit the file, instead of executing it
+ // the temp file contains: `cat "C:\test.txt"`
+ // TODO this should actually work
+ {give{`cmd /c {f}`, ``, newItems(`cat "C:\test.txt"`)}, want{match: `^cmd /c .*\fzf-preview-[0-9]{9}$`}},
+ }
+ testCommands(t, tests)
+}
+
+// purpose of this test is to demonstrate some shortcomings of fzf's templating system on Windows in Powershell
+func TestPowershellCommands(t *testing.T) {
+ if !util.IsWindows() {
+ t.SkipNow()
+ }
+
+ tests := []testCase{
+ // reference: give{template, query, items}, want{output OR match}
+
+ /*
+ You can read each line in the following table as a pipeline that
+ consist of series of parsers that act upon your input (col. 1) and
+ each cell represents the output value.
+
+ For example:
+ - exec.Command("program.exe", `\''`)
+ - goes to win32 api which will process it transparently as it contains no special characters, see [CommandLineToArgvW][].
+ - powershell command will receive it as is, that is two arguments: a literal backslash and empty string in single quotes
+ - native command run via/from powershell will receive only one argument: a literal backslash. Because extra parsing rules apply, see [NativeCallsFromPowershell][].
+ - some¹ apps have internal parser, that requires one more level of escaping (yes, this is completely application-specific, but see terminal_test.go#TestWindowsCommands)
+
+ Character⁰ CommandLineToArgvW Powershell commands Native commands from Powershell Apps requiring escapes¹ | Being tested below
+ ---------- ------------------ ------------------------------ ------------------------------- -------------------------- | ------------------
+ " empty string² missing argument error ... ... |
+ \" literal " unbalanced quote error ... ... |
+ '\"' literal '"' literal " empty string empty string (match all) | yes
+ '\\\"' literal '\"' literal \" literal " literal " |
+ ---------- ------------------ ------------------------------ ------------------------------- -------------------------- | ------------------
+ \ transparent transparent transparent regex error |
+ '\' transparent literal \ literal \ regex error | yes
+ \\ transparent transparent transparent literal \ |
+ '\\' transparent literal \\ literal \\ literal \ |
+ ---------- ------------------ ------------------------------ ------------------------------- -------------------------- | ------------------
+ ' transparent unbalanced quote error ... ... |
+ \' transparent literal \ and unb. quote error ... ... |
+ \'' transparent literal \ and empty string literal \ regex error | no, but given as example above
+ ''' transparent unbalanced quote error ... ... |
+ '''' transparent literal ' literal ' literal ' | yes
+ ---------- ------------------ ------------------------------ ------------------------------- -------------------------- | ------------------
+
+ ⁰: charatecter or characters 'x' as an argument to a program in go's call: exec.Command("program.exe", `x`)
+ ¹: native commands like grep, git grep, ripgrep
+ ²: interpreted as a grouping quote, affects argument parser and gets removed from the result
+
+ [CommandLineToArgvW]: https://docs.microsoft.com/en-gb/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#remarks
+ [NativeCallsFromPowershell]: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parsing?view=powershell-7.1#passing-arguments-that-contain-quote-characters
+ */
+
+ // 1) working examples
+
+ {give{`Get-Content {}`, ``, newItems(`C:\test.txt`)}, want{output: `Get-Content 'C:\test.txt'`}},
+ {give{`rg -- "package" {}`, ``, newItems(`.\test.go`)}, want{output: `rg -- "package" '.\test.go'`}},
+
+ // example of escaping single quotes
+ {give{`rg -- {}`, ``, newItems(`'foobar'`)}, want{output: `rg -- '''foobar'''`}},
+
+ // chaining powershells
+ {give{`powershell -NoProfile -Command {}`, ``, newItems(`cat "C:\test.txt"`)}, want{output: `powershell -NoProfile -Command 'cat \"C:\test.txt\"'`}},
+
+ // 2) problematic examples
+ // (not necessarily unexpected)
+
+ // looking for a path string will only work with escaped backslashes
+ {give{`rg -- {}`, ``, newItems(`C:\test.txt`)}, want{output: `rg -- 'C:\test.txt'`}},
+ // looking for a literal double quote will only work with triple escaped double quotes
+ {give{`rg -- {}`, ``, newItems(`"C:\test.txt"`)}, want{output: `rg -- '\"C:\test.txt\"'`}},
+
+ // Get-Content (i.e. cat alias) is parsing `"` as a part of the file path, returns an error:
+ // Get-Content : Cannot find drive. A drive with the name '"C:' does not exist.
+ {give{`cat {}`, ``, newItems(`"C:\test.txt"`)}, want{output: `cat '\"C:\test.txt\"'`}},
+
+ // the "file" flag in the pattern won't create *.ps1 file so the powershell will offload this "unknown" filetype
+ // to explorer, which will prompt user to pick editing program for the fzf-preview file
+ // the temp file contains: `cat "C:\test.txt"`
+ // TODO this should actually work
+ {give{`powershell -NoProfile -Command {f}`, ``, newItems(`cat "C:\test.txt"`)}, want{match: `^powershell -NoProfile -Command .*\fzf-preview-[0-9]{9}$`}},
+ }
+
+ // to force powershell-style escaping we temporarily set environment variable that fzf honors
+ shellBackup := os.Getenv("SHELL")
+ os.Setenv("SHELL", "powershell")
+ testCommands(t, tests)
+ os.Setenv("SHELL", shellBackup)
+}
+
+/*
+Test typical valid placeholders and parsing of them.
+
+Also since the parser assumes the input is matched with `placeholder` regex,
+the regex is tested here as well.
+*/
+func TestParsePlaceholder(t *testing.T) {
+ // give, want pairs
+ templates := map[string]string{
+ // I. item type placeholder
+ `{}`: `{}`,
+ `{+}`: `{+}`,
+ `{n}`: `{n}`,
+ `{+n}`: `{+n}`,
+ `{f}`: `{f}`,
+ `{+nf}`: `{+nf}`,
+
+ // II. token type placeholders
+ `{..}`: `{..}`,
+ `{1..}`: `{1..}`,
+ `{..2}`: `{..2}`,
+ `{1..2}`: `{1..2}`,
+ `{-2..-1}`: `{-2..-1}`,
+ // shorthand for x..x range
+ `{1}`: `{1}`,
+ `{1..1}`: `{1..1}`,
+ `{-6}`: `{-6}`,
+ // multiple ranges
+ `{1,2}`: `{1,2}`,
+ `{1,2,4}`: `{1,2,4}`,
+ `{1,2..4}`: `{1,2..4}`,
+ `{1..2,-4..-3}`: `{1..2,-4..-3}`,
+ // flags
+ `{+1}`: `{+1}`,
+ `{+-1}`: `{+-1}`,
+ `{s1}`: `{s1}`,
+ `{f1}`: `{f1}`,
+ `{+s1..2}`: `{+s1..2}`,
+ `{+sf1..2}`: `{+sf1..2}`,
+
+ // III. query type placeholder
+ // query flag is not removed after parsing, so it gets doubled
+ // while the double q is invalid, it is useful here for testing purposes
+ `{q}`: `{qq}`,
+
+ // IV. escaping placeholder
+ `\{}`: `{}`,
+ `\{++}`: `{++}`,
+ `{++}`: `{+}`,
+ }
+
+ for giveTemplate, wantTemplate := range templates {
+ if !placeholder.MatchString(giveTemplate) {
+ t.Errorf(`given placeholder %s does not match placeholder regex, so attempt to parse it is unexpected`, giveTemplate)
+ continue
+ }
+
+ _, placeholderWithoutFlags, flags := parsePlaceholder(giveTemplate)
+ gotTemplate := placeholderWithoutFlags[:1] + flags.encodePlaceholder() + placeholderWithoutFlags[1:]
+
+ if gotTemplate != wantTemplate {
+ t.Errorf(`parsed placeholder "%s" into "%s", but want "%s"`, giveTemplate, gotTemplate, wantTemplate)
+ }
+ }
+}
+
+/* utilities section */
+
+// Item represents one line in fzf UI. Usually it is relative path to files and folders.
+func newItem(str string) *Item {
+ bytes := []byte(str)
+ trimmed, _, _ := extractColor(str, nil, nil)
+ return &Item{origText: &bytes, text: util.ToChars([]byte(trimmed))}
+}
+
+// Functions tested in this file require array of items (allItems). The array needs
+// to consist of at least two nils. This is helper function.
+func newItems(str ...string) []*Item {
+ result := make([]*Item, util.Max(len(str), 2))
+ for i, s := range str {
+ result[i] = newItem(s)
+ }
+ return result
+}
+
+// (for logging purposes)
+func (item *Item) String() string {
+ return item.AsString(true)
+}
+
+// Helper function to parse, execute and convert "text/template" to string. Panics on error.
+func templateToString(format string, data interface{}) string {
+ bb := &bytes.Buffer{}
+
+ err := template.Must(template.New("").Parse(format)).Execute(bb, data)
+ if err != nil {
+ panic(err)
+ }
+
+ return bb.String()
+}
+
+// ad hoc types for test cases
+type give struct {
+ template string
+ query string
+ allItems []*Item
+}
+type want struct {
+ /*
+ Unix:
+ The `want.output` string is supposed to be formatted for evaluation by
+ `sh -c command` system call.
+
+ Windows:
+ The `want.output` string is supposed to be formatted for evaluation by
+ `cmd.exe /s /c "command"` system call. The `/s` switch enables so called old
+ behaviour, which is more favourable for nesting (possibly escaped)
+ special characters. This is the relevant section of `help cmd`:
+
+ ...old behavior is to see if the first character is
+ a quote character and if so, strip the leading character and
+ remove the last quote character on the command line, preserving
+ any text after the last quote character.
+ */
+ output string // literal output
+ match string // output is matched against this regex (when output is empty string)
+}
+type testCase struct {
+ give
+ want
+}
+
+func testCommands(t *testing.T, tests []testCase) {
+ // common test parameters
+ delim := "\t"
+ delimiter := Delimiter{str: &delim}
+ printsep := ""
+ stripAnsi := false
+ forcePlus := false
+
+ // evaluate the test cases
+ for idx, test := range tests {
+ gotOutput := replacePlaceholder(
+ test.give.template, stripAnsi, delimiter, printsep, forcePlus,
+ test.give.query,
+ test.give.allItems)
+ switch {
+ case test.want.output != "":
+ if gotOutput != test.want.output {
+ t.Errorf("tests[%v]:\ngave{\n\ttemplate: '%s',\n\tquery: '%s',\n\tallItems: %s}\nand got '%s',\nbut want '%s'",
+ idx,
+ test.give.template, test.give.query, test.give.allItems,
+ gotOutput, test.want.output)
+ }
+ case test.want.match != "":
+ wantMatch := strings.ReplaceAll(test.want.match, `\`, `\\`)
+ wantRegex := regexp.MustCompile(wantMatch)
+ if !wantRegex.MatchString(gotOutput) {
+ t.Errorf("tests[%v]:\ngave{\n\ttemplate: '%s',\n\tquery: '%s',\n\tallItems: %s}\nand got '%s',\nbut want '%s'",
+ idx,
+ test.give.template, test.give.query, test.give.allItems,
+ gotOutput, test.want.match)
+ }
+ default:
+ t.Errorf("tests[%v]: test case does not describe 'want' property", idx)
+ }
+ }
+}
+
+// naive encoder of placeholder flags
+func (flags placeholderFlags) encodePlaceholder() string {
+ encoded := ""
+ if flags.plus {
+ encoded += "+"
+ }
+ if flags.preserveSpace {
+ encoded += "s"
+ }
+ if flags.number {
+ encoded += "n"
+ }
+ if flags.file {
+ encoded += "f"
+ }
+ if flags.query {
+ encoded += "q"
+ }
+ return encoded
+}
+
+// can be replaced with os.ReadFile() in go 1.16+
+func readFile(path string) ([]byte, error) {
+ file, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ data := make([]byte, 0, 128)
+ for {
+ if len(data) >= cap(data) {
+ d := append(data[:cap(data)], 0)
+ data = d[:len(data)]
+ }
+
+ n, err := file.Read(data[len(data):cap(data)])
+ data = data[:len(data)+n]
+ if err != nil {
+ if err == io.EOF {
+ err = nil
+ }
+ return data, err
+ }
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/terminal_unix.go b/dot-oh-my-zsh/custom/plugins/fzf/src/terminal_unix.go
new file mode 100644
index 00000000..4cee73b0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/terminal_unix.go
@@ -0,0 +1,26 @@
+//go:build !windows
+
+package fzf
+
+import (
+ "os"
+ "os/signal"
+ "strings"
+ "syscall"
+)
+
+func notifyOnResize(resizeChan chan<- os.Signal) {
+ signal.Notify(resizeChan, syscall.SIGWINCH)
+}
+
+func notifyStop(p *os.Process) {
+ p.Signal(syscall.SIGSTOP)
+}
+
+func notifyOnCont(resizeChan chan<- os.Signal) {
+ signal.Notify(resizeChan, syscall.SIGCONT)
+}
+
+func quoteEntry(entry string) string {
+ return "'" + strings.Replace(entry, "'", "'\\''", -1) + "'"
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/terminal_windows.go b/dot-oh-my-zsh/custom/plugins/fzf/src/terminal_windows.go
new file mode 100644
index 00000000..a1ea7a22
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/terminal_windows.go
@@ -0,0 +1,45 @@
+//go:build windows
+
+package fzf
+
+import (
+ "os"
+ "regexp"
+ "strings"
+)
+
+func notifyOnResize(resizeChan chan<- os.Signal) {
+ // TODO
+}
+
+func notifyStop(p *os.Process) {
+ // NOOP
+}
+
+func notifyOnCont(resizeChan chan<- os.Signal) {
+ // NOOP
+}
+
+func quoteEntry(entry string) string {
+ shell := os.Getenv("SHELL")
+ if len(shell) == 0 {
+ shell = "cmd"
+ }
+
+ if strings.Contains(shell, "cmd") {
+ // backslash escaping is done here for applications
+ // (see ripgrep test case in terminal_test.go#TestWindowsCommands)
+ escaped := strings.Replace(entry, `\`, `\\`, -1)
+ escaped = `"` + strings.Replace(escaped, `"`, `\"`, -1) + `"`
+ // caret is the escape character for cmd shell
+ r, _ := regexp.Compile(`[&|<>()@^%!"]`)
+ return r.ReplaceAllStringFunc(escaped, func(match string) string {
+ return "^" + match
+ })
+ } else if strings.Contains(shell, "pwsh") || strings.Contains(shell, "powershell") {
+ escaped := strings.Replace(entry, `"`, `\"`, -1)
+ return "'" + strings.Replace(escaped, "'", "''", -1) + "'"
+ } else {
+ return "'" + strings.Replace(entry, "'", "'\\''", -1) + "'"
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tokenizer.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tokenizer.go
new file mode 100644
index 00000000..9f9e2c19
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tokenizer.go
@@ -0,0 +1,253 @@
+package fzf
+
+import (
+ "bytes"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/junegunn/fzf/src/util"
+)
+
+const rangeEllipsis = 0
+
+// Range represents nth-expression
+type Range struct {
+ begin int
+ end int
+}
+
+// Token contains the tokenized part of the strings and its prefix length
+type Token struct {
+ text *util.Chars
+ prefixLength int32
+}
+
+// String returns the string representation of a Token.
+func (t Token) String() string {
+ return fmt.Sprintf("Token{text: %s, prefixLength: %d}", t.text, t.prefixLength)
+}
+
+// Delimiter for tokenizing the input
+type Delimiter struct {
+ regex *regexp.Regexp
+ str *string
+}
+
+// String returns the string representation of a Delimiter.
+func (d Delimiter) String() string {
+ return fmt.Sprintf("Delimiter{regex: %v, str: &%q}", d.regex, *d.str)
+}
+
+func newRange(begin int, end int) Range {
+ if begin == 1 {
+ begin = rangeEllipsis
+ }
+ if end == -1 {
+ end = rangeEllipsis
+ }
+ return Range{begin, end}
+}
+
+// ParseRange parses nth-expression and returns the corresponding Range object
+func ParseRange(str *string) (Range, bool) {
+ if (*str) == ".." {
+ return newRange(rangeEllipsis, rangeEllipsis), true
+ } else if strings.HasPrefix(*str, "..") {
+ end, err := strconv.Atoi((*str)[2:])
+ if err != nil || end == 0 {
+ return Range{}, false
+ }
+ return newRange(rangeEllipsis, end), true
+ } else if strings.HasSuffix(*str, "..") {
+ begin, err := strconv.Atoi((*str)[:len(*str)-2])
+ if err != nil || begin == 0 {
+ return Range{}, false
+ }
+ return newRange(begin, rangeEllipsis), true
+ } else if strings.Contains(*str, "..") {
+ ns := strings.Split(*str, "..")
+ if len(ns) != 2 {
+ return Range{}, false
+ }
+ begin, err1 := strconv.Atoi(ns[0])
+ end, err2 := strconv.Atoi(ns[1])
+ if err1 != nil || err2 != nil || begin == 0 || end == 0 {
+ return Range{}, false
+ }
+ return newRange(begin, end), true
+ }
+
+ n, err := strconv.Atoi(*str)
+ if err != nil || n == 0 {
+ return Range{}, false
+ }
+ return newRange(n, n), true
+}
+
+func withPrefixLengths(tokens []string, begin int) []Token {
+ ret := make([]Token, len(tokens))
+
+ prefixLength := begin
+ for idx := range tokens {
+ chars := util.ToChars([]byte(tokens[idx]))
+ ret[idx] = Token{&chars, int32(prefixLength)}
+ prefixLength += chars.Length()
+ }
+ return ret
+}
+
+const (
+ awkNil = iota
+ awkBlack
+ awkWhite
+)
+
+func awkTokenizer(input string) ([]string, int) {
+ // 9, 32
+ ret := []string{}
+ prefixLength := 0
+ state := awkNil
+ begin := 0
+ end := 0
+ for idx := 0; idx < len(input); idx++ {
+ r := input[idx]
+ white := r == 9 || r == 32
+ switch state {
+ case awkNil:
+ if white {
+ prefixLength++
+ } else {
+ state, begin, end = awkBlack, idx, idx+1
+ }
+ case awkBlack:
+ end = idx + 1
+ if white {
+ state = awkWhite
+ }
+ case awkWhite:
+ if white {
+ end = idx + 1
+ } else {
+ ret = append(ret, input[begin:end])
+ state, begin, end = awkBlack, idx, idx+1
+ }
+ }
+ }
+ if begin < end {
+ ret = append(ret, input[begin:end])
+ }
+ return ret, prefixLength
+}
+
+// Tokenize tokenizes the given string with the delimiter
+func Tokenize(text string, delimiter Delimiter) []Token {
+ if delimiter.str == nil && delimiter.regex == nil {
+ // AWK-style (\S+\s*)
+ tokens, prefixLength := awkTokenizer(text)
+ return withPrefixLengths(tokens, prefixLength)
+ }
+
+ if delimiter.str != nil {
+ return withPrefixLengths(strings.SplitAfter(text, *delimiter.str), 0)
+ }
+
+ // FIXME performance
+ var tokens []string
+ if delimiter.regex != nil {
+ locs := delimiter.regex.FindAllStringIndex(text, -1)
+ begin := 0
+ for _, loc := range locs {
+ tokens = append(tokens, text[begin:loc[1]])
+ begin = loc[1]
+ }
+ if begin < len(text) {
+ tokens = append(tokens, text[begin:])
+ }
+ }
+ return withPrefixLengths(tokens, 0)
+}
+
+func joinTokens(tokens []Token) string {
+ var output bytes.Buffer
+ for _, token := range tokens {
+ output.WriteString(token.text.ToString())
+ }
+ return output.String()
+}
+
+// Transform is used to transform the input when --with-nth option is given
+func Transform(tokens []Token, withNth []Range) []Token {
+ transTokens := make([]Token, len(withNth))
+ numTokens := len(tokens)
+ for idx, r := range withNth {
+ parts := []*util.Chars{}
+ minIdx := 0
+ if r.begin == r.end {
+ idx := r.begin
+ if idx == rangeEllipsis {
+ chars := util.ToChars([]byte(joinTokens(tokens)))
+ parts = append(parts, &chars)
+ } else {
+ if idx < 0 {
+ idx += numTokens + 1
+ }
+ if idx >= 1 && idx <= numTokens {
+ minIdx = idx - 1
+ parts = append(parts, tokens[idx-1].text)
+ }
+ }
+ } else {
+ var begin, end int
+ if r.begin == rangeEllipsis { // ..N
+ begin, end = 1, r.end
+ if end < 0 {
+ end += numTokens + 1
+ }
+ } else if r.end == rangeEllipsis { // N..
+ begin, end = r.begin, numTokens
+ if begin < 0 {
+ begin += numTokens + 1
+ }
+ } else {
+ begin, end = r.begin, r.end
+ if begin < 0 {
+ begin += numTokens + 1
+ }
+ if end < 0 {
+ end += numTokens + 1
+ }
+ }
+ minIdx = util.Max(0, begin-1)
+ for idx := begin; idx <= end; idx++ {
+ if idx >= 1 && idx <= numTokens {
+ parts = append(parts, tokens[idx-1].text)
+ }
+ }
+ }
+ // Merge multiple parts
+ var merged util.Chars
+ switch len(parts) {
+ case 0:
+ merged = util.ToChars([]byte{})
+ case 1:
+ merged = *parts[0]
+ default:
+ var output bytes.Buffer
+ for _, part := range parts {
+ output.WriteString(part.ToString())
+ }
+ merged = util.ToChars(output.Bytes())
+ }
+
+ var prefixLength int32
+ if minIdx < numTokens {
+ prefixLength = tokens[minIdx].prefixLength
+ } else {
+ prefixLength = 0
+ }
+ transTokens[idx] = Token{&merged, prefixLength}
+ }
+ return transTokens
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tokenizer_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tokenizer_test.go
new file mode 100644
index 00000000..985cef9f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tokenizer_test.go
@@ -0,0 +1,112 @@
+package fzf
+
+import (
+ "testing"
+)
+
+func TestParseRange(t *testing.T) {
+ {
+ i := ".."
+ r, _ := ParseRange(&i)
+ if r.begin != rangeEllipsis || r.end != rangeEllipsis {
+ t.Errorf("%v", r)
+ }
+ }
+ {
+ i := "3.."
+ r, _ := ParseRange(&i)
+ if r.begin != 3 || r.end != rangeEllipsis {
+ t.Errorf("%v", r)
+ }
+ }
+ {
+ i := "3..5"
+ r, _ := ParseRange(&i)
+ if r.begin != 3 || r.end != 5 {
+ t.Errorf("%v", r)
+ }
+ }
+ {
+ i := "-3..-5"
+ r, _ := ParseRange(&i)
+ if r.begin != -3 || r.end != -5 {
+ t.Errorf("%v", r)
+ }
+ }
+ {
+ i := "3"
+ r, _ := ParseRange(&i)
+ if r.begin != 3 || r.end != 3 {
+ t.Errorf("%v", r)
+ }
+ }
+}
+
+func TestTokenize(t *testing.T) {
+ // AWK-style
+ input := " abc: def: ghi "
+ tokens := Tokenize(input, Delimiter{})
+ if tokens[0].text.ToString() != "abc: " || tokens[0].prefixLength != 2 {
+ t.Errorf("%s", tokens)
+ }
+
+ // With delimiter
+ tokens = Tokenize(input, delimiterRegexp(":"))
+ if tokens[0].text.ToString() != " abc:" || tokens[0].prefixLength != 0 {
+ t.Error(tokens[0].text.ToString(), tokens[0].prefixLength)
+ }
+
+ // With delimiter regex
+ tokens = Tokenize(input, delimiterRegexp("\\s+"))
+ if tokens[0].text.ToString() != " " || tokens[0].prefixLength != 0 ||
+ tokens[1].text.ToString() != "abc: " || tokens[1].prefixLength != 2 ||
+ tokens[2].text.ToString() != "def: " || tokens[2].prefixLength != 8 ||
+ tokens[3].text.ToString() != "ghi " || tokens[3].prefixLength != 14 {
+ t.Errorf("%s", tokens)
+ }
+}
+
+func TestTransform(t *testing.T) {
+ input := " abc: def: ghi: jkl"
+ {
+ tokens := Tokenize(input, Delimiter{})
+ {
+ ranges := splitNth("1,2,3")
+ tx := Transform(tokens, ranges)
+ if joinTokens(tx) != "abc: def: ghi: " {
+ t.Errorf("%s", tx)
+ }
+ }
+ {
+ ranges := splitNth("1..2,3,2..,1")
+ tx := Transform(tokens, ranges)
+ if string(joinTokens(tx)) != "abc: def: ghi: def: ghi: jklabc: " ||
+ len(tx) != 4 ||
+ tx[0].text.ToString() != "abc: def: " || tx[0].prefixLength != 2 ||
+ tx[1].text.ToString() != "ghi: " || tx[1].prefixLength != 14 ||
+ tx[2].text.ToString() != "def: ghi: jkl" || tx[2].prefixLength != 8 ||
+ tx[3].text.ToString() != "abc: " || tx[3].prefixLength != 2 {
+ t.Errorf("%s", tx)
+ }
+ }
+ }
+ {
+ tokens := Tokenize(input, delimiterRegexp(":"))
+ {
+ ranges := splitNth("1..2,3,2..,1")
+ tx := Transform(tokens, ranges)
+ if joinTokens(tx) != " abc: def: ghi: def: ghi: jkl abc:" ||
+ len(tx) != 4 ||
+ tx[0].text.ToString() != " abc: def:" || tx[0].prefixLength != 0 ||
+ tx[1].text.ToString() != " ghi:" || tx[1].prefixLength != 12 ||
+ tx[2].text.ToString() != " def: ghi: jkl" || tx[2].prefixLength != 6 ||
+ tx[3].text.ToString() != " abc:" || tx[3].prefixLength != 0 {
+ t.Errorf("%s", tx)
+ }
+ }
+ }
+}
+
+func TestTransformIndexOutOfBounds(t *testing.T) {
+ Transform([]Token{}, splitNth("1"))
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/dummy.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/dummy.go
new file mode 100644
index 00000000..297a887e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/dummy.go
@@ -0,0 +1,45 @@
+//go:build !tcell && !windows
+
+package tui
+
+type Attr int32
+
+func HasFullscreenRenderer() bool {
+ return false
+}
+
+func (a Attr) Merge(b Attr) Attr {
+ return a | b
+}
+
+const (
+ AttrUndefined = Attr(0)
+ AttrRegular = Attr(1 << 8)
+ AttrClear = Attr(1 << 9)
+
+ Bold = Attr(1)
+ Dim = Attr(1 << 1)
+ Italic = Attr(1 << 2)
+ Underline = Attr(1 << 3)
+ Blink = Attr(1 << 4)
+ Blink2 = Attr(1 << 5)
+ Reverse = Attr(1 << 6)
+ StrikeThrough = Attr(1 << 7)
+)
+
+func (r *FullscreenRenderer) Init() {}
+func (r *FullscreenRenderer) Pause(bool) {}
+func (r *FullscreenRenderer) Resume(bool, bool) {}
+func (r *FullscreenRenderer) Clear() {}
+func (r *FullscreenRenderer) Refresh() {}
+func (r *FullscreenRenderer) Close() {}
+
+func (r *FullscreenRenderer) GetChar() Event { return Event{} }
+func (r *FullscreenRenderer) MaxX() int { return 0 }
+func (r *FullscreenRenderer) MaxY() int { return 0 }
+
+func (r *FullscreenRenderer) RefreshWindows(windows []Window) {}
+
+func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window {
+ return nil
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/light.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/light.go
new file mode 100644
index 00000000..0546caa8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/light.go
@@ -0,0 +1,1019 @@
+package tui
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf8"
+
+ "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
+
+ "golang.org/x/term"
+)
+
+const (
+ defaultWidth = 80
+ defaultHeight = 24
+
+ defaultEscDelay = 100
+ escPollInterval = 5
+ offsetPollTries = 10
+ maxInputBuffer = 1024 * 1024
+)
+
+const consoleDevice string = "/dev/tty"
+
+var offsetRegexp *regexp.Regexp = regexp.MustCompile("(.*)\x1b\\[([0-9]+);([0-9]+)R")
+var offsetRegexpBegin *regexp.Regexp = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R")
+
+func (r *LightRenderer) stderr(str string) {
+ r.stderrInternal(str, true)
+}
+
+// FIXME: Need better handling of non-displayable characters
+func (r *LightRenderer) stderrInternal(str string, allowNLCR bool) {
+ bytes := []byte(str)
+ runes := []rune{}
+ for len(bytes) > 0 {
+ r, sz := utf8.DecodeRune(bytes)
+ nlcr := r == '\n' || r == '\r'
+ if r >= 32 || r == '\x1b' || nlcr {
+ if r == utf8.RuneError || nlcr && !allowNLCR {
+ runes = append(runes, ' ')
+ } else {
+ runes = append(runes, r)
+ }
+ }
+ bytes = bytes[sz:]
+ }
+ r.queued.WriteString(string(runes))
+}
+
+func (r *LightRenderer) csi(code string) {
+ r.stderr("\x1b[" + code)
+}
+
+func (r *LightRenderer) flush() {
+ if r.queued.Len() > 0 {
+ fmt.Fprint(os.Stderr, "\x1b[?25l"+r.queued.String()+"\x1b[?25h")
+ r.queued.Reset()
+ }
+}
+
+// Light renderer
+type LightRenderer struct {
+ theme *ColorTheme
+ mouse bool
+ forceBlack bool
+ clearOnExit bool
+ prevDownTime time.Time
+ clickY []int
+ ttyin *os.File
+ buffer []byte
+ origState *term.State
+ width int
+ height int
+ yoffset int
+ tabstop int
+ escDelay int
+ fullscreen bool
+ upOneLine bool
+ queued strings.Builder
+ y int
+ x int
+ maxHeightFunc func(int) int
+
+ // Windows only
+ ttyinChannel chan byte
+ inHandle uintptr
+ outHandle uintptr
+ origStateInput uint32
+ origStateOutput uint32
+}
+
+type LightWindow struct {
+ renderer *LightRenderer
+ colored bool
+ preview bool
+ border BorderStyle
+ top int
+ left int
+ width int
+ height int
+ posx int
+ posy int
+ tabstop int
+ fg Color
+ bg Color
+}
+
+func NewLightRenderer(theme *ColorTheme, forceBlack bool, mouse bool, tabstop int, clearOnExit bool, fullscreen bool, maxHeightFunc func(int) int) Renderer {
+ r := LightRenderer{
+ theme: theme,
+ forceBlack: forceBlack,
+ mouse: mouse,
+ clearOnExit: clearOnExit,
+ ttyin: openTtyIn(),
+ yoffset: 0,
+ tabstop: tabstop,
+ fullscreen: fullscreen,
+ upOneLine: false,
+ maxHeightFunc: maxHeightFunc}
+ return &r
+}
+
+func repeat(r rune, times int) string {
+ if times > 0 {
+ return strings.Repeat(string(r), times)
+ }
+ return ""
+}
+
+func atoi(s string, defaultValue int) int {
+ value, err := strconv.Atoi(s)
+ if err != nil {
+ return defaultValue
+ }
+ return value
+}
+
+func (r *LightRenderer) Init() {
+ r.escDelay = atoi(os.Getenv("ESCDELAY"), defaultEscDelay)
+
+ if err := r.initPlatform(); err != nil {
+ errorExit(err.Error())
+ }
+ r.updateTerminalSize()
+ initTheme(r.theme, r.defaultTheme(), r.forceBlack)
+
+ if r.fullscreen {
+ r.smcup()
+ } else {
+ // We assume that --no-clear is used for repetitive relaunching of fzf.
+ // So we do not clear the lower bottom of the screen.
+ if r.clearOnExit {
+ r.csi("J")
+ }
+ y, x := r.findOffset()
+ r.mouse = r.mouse && y >= 0
+ // When --no-clear is used for repetitive relaunching, there is a small
+ // time frame between fzf processes where the user keystrokes are not
+ // captured by either of fzf process which can cause x offset to be
+ // increased and we're left with unwanted extra new line.
+ if x > 0 && r.clearOnExit {
+ r.upOneLine = true
+ r.makeSpace()
+ }
+ for i := 1; i < r.MaxY(); i++ {
+ r.makeSpace()
+ }
+ }
+
+ if r.mouse {
+ r.csi("?1000h")
+ r.csi("?1006h")
+ }
+ r.csi(fmt.Sprintf("%dA", r.MaxY()-1))
+ r.csi("G")
+ r.csi("K")
+ if !r.clearOnExit && !r.fullscreen {
+ r.csi("s")
+ }
+ if !r.fullscreen && r.mouse {
+ r.yoffset, _ = r.findOffset()
+ }
+}
+
+func (r *LightRenderer) makeSpace() {
+ r.stderr("\n")
+ r.csi("G")
+}
+
+func (r *LightRenderer) move(y int, x int) {
+ // w.csi("u")
+ if r.y < y {
+ r.csi(fmt.Sprintf("%dB", y-r.y))
+ } else if r.y > y {
+ r.csi(fmt.Sprintf("%dA", r.y-y))
+ }
+ r.stderr("\r")
+ if x > 0 {
+ r.csi(fmt.Sprintf("%dC", x))
+ }
+ r.y = y
+ r.x = x
+}
+
+func (r *LightRenderer) origin() {
+ r.move(0, 0)
+}
+
+func getEnv(name string, defaultValue int) int {
+ env := os.Getenv(name)
+ if len(env) == 0 {
+ return defaultValue
+ }
+ return atoi(env, defaultValue)
+}
+
+func (r *LightRenderer) getBytes() []byte {
+ return r.getBytesInternal(r.buffer, false)
+}
+
+func (r *LightRenderer) getBytesInternal(buffer []byte, nonblock bool) []byte {
+ c, ok := r.getch(nonblock)
+ if !nonblock && !ok {
+ r.Close()
+ errorExit("Failed to read " + consoleDevice)
+ }
+
+ retries := 0
+ if c == ESC.Int() || nonblock {
+ retries = r.escDelay / escPollInterval
+ }
+ buffer = append(buffer, byte(c))
+
+ pc := c
+ for {
+ c, ok = r.getch(true)
+ if !ok {
+ if retries > 0 {
+ retries--
+ time.Sleep(escPollInterval * time.Millisecond)
+ continue
+ }
+ break
+ } else if c == ESC.Int() && pc != c {
+ retries = r.escDelay / escPollInterval
+ } else {
+ retries = 0
+ }
+ buffer = append(buffer, byte(c))
+ pc = c
+
+ // This should never happen under normal conditions,
+ // so terminate fzf immediately.
+ if len(buffer) > maxInputBuffer {
+ r.Close()
+ panic(fmt.Sprintf("Input buffer overflow (%d): %v", len(buffer), buffer))
+ }
+ }
+
+ return buffer
+}
+
+func (r *LightRenderer) GetChar() Event {
+ if len(r.buffer) == 0 {
+ r.buffer = r.getBytes()
+ }
+ if len(r.buffer) == 0 {
+ panic("Empty buffer")
+ }
+
+ sz := 1
+ defer func() {
+ r.buffer = r.buffer[sz:]
+ }()
+
+ switch r.buffer[0] {
+ case CtrlC.Byte():
+ return Event{CtrlC, 0, nil}
+ case CtrlG.Byte():
+ return Event{CtrlG, 0, nil}
+ case CtrlQ.Byte():
+ return Event{CtrlQ, 0, nil}
+ case 127:
+ return Event{BSpace, 0, nil}
+ case 0:
+ return Event{CtrlSpace, 0, nil}
+ case 28:
+ return Event{CtrlBackSlash, 0, nil}
+ case 29:
+ return Event{CtrlRightBracket, 0, nil}
+ case 30:
+ return Event{CtrlCaret, 0, nil}
+ case 31:
+ return Event{CtrlSlash, 0, nil}
+ case ESC.Byte():
+ ev := r.escSequence(&sz)
+ // Second chance
+ if ev.Type == Invalid {
+ r.buffer = r.getBytes()
+ ev = r.escSequence(&sz)
+ }
+ return ev
+ }
+
+ // CTRL-A ~ CTRL-Z
+ if r.buffer[0] <= CtrlZ.Byte() {
+ return Event{EventType(r.buffer[0]), 0, nil}
+ }
+ char, rsz := utf8.DecodeRune(r.buffer)
+ if char == utf8.RuneError {
+ return Event{ESC, 0, nil}
+ }
+ sz = rsz
+ return Event{Rune, char, nil}
+}
+
+func (r *LightRenderer) escSequence(sz *int) Event {
+ if len(r.buffer) < 2 {
+ return Event{ESC, 0, nil}
+ }
+
+ loc := offsetRegexpBegin.FindIndex(r.buffer)
+ if loc != nil && loc[0] == 0 {
+ *sz = loc[1]
+ return Event{Invalid, 0, nil}
+ }
+
+ *sz = 2
+ if r.buffer[1] >= 1 && r.buffer[1] <= 'z'-'a'+1 {
+ return CtrlAltKey(rune(r.buffer[1] + 'a' - 1))
+ }
+ alt := false
+ if len(r.buffer) > 2 && r.buffer[1] == ESC.Byte() {
+ r.buffer = r.buffer[1:]
+ alt = true
+ }
+ switch r.buffer[1] {
+ case ESC.Byte():
+ return Event{ESC, 0, nil}
+ case 127:
+ return Event{AltBS, 0, nil}
+ case '[', 'O':
+ if len(r.buffer) < 3 {
+ return Event{Invalid, 0, nil}
+ }
+ *sz = 3
+ switch r.buffer[2] {
+ case 'D':
+ if alt {
+ return Event{AltLeft, 0, nil}
+ }
+ return Event{Left, 0, nil}
+ case 'C':
+ if alt {
+ // Ugh..
+ return Event{AltRight, 0, nil}
+ }
+ return Event{Right, 0, nil}
+ case 'B':
+ if alt {
+ return Event{AltDown, 0, nil}
+ }
+ return Event{Down, 0, nil}
+ case 'A':
+ if alt {
+ return Event{AltUp, 0, nil}
+ }
+ return Event{Up, 0, nil}
+ case 'Z':
+ return Event{BTab, 0, nil}
+ case 'H':
+ return Event{Home, 0, nil}
+ case 'F':
+ return Event{End, 0, nil}
+ case '<':
+ return r.mouseSequence(sz)
+ case 'P':
+ return Event{F1, 0, nil}
+ case 'Q':
+ return Event{F2, 0, nil}
+ case 'R':
+ return Event{F3, 0, nil}
+ case 'S':
+ return Event{F4, 0, nil}
+ case '1', '2', '3', '4', '5', '6':
+ if len(r.buffer) < 4 {
+ return Event{Invalid, 0, nil}
+ }
+ *sz = 4
+ switch r.buffer[2] {
+ case '2':
+ if r.buffer[3] == '~' {
+ return Event{Insert, 0, nil}
+ }
+ if len(r.buffer) > 4 && r.buffer[4] == '~' {
+ *sz = 5
+ switch r.buffer[3] {
+ case '0':
+ return Event{F9, 0, nil}
+ case '1':
+ return Event{F10, 0, nil}
+ case '3':
+ return Event{F11, 0, nil}
+ case '4':
+ return Event{F12, 0, nil}
+ }
+ }
+ // Bracketed paste mode: \e[200~ ... \e[201~
+ if len(r.buffer) > 5 && r.buffer[3] == '0' && (r.buffer[4] == '0' || r.buffer[4] == '1') && r.buffer[5] == '~' {
+ // Immediately discard the sequence from the buffer and reread input
+ r.buffer = r.buffer[6:]
+ *sz = 0
+ return r.GetChar()
+ }
+ return Event{Invalid, 0, nil} // INS
+ case '3':
+ return Event{Del, 0, nil}
+ case '4':
+ return Event{End, 0, nil}
+ case '5':
+ return Event{PgUp, 0, nil}
+ case '6':
+ return Event{PgDn, 0, nil}
+ case '1':
+ switch r.buffer[3] {
+ case '~':
+ return Event{Home, 0, nil}
+ case '1', '2', '3', '4', '5', '7', '8', '9':
+ if len(r.buffer) == 5 && r.buffer[4] == '~' {
+ *sz = 5
+ switch r.buffer[3] {
+ case '1':
+ return Event{F1, 0, nil}
+ case '2':
+ return Event{F2, 0, nil}
+ case '3':
+ return Event{F3, 0, nil}
+ case '4':
+ return Event{F4, 0, nil}
+ case '5':
+ return Event{F5, 0, nil}
+ case '7':
+ return Event{F6, 0, nil}
+ case '8':
+ return Event{F7, 0, nil}
+ case '9':
+ return Event{F8, 0, nil}
+ }
+ }
+ return Event{Invalid, 0, nil}
+ case ';':
+ if len(r.buffer) < 6 {
+ return Event{Invalid, 0, nil}
+ }
+ *sz = 6
+ switch r.buffer[4] {
+ case '1', '2', '3', '5':
+ alt := r.buffer[4] == '3'
+ altShift := r.buffer[4] == '1' && r.buffer[5] == '0'
+ char := r.buffer[5]
+ if altShift {
+ if len(r.buffer) < 7 {
+ return Event{Invalid, 0, nil}
+ }
+ *sz = 7
+ char = r.buffer[6]
+ }
+ switch char {
+ case 'A':
+ if alt {
+ return Event{AltUp, 0, nil}
+ }
+ if altShift {
+ return Event{AltSUp, 0, nil}
+ }
+ return Event{SUp, 0, nil}
+ case 'B':
+ if alt {
+ return Event{AltDown, 0, nil}
+ }
+ if altShift {
+ return Event{AltSDown, 0, nil}
+ }
+ return Event{SDown, 0, nil}
+ case 'C':
+ if alt {
+ return Event{AltRight, 0, nil}
+ }
+ if altShift {
+ return Event{AltSRight, 0, nil}
+ }
+ return Event{SRight, 0, nil}
+ case 'D':
+ if alt {
+ return Event{AltLeft, 0, nil}
+ }
+ if altShift {
+ return Event{AltSLeft, 0, nil}
+ }
+ return Event{SLeft, 0, nil}
+ }
+ } // r.buffer[4]
+ } // r.buffer[3]
+ } // r.buffer[2]
+ } // r.buffer[2]
+ } // r.buffer[1]
+ rest := bytes.NewBuffer(r.buffer[1:])
+ c, size, err := rest.ReadRune()
+ if err == nil {
+ *sz = 1 + size
+ return AltKey(c)
+ }
+ return Event{Invalid, 0, nil}
+}
+
+// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
+func (r *LightRenderer) mouseSequence(sz *int) Event {
+ // "\e[<0;0;0M"
+ if len(r.buffer) < 9 || !r.mouse {
+ return Event{Invalid, 0, nil}
+ }
+
+ rest := r.buffer[*sz:]
+ end := bytes.IndexAny(rest, "mM")
+ if end == -1 {
+ return Event{Invalid, 0, nil}
+ }
+
+ elems := strings.SplitN(string(rest[:end]), ";", 3)
+ if len(elems) != 3 {
+ return Event{Invalid, 0, nil}
+ }
+
+ t := atoi(elems[0], -1)
+ x := atoi(elems[1], -1) - 1
+ y := atoi(elems[2], -1) - 1 - r.yoffset
+ if t < 0 || x < 0 || y < 0 {
+ return Event{Invalid, 0, nil}
+ }
+ *sz += end + 1
+
+ down := rest[end] == 'M'
+
+ scroll := 0
+ if t >= 64 {
+ t -= 64
+ if t&0b1 == 1 {
+ scroll = -1
+ } else {
+ scroll = 1
+ }
+ }
+
+ // middle := t & 0b1
+ left := t&0b11 == 0
+
+ // shift := t & 0b100
+ // ctrl := t & 0b1000
+ mod := t&0b1100 > 0
+
+ if scroll != 0 {
+ return Event{Mouse, 0, &MouseEvent{y, x, scroll, false, false, false, mod}}
+ }
+
+ double := false
+ if down {
+ now := time.Now()
+ if !left { // Right double click is not allowed
+ r.clickY = []int{}
+ } else if now.Sub(r.prevDownTime) < doubleClickDuration {
+ r.clickY = append(r.clickY, y)
+ } else {
+ r.clickY = []int{y}
+ }
+ r.prevDownTime = now
+ } else {
+ if len(r.clickY) > 1 && r.clickY[0] == r.clickY[1] &&
+ time.Since(r.prevDownTime) < doubleClickDuration {
+ double = true
+ }
+ }
+ return Event{Mouse, 0, &MouseEvent{y, x, 0, left, down, double, mod}}
+}
+
+func (r *LightRenderer) smcup() {
+ r.csi("?1049h")
+}
+
+func (r *LightRenderer) rmcup() {
+ r.csi("?1049l")
+}
+
+func (r *LightRenderer) Pause(clear bool) {
+ r.restoreTerminal()
+ if clear {
+ if r.fullscreen {
+ r.rmcup()
+ } else {
+ r.smcup()
+ r.csi("H")
+ }
+ r.flush()
+ }
+}
+
+func (r *LightRenderer) Resume(clear bool, sigcont bool) {
+ r.setupTerminal()
+ if clear {
+ if r.fullscreen {
+ r.smcup()
+ } else {
+ r.rmcup()
+ }
+ r.flush()
+ } else if sigcont && !r.fullscreen && r.mouse {
+ // NOTE: SIGCONT (Coming back from CTRL-Z):
+ // It's highly likely that the offset we obtained at the beginning is
+ // no longer correct, so we simply disable mouse input.
+ r.csi("?1000l")
+ r.csi("?1006l")
+ r.mouse = false
+ }
+}
+
+func (r *LightRenderer) Clear() {
+ if r.fullscreen {
+ r.csi("H")
+ }
+ // r.csi("u")
+ r.origin()
+ r.csi("J")
+ r.flush()
+}
+
+func (r *LightRenderer) RefreshWindows(windows []Window) {
+ r.flush()
+}
+
+func (r *LightRenderer) Refresh() {
+ r.updateTerminalSize()
+}
+
+func (r *LightRenderer) Close() {
+ // r.csi("u")
+ if r.clearOnExit {
+ if r.fullscreen {
+ r.rmcup()
+ } else {
+ r.origin()
+ if r.upOneLine {
+ r.csi("A")
+ }
+ r.csi("J")
+ }
+ } else if !r.fullscreen {
+ r.csi("u")
+ }
+ if r.mouse {
+ r.csi("?1000l")
+ r.csi("?1006l")
+ }
+ r.flush()
+ r.closePlatform()
+ r.restoreTerminal()
+}
+
+func (r *LightRenderer) MaxX() int {
+ return r.width
+}
+
+func (r *LightRenderer) MaxY() int {
+ return r.height
+}
+
+func (r *LightRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window {
+ w := &LightWindow{
+ renderer: r,
+ colored: r.theme.Colored,
+ preview: preview,
+ border: borderStyle,
+ top: top,
+ left: left,
+ width: width,
+ height: height,
+ tabstop: r.tabstop,
+ fg: colDefault,
+ bg: colDefault}
+ if preview {
+ w.fg = r.theme.PreviewFg.Color
+ w.bg = r.theme.PreviewBg.Color
+ } else {
+ w.fg = r.theme.Fg.Color
+ w.bg = r.theme.Bg.Color
+ }
+ w.drawBorder()
+ return w
+}
+
+func (w *LightWindow) drawBorder() {
+ switch w.border.shape {
+ case BorderRounded, BorderSharp:
+ w.drawBorderAround()
+ case BorderHorizontal:
+ w.drawBorderHorizontal(true, true)
+ case BorderVertical:
+ w.drawBorderVertical(true, true)
+ case BorderTop:
+ w.drawBorderHorizontal(true, false)
+ case BorderBottom:
+ w.drawBorderHorizontal(false, true)
+ case BorderLeft:
+ w.drawBorderVertical(true, false)
+ case BorderRight:
+ w.drawBorderVertical(false, true)
+ }
+}
+
+func (w *LightWindow) drawBorderHorizontal(top, bottom bool) {
+ color := ColBorder
+ if w.preview {
+ color = ColPreviewBorder
+ }
+ if top {
+ w.Move(0, 0)
+ w.CPrint(color, repeat(w.border.horizontal, w.width))
+ }
+ if bottom {
+ w.Move(w.height-1, 0)
+ w.CPrint(color, repeat(w.border.horizontal, w.width))
+ }
+}
+
+func (w *LightWindow) drawBorderVertical(left, right bool) {
+ width := w.width - 2
+ if !left || !right {
+ width++
+ }
+ color := ColBorder
+ if w.preview {
+ color = ColPreviewBorder
+ }
+ for y := 0; y < w.height; y++ {
+ w.Move(y, 0)
+ if left {
+ w.CPrint(color, string(w.border.vertical))
+ }
+ w.CPrint(color, repeat(' ', width))
+ if right {
+ w.CPrint(color, string(w.border.vertical))
+ }
+ }
+}
+
+func (w *LightWindow) drawBorderAround() {
+ w.Move(0, 0)
+ color := ColBorder
+ if w.preview {
+ color = ColPreviewBorder
+ }
+ w.CPrint(color, string(w.border.topLeft)+repeat(w.border.horizontal, w.width-2)+string(w.border.topRight))
+ for y := 1; y < w.height-1; y++ {
+ w.Move(y, 0)
+ w.CPrint(color, string(w.border.vertical))
+ w.CPrint(color, repeat(' ', w.width-2))
+ w.CPrint(color, string(w.border.vertical))
+ }
+ w.Move(w.height-1, 0)
+ w.CPrint(color, string(w.border.bottomLeft)+repeat(w.border.horizontal, w.width-2)+string(w.border.bottomRight))
+}
+
+func (w *LightWindow) csi(code string) {
+ w.renderer.csi(code)
+}
+
+func (w *LightWindow) stderrInternal(str string, allowNLCR bool) {
+ w.renderer.stderrInternal(str, allowNLCR)
+}
+
+func (w *LightWindow) Top() int {
+ return w.top
+}
+
+func (w *LightWindow) Left() int {
+ return w.left
+}
+
+func (w *LightWindow) Width() int {
+ return w.width
+}
+
+func (w *LightWindow) Height() int {
+ return w.height
+}
+
+func (w *LightWindow) Refresh() {
+}
+
+func (w *LightWindow) Close() {
+}
+
+func (w *LightWindow) X() int {
+ return w.posx
+}
+
+func (w *LightWindow) Y() int {
+ return w.posy
+}
+
+func (w *LightWindow) Enclose(y int, x int) bool {
+ return x >= w.left && x < (w.left+w.width) &&
+ y >= w.top && y < (w.top+w.height)
+}
+
+func (w *LightWindow) Move(y int, x int) {
+ w.posx = x
+ w.posy = y
+
+ w.renderer.move(w.Top()+y, w.Left()+x)
+}
+
+func (w *LightWindow) MoveAndClear(y int, x int) {
+ w.Move(y, x)
+ // We should not delete preview window on the right
+ // csi("K")
+ w.Print(repeat(' ', w.width-x))
+ w.Move(y, x)
+}
+
+func attrCodes(attr Attr) []string {
+ codes := []string{}
+ if (attr & AttrClear) > 0 {
+ return codes
+ }
+ if (attr & Bold) > 0 {
+ codes = append(codes, "1")
+ }
+ if (attr & Dim) > 0 {
+ codes = append(codes, "2")
+ }
+ if (attr & Italic) > 0 {
+ codes = append(codes, "3")
+ }
+ if (attr & Underline) > 0 {
+ codes = append(codes, "4")
+ }
+ if (attr & Blink) > 0 {
+ codes = append(codes, "5")
+ }
+ if (attr & Reverse) > 0 {
+ codes = append(codes, "7")
+ }
+ if (attr & StrikeThrough) > 0 {
+ codes = append(codes, "9")
+ }
+ return codes
+}
+
+func colorCodes(fg Color, bg Color) []string {
+ codes := []string{}
+ appendCode := func(c Color, offset int) {
+ if c == colDefault {
+ return
+ }
+ if c.is24() {
+ r := (c >> 16) & 0xff
+ g := (c >> 8) & 0xff
+ b := (c) & 0xff
+ codes = append(codes, fmt.Sprintf("%d;2;%d;%d;%d", 38+offset, r, g, b))
+ } else if c >= colBlack && c <= colWhite {
+ codes = append(codes, fmt.Sprintf("%d", int(c)+30+offset))
+ } else if c > colWhite && c < 16 {
+ codes = append(codes, fmt.Sprintf("%d", int(c)+90+offset-8))
+ } else if c >= 16 && c < 256 {
+ codes = append(codes, fmt.Sprintf("%d;5;%d", 38+offset, c))
+ }
+ }
+ appendCode(fg, 0)
+ appendCode(bg, 10)
+ return codes
+}
+
+func (w *LightWindow) csiColor(fg Color, bg Color, attr Attr) bool {
+ codes := append(attrCodes(attr), colorCodes(fg, bg)...)
+ w.csi(";" + strings.Join(codes, ";") + "m")
+ return len(codes) > 0
+}
+
+func (w *LightWindow) Print(text string) {
+ w.cprint2(colDefault, w.bg, AttrRegular, text)
+}
+
+func cleanse(str string) string {
+ return strings.Replace(str, "\x1b", "", -1)
+}
+
+func (w *LightWindow) CPrint(pair ColorPair, text string) {
+ w.csiColor(pair.Fg(), pair.Bg(), pair.Attr())
+ w.stderrInternal(cleanse(text), false)
+ w.csi("m")
+}
+
+func (w *LightWindow) cprint2(fg Color, bg Color, attr Attr, text string) {
+ if w.csiColor(fg, bg, attr) {
+ defer w.csi("m")
+ }
+ w.stderrInternal(cleanse(text), false)
+}
+
+type wrappedLine struct {
+ text string
+ displayWidth int
+}
+
+func wrapLine(input string, prefixLength int, max int, tabstop int) []wrappedLine {
+ lines := []wrappedLine{}
+ width := 0
+ line := ""
+ gr := uniseg.NewGraphemes(input)
+ for gr.Next() {
+ rs := gr.Runes()
+ str := string(rs)
+ var w int
+ if len(rs) == 1 && rs[0] == '\t' {
+ w = tabstop - (prefixLength+width)%tabstop
+ str = repeat(' ', w)
+ } else {
+ w = runewidth.StringWidth(str)
+ }
+ width += w
+
+ if prefixLength+width <= max {
+ line += str
+ } else {
+ lines = append(lines, wrappedLine{string(line), width - w})
+ line = str
+ prefixLength = 0
+ width = w
+ }
+ }
+ lines = append(lines, wrappedLine{string(line), width})
+ return lines
+}
+
+func (w *LightWindow) fill(str string, onMove func()) FillReturn {
+ allLines := strings.Split(str, "\n")
+ for i, line := range allLines {
+ lines := wrapLine(line, w.posx, w.width, w.tabstop)
+ for j, wl := range lines {
+ w.stderrInternal(wl.text, false)
+ w.posx += wl.displayWidth
+
+ // Wrap line
+ if j < len(lines)-1 || i < len(allLines)-1 {
+ if w.posy+1 >= w.height {
+ return FillSuspend
+ }
+ w.MoveAndClear(w.posy, w.posx)
+ w.Move(w.posy+1, 0)
+ onMove()
+ }
+ }
+ }
+ if w.posx+1 >= w.Width() {
+ if w.posy+1 >= w.height {
+ return FillSuspend
+ }
+ w.Move(w.posy+1, 0)
+ onMove()
+ return FillNextLine
+ }
+ return FillContinue
+}
+
+func (w *LightWindow) setBg() {
+ if w.bg != colDefault {
+ w.csiColor(colDefault, w.bg, AttrRegular)
+ }
+}
+
+func (w *LightWindow) Fill(text string) FillReturn {
+ w.Move(w.posy, w.posx)
+ w.setBg()
+ return w.fill(text, w.setBg)
+}
+
+func (w *LightWindow) CFill(fg Color, bg Color, attr Attr, text string) FillReturn {
+ w.Move(w.posy, w.posx)
+ if fg == colDefault {
+ fg = w.fg
+ }
+ if bg == colDefault {
+ bg = w.bg
+ }
+ if w.csiColor(fg, bg, attr) {
+ defer w.csi("m")
+ return w.fill(text, func() { w.csiColor(fg, bg, attr) })
+ }
+ return w.fill(text, w.setBg)
+}
+
+func (w *LightWindow) FinishFill() {
+ w.MoveAndClear(w.posy, w.posx)
+ for y := w.posy + 1; y < w.height; y++ {
+ w.MoveAndClear(y, 0)
+ }
+}
+
+func (w *LightWindow) Erase() {
+ w.drawBorder()
+ // We don't erase the window here to avoid flickering during scroll
+ w.Move(0, 0)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/light_unix.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/light_unix.go
new file mode 100644
index 00000000..6dc058c8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/light_unix.go
@@ -0,0 +1,110 @@
+//go:build !windows
+
+package tui
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+ "syscall"
+
+ "github.com/junegunn/fzf/src/util"
+ "golang.org/x/term"
+)
+
+func IsLightRendererSupported() bool {
+ return true
+}
+
+func (r *LightRenderer) defaultTheme() *ColorTheme {
+ if strings.Contains(os.Getenv("TERM"), "256") {
+ return Dark256
+ }
+ colors, err := exec.Command("tput", "colors").Output()
+ if err == nil && atoi(strings.TrimSpace(string(colors)), 16) > 16 {
+ return Dark256
+ }
+ return Default16
+}
+
+func (r *LightRenderer) fd() int {
+ return int(r.ttyin.Fd())
+}
+
+func (r *LightRenderer) initPlatform() error {
+ fd := r.fd()
+ origState, err := term.GetState(fd)
+ if err != nil {
+ return err
+ }
+ r.origState = origState
+ term.MakeRaw(fd)
+ return nil
+}
+
+func (r *LightRenderer) closePlatform() {
+ // NOOP
+}
+
+func openTtyIn() *os.File {
+ in, err := os.OpenFile(consoleDevice, syscall.O_RDONLY, 0)
+ if err != nil {
+ tty := ttyname()
+ if len(tty) > 0 {
+ if in, err := os.OpenFile(tty, syscall.O_RDONLY, 0); err == nil {
+ return in
+ }
+ }
+ fmt.Fprintln(os.Stderr, "Failed to open "+consoleDevice)
+ os.Exit(2)
+ }
+ return in
+}
+
+func (r *LightRenderer) setupTerminal() {
+ term.MakeRaw(r.fd())
+}
+
+func (r *LightRenderer) restoreTerminal() {
+ term.Restore(r.fd(), r.origState)
+}
+
+func (r *LightRenderer) updateTerminalSize() {
+ width, height, err := term.GetSize(r.fd())
+
+ if err == nil {
+ r.width = width
+ r.height = r.maxHeightFunc(height)
+ } else {
+ r.width = getEnv("COLUMNS", defaultWidth)
+ r.height = r.maxHeightFunc(getEnv("LINES", defaultHeight))
+ }
+}
+
+func (r *LightRenderer) findOffset() (row int, col int) {
+ r.csi("6n")
+ r.flush()
+ bytes := []byte{}
+ for tries := 0; tries < offsetPollTries; tries++ {
+ bytes = r.getBytesInternal(bytes, tries > 0)
+ offsets := offsetRegexp.FindSubmatch(bytes)
+ if len(offsets) > 3 {
+ // Add anything we skipped over to the input buffer
+ r.buffer = append(r.buffer, offsets[1]...)
+ return atoi(string(offsets[2]), 0) - 1, atoi(string(offsets[3]), 0) - 1
+ }
+ }
+ return -1, -1
+}
+
+func (r *LightRenderer) getch(nonblock bool) (int, bool) {
+ b := make([]byte, 1)
+ fd := r.fd()
+ util.SetNonblock(r.ttyin, nonblock)
+ _, err := util.Read(fd, b)
+ if err != nil {
+ return 0, false
+ }
+ return int(b[0]), true
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/light_windows.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/light_windows.go
new file mode 100644
index 00000000..db829d3a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/light_windows.go
@@ -0,0 +1,145 @@
+//go:build windows
+
+package tui
+
+import (
+ "os"
+ "syscall"
+ "time"
+
+ "github.com/junegunn/fzf/src/util"
+ "golang.org/x/sys/windows"
+)
+
+const (
+ timeoutInterval = 10
+)
+
+var (
+ consoleFlagsInput = uint32(windows.ENABLE_VIRTUAL_TERMINAL_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_EXTENDED_FLAGS)
+ consoleFlagsOutput = uint32(windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | windows.ENABLE_PROCESSED_OUTPUT | windows.DISABLE_NEWLINE_AUTO_RETURN)
+)
+
+// IsLightRendererSupported checks to see if the Light renderer is supported
+func IsLightRendererSupported() bool {
+ var oldState uint32
+ // enable vt100 emulation (https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences)
+ if windows.GetConsoleMode(windows.Stderr, &oldState) != nil {
+ return false
+ }
+ // attempt to set mode to determine if we support VT 100 codes. This will work on newer Windows 10
+ // version:
+ canSetVt100 := windows.SetConsoleMode(windows.Stderr, oldState|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) == nil
+ var checkState uint32
+ if windows.GetConsoleMode(windows.Stderr, &checkState) != nil ||
+ (checkState&windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) != windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING {
+ return false
+ }
+ windows.SetConsoleMode(windows.Stderr, oldState)
+ return canSetVt100
+}
+
+func (r *LightRenderer) defaultTheme() *ColorTheme {
+ // the getenv check is borrowed from here: https://github.com/gdamore/tcell/commit/0c473b86d82f68226a142e96cc5a34c5a29b3690#diff-b008fcd5e6934bf31bc3d33bf49f47d8R178:
+ if !IsLightRendererSupported() || os.Getenv("ConEmuPID") != "" || os.Getenv("TCELL_TRUECOLOR") == "disable" {
+ return Default16
+ }
+ return Dark256
+}
+
+func (r *LightRenderer) initPlatform() error {
+ //outHandle := windows.Stdout
+ outHandle, _ := syscall.Open("CONOUT$", syscall.O_RDWR, 0)
+ // enable vt100 emulation (https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences)
+ if err := windows.GetConsoleMode(windows.Handle(outHandle), &r.origStateOutput); err != nil {
+ return err
+ }
+ r.outHandle = uintptr(outHandle)
+ inHandle, _ := syscall.Open("CONIN$", syscall.O_RDWR, 0)
+ if err := windows.GetConsoleMode(windows.Handle(inHandle), &r.origStateInput); err != nil {
+ return err
+ }
+ r.inHandle = uintptr(inHandle)
+
+ r.setupTerminal()
+
+ // channel for non-blocking reads. Buffer to make sure
+ // we get the ESC sets:
+ r.ttyinChannel = make(chan byte, 1024)
+
+ // the following allows for non-blocking IO.
+ // syscall.SetNonblock() is a NOOP under Windows.
+ go func() {
+ fd := int(r.inHandle)
+ b := make([]byte, 1)
+ for {
+ // HACK: if run from PSReadline, something resets ConsoleMode to remove ENABLE_VIRTUAL_TERMINAL_INPUT.
+ _ = windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput)
+
+ _, err := util.Read(fd, b)
+ if err == nil {
+ r.ttyinChannel <- b[0]
+ }
+ }
+ }()
+
+ return nil
+}
+
+func (r *LightRenderer) closePlatform() {
+ windows.SetConsoleMode(windows.Handle(r.outHandle), r.origStateOutput)
+ windows.SetConsoleMode(windows.Handle(r.inHandle), r.origStateInput)
+}
+
+func openTtyIn() *os.File {
+ // not used
+ return nil
+}
+
+func (r *LightRenderer) setupTerminal() error {
+ if err := windows.SetConsoleMode(windows.Handle(r.outHandle), consoleFlagsOutput); err != nil {
+ return err
+ }
+ return windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput)
+}
+
+func (r *LightRenderer) restoreTerminal() error {
+ if err := windows.SetConsoleMode(windows.Handle(r.inHandle), r.origStateInput); err != nil {
+ return err
+ }
+ return windows.SetConsoleMode(windows.Handle(r.outHandle), r.origStateOutput)
+}
+
+func (r *LightRenderer) updateTerminalSize() {
+ var bufferInfo windows.ConsoleScreenBufferInfo
+ if err := windows.GetConsoleScreenBufferInfo(windows.Handle(r.outHandle), &bufferInfo); err != nil {
+ r.width = getEnv("COLUMNS", defaultWidth)
+ r.height = r.maxHeightFunc(getEnv("LINES", defaultHeight))
+
+ } else {
+ r.width = int(bufferInfo.Window.Right - bufferInfo.Window.Left)
+ r.height = r.maxHeightFunc(int(bufferInfo.Window.Bottom - bufferInfo.Window.Top))
+ }
+}
+
+func (r *LightRenderer) findOffset() (row int, col int) {
+ var bufferInfo windows.ConsoleScreenBufferInfo
+ if err := windows.GetConsoleScreenBufferInfo(windows.Handle(r.outHandle), &bufferInfo); err != nil {
+ return -1, -1
+ }
+ return int(bufferInfo.CursorPosition.X), int(bufferInfo.CursorPosition.Y)
+}
+
+func (r *LightRenderer) getch(nonblock bool) (int, bool) {
+ if nonblock {
+ select {
+ case bc := <-r.ttyinChannel:
+ return int(bc), true
+ case <-time.After(timeoutInterval * time.Millisecond):
+ return 0, false
+ }
+ } else {
+ bc := <-r.ttyinChannel
+ return int(bc), true
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tcell.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tcell.go
new file mode 100644
index 00000000..a873378d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tcell.go
@@ -0,0 +1,732 @@
+//go:build tcell || windows
+
+package tui
+
+import (
+ "os"
+ "time"
+
+ "runtime"
+
+ "github.com/gdamore/tcell/v2"
+ "github.com/gdamore/tcell/v2/encoding"
+
+ "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
+)
+
+func HasFullscreenRenderer() bool {
+ return true
+}
+
+func asTcellColor(color Color) tcell.Color {
+ value := uint64(tcell.ColorValid) + uint64(color)
+ if color.is24() {
+ value = value | uint64(tcell.ColorIsRGB)
+ }
+ return tcell.Color(value)
+}
+
+func (p ColorPair) style() tcell.Style {
+ style := tcell.StyleDefault
+ return style.Foreground(asTcellColor(p.Fg())).Background(asTcellColor(p.Bg()))
+}
+
+type Attr int32
+
+type TcellWindow struct {
+ color bool
+ preview bool
+ top int
+ left int
+ width int
+ height int
+ normal ColorPair
+ lastX int
+ lastY int
+ moveCursor bool
+ borderStyle BorderStyle
+}
+
+func (w *TcellWindow) Top() int {
+ return w.top
+}
+
+func (w *TcellWindow) Left() int {
+ return w.left
+}
+
+func (w *TcellWindow) Width() int {
+ return w.width
+}
+
+func (w *TcellWindow) Height() int {
+ return w.height
+}
+
+func (w *TcellWindow) Refresh() {
+ if w.moveCursor {
+ _screen.ShowCursor(w.left+w.lastX, w.top+w.lastY)
+ w.moveCursor = false
+ }
+ w.lastX = 0
+ w.lastY = 0
+
+ w.drawBorder()
+}
+
+func (w *TcellWindow) FinishFill() {
+ // NO-OP
+}
+
+const (
+ Bold Attr = Attr(tcell.AttrBold)
+ Dim = Attr(tcell.AttrDim)
+ Blink = Attr(tcell.AttrBlink)
+ Reverse = Attr(tcell.AttrReverse)
+ Underline = Attr(tcell.AttrUnderline)
+ StrikeThrough = Attr(tcell.AttrStrikeThrough)
+ Italic = Attr(tcell.AttrItalic)
+)
+
+const (
+ AttrUndefined = Attr(0)
+ AttrRegular = Attr(1 << 7)
+ AttrClear = Attr(1 << 8)
+)
+
+func (r *FullscreenRenderer) defaultTheme() *ColorTheme {
+ if _screen.Colors() >= 256 {
+ return Dark256
+ }
+ return Default16
+}
+
+var (
+ _colorToAttribute = []tcell.Color{
+ tcell.ColorBlack,
+ tcell.ColorRed,
+ tcell.ColorGreen,
+ tcell.ColorYellow,
+ tcell.ColorBlue,
+ tcell.ColorDarkMagenta,
+ tcell.ColorLightCyan,
+ tcell.ColorWhite,
+ }
+)
+
+func (c Color) Style() tcell.Color {
+ if c <= colDefault {
+ return tcell.ColorDefault
+ } else if c >= colBlack && c <= colWhite {
+ return _colorToAttribute[int(c)]
+ } else {
+ return tcell.Color(c)
+ }
+}
+
+func (a Attr) Merge(b Attr) Attr {
+ return a | b
+}
+
+// handle the following as private members of FullscreenRenderer instance
+// they are declared here to prevent introducing tcell library in non-windows builds
+var (
+ _screen tcell.Screen
+ _prevMouseButton tcell.ButtonMask
+)
+
+func (r *FullscreenRenderer) initScreen() {
+ s, e := tcell.NewScreen()
+ if e != nil {
+ errorExit(e.Error())
+ }
+ if e = s.Init(); e != nil {
+ errorExit(e.Error())
+ }
+ if r.mouse {
+ s.EnableMouse()
+ } else {
+ s.DisableMouse()
+ }
+ _screen = s
+}
+
+func (r *FullscreenRenderer) Init() {
+ if os.Getenv("TERM") == "cygwin" {
+ os.Setenv("TERM", "")
+ }
+ encoding.Register()
+
+ r.initScreen()
+ initTheme(r.theme, r.defaultTheme(), r.forceBlack)
+}
+
+func (r *FullscreenRenderer) MaxX() int {
+ ncols, _ := _screen.Size()
+ return int(ncols)
+}
+
+func (r *FullscreenRenderer) MaxY() int {
+ _, nlines := _screen.Size()
+ return int(nlines)
+}
+
+func (w *TcellWindow) X() int {
+ return w.lastX
+}
+
+func (w *TcellWindow) Y() int {
+ return w.lastY
+}
+
+func (r *FullscreenRenderer) Clear() {
+ _screen.Sync()
+ _screen.Clear()
+}
+
+func (r *FullscreenRenderer) Refresh() {
+ // noop
+}
+
+func (r *FullscreenRenderer) GetChar() Event {
+ ev := _screen.PollEvent()
+ switch ev := ev.(type) {
+ case *tcell.EventResize:
+ return Event{Resize, 0, nil}
+
+ // process mouse events:
+ case *tcell.EventMouse:
+ // mouse down events have zeroed buttons, so we can't use them
+ // mouse up event consists of two events, 1. (main) event with modifier and other metadata, 2. event with zeroed buttons
+ // so mouse click is three consecutive events, but the first and last are indistinguishable from movement events (with released buttons)
+ // dragging has same structure, it only repeats the middle (main) event appropriately
+ x, y := ev.Position()
+ mod := ev.Modifiers() != 0
+
+ // since we dont have mouse down events (unlike LightRenderer), we need to track state in prevButton
+ prevButton, button := _prevMouseButton, ev.Buttons()
+ _prevMouseButton = button
+ drag := prevButton == button
+
+ switch {
+ case button&tcell.WheelDown != 0:
+ return Event{Mouse, 0, &MouseEvent{y, x, -1, false, false, false, mod}}
+ case button&tcell.WheelUp != 0:
+ return Event{Mouse, 0, &MouseEvent{y, x, +1, false, false, false, mod}}
+ case button&tcell.Button1 != 0 && !drag:
+ // all potential double click events put their 'line' coordinate in the clickY array
+ // double click event has two conditions, temporal and spatial, the first is checked here
+ now := time.Now()
+ if now.Sub(r.prevDownTime) < doubleClickDuration {
+ r.clickY = append(r.clickY, y)
+ } else {
+ r.clickY = []int{y}
+ }
+ r.prevDownTime = now
+
+ // detect double clicks (also check for spatial condition)
+ n := len(r.clickY)
+ double := n > 1 && r.clickY[n-2] == r.clickY[n-1]
+ if double {
+ // make sure two consecutive double clicks require four clicks
+ r.clickY = []int{}
+ }
+
+ // fire single or double click event
+ return Event{Mouse, 0, &MouseEvent{y, x, 0, true, !double, double, mod}}
+ case button&tcell.Button2 != 0 && !drag:
+ return Event{Mouse, 0, &MouseEvent{y, x, 0, false, true, false, mod}}
+ case runtime.GOOS != "windows":
+
+ // double and single taps on Windows don't quite work due to
+ // the console acting on the events and not allowing us
+ // to consume them.
+
+ left := button&tcell.Button1 != 0
+ down := left || button&tcell.Button3 != 0
+ double := false
+ if down {
+ now := time.Now()
+ if !left {
+ r.clickY = []int{}
+ } else if now.Sub(r.prevDownTime) < doubleClickDuration {
+ r.clickY = append(r.clickY, x)
+ } else {
+ r.clickY = []int{x}
+ r.prevDownTime = now
+ }
+ } else {
+ if len(r.clickY) > 1 && r.clickY[0] == r.clickY[1] &&
+ time.Now().Sub(r.prevDownTime) < doubleClickDuration {
+ double = true
+ }
+ }
+
+ return Event{Mouse, 0, &MouseEvent{y, x, 0, left, down, double, mod}}
+ }
+
+ // process keyboard:
+ case *tcell.EventKey:
+ mods := ev.Modifiers()
+ none := mods == tcell.ModNone
+ alt := (mods & tcell.ModAlt) > 0
+ ctrl := (mods & tcell.ModCtrl) > 0
+ shift := (mods & tcell.ModShift) > 0
+ ctrlAlt := ctrl && alt
+ altShift := alt && shift
+
+ keyfn := func(r rune) Event {
+ if alt {
+ return CtrlAltKey(r)
+ }
+ return EventType(CtrlA.Int() - 'a' + int(r)).AsEvent()
+ }
+ switch ev.Key() {
+ // section 1: Ctrl+(Alt)+[a-z]
+ case tcell.KeyCtrlA:
+ return keyfn('a')
+ case tcell.KeyCtrlB:
+ return keyfn('b')
+ case tcell.KeyCtrlC:
+ return keyfn('c')
+ case tcell.KeyCtrlD:
+ return keyfn('d')
+ case tcell.KeyCtrlE:
+ return keyfn('e')
+ case tcell.KeyCtrlF:
+ return keyfn('f')
+ case tcell.KeyCtrlG:
+ return keyfn('g')
+ case tcell.KeyCtrlH:
+ switch ev.Rune() {
+ case 0:
+ if ctrl {
+ return Event{BSpace, 0, nil}
+ }
+ case rune(tcell.KeyCtrlH):
+ switch {
+ case ctrl:
+ return keyfn('h')
+ case alt:
+ return Event{AltBS, 0, nil}
+ case none, shift:
+ return Event{BSpace, 0, nil}
+ }
+ }
+ case tcell.KeyCtrlI:
+ return keyfn('i')
+ case tcell.KeyCtrlJ:
+ return keyfn('j')
+ case tcell.KeyCtrlK:
+ return keyfn('k')
+ case tcell.KeyCtrlL:
+ return keyfn('l')
+ case tcell.KeyCtrlM:
+ return keyfn('m')
+ case tcell.KeyCtrlN:
+ return keyfn('n')
+ case tcell.KeyCtrlO:
+ return keyfn('o')
+ case tcell.KeyCtrlP:
+ return keyfn('p')
+ case tcell.KeyCtrlQ:
+ return keyfn('q')
+ case tcell.KeyCtrlR:
+ return keyfn('r')
+ case tcell.KeyCtrlS:
+ return keyfn('s')
+ case tcell.KeyCtrlT:
+ return keyfn('t')
+ case tcell.KeyCtrlU:
+ return keyfn('u')
+ case tcell.KeyCtrlV:
+ return keyfn('v')
+ case tcell.KeyCtrlW:
+ return keyfn('w')
+ case tcell.KeyCtrlX:
+ return keyfn('x')
+ case tcell.KeyCtrlY:
+ return keyfn('y')
+ case tcell.KeyCtrlZ:
+ return keyfn('z')
+ // section 2: Ctrl+[ \]_]
+ case tcell.KeyCtrlSpace:
+ return Event{CtrlSpace, 0, nil}
+ case tcell.KeyCtrlBackslash:
+ return Event{CtrlBackSlash, 0, nil}
+ case tcell.KeyCtrlRightSq:
+ return Event{CtrlRightBracket, 0, nil}
+ case tcell.KeyCtrlCarat:
+ return Event{CtrlCaret, 0, nil}
+ case tcell.KeyCtrlUnderscore:
+ return Event{CtrlSlash, 0, nil}
+ // section 3: (Alt)+Backspace2
+ case tcell.KeyBackspace2:
+ if alt {
+ return Event{AltBS, 0, nil}
+ }
+ return Event{BSpace, 0, nil}
+
+ // section 4: (Alt+Shift)+Key(Up|Down|Left|Right)
+ case tcell.KeyUp:
+ if altShift {
+ return Event{AltSUp, 0, nil}
+ }
+ if shift {
+ return Event{SUp, 0, nil}
+ }
+ if alt {
+ return Event{AltUp, 0, nil}
+ }
+ return Event{Up, 0, nil}
+ case tcell.KeyDown:
+ if altShift {
+ return Event{AltSDown, 0, nil}
+ }
+ if shift {
+ return Event{SDown, 0, nil}
+ }
+ if alt {
+ return Event{AltDown, 0, nil}
+ }
+ return Event{Down, 0, nil}
+ case tcell.KeyLeft:
+ if altShift {
+ return Event{AltSLeft, 0, nil}
+ }
+ if shift {
+ return Event{SLeft, 0, nil}
+ }
+ if alt {
+ return Event{AltLeft, 0, nil}
+ }
+ return Event{Left, 0, nil}
+ case tcell.KeyRight:
+ if altShift {
+ return Event{AltSRight, 0, nil}
+ }
+ if shift {
+ return Event{SRight, 0, nil}
+ }
+ if alt {
+ return Event{AltRight, 0, nil}
+ }
+ return Event{Right, 0, nil}
+
+ // section 5: (Insert|Home|Delete|End|PgUp|PgDn|BackTab|F1-F12)
+ case tcell.KeyInsert:
+ return Event{Insert, 0, nil}
+ case tcell.KeyHome:
+ return Event{Home, 0, nil}
+ case tcell.KeyDelete:
+ return Event{Del, 0, nil}
+ case tcell.KeyEnd:
+ return Event{End, 0, nil}
+ case tcell.KeyPgUp:
+ return Event{PgUp, 0, nil}
+ case tcell.KeyPgDn:
+ return Event{PgDn, 0, nil}
+ case tcell.KeyBacktab:
+ return Event{BTab, 0, nil}
+ case tcell.KeyF1:
+ return Event{F1, 0, nil}
+ case tcell.KeyF2:
+ return Event{F2, 0, nil}
+ case tcell.KeyF3:
+ return Event{F3, 0, nil}
+ case tcell.KeyF4:
+ return Event{F4, 0, nil}
+ case tcell.KeyF5:
+ return Event{F5, 0, nil}
+ case tcell.KeyF6:
+ return Event{F6, 0, nil}
+ case tcell.KeyF7:
+ return Event{F7, 0, nil}
+ case tcell.KeyF8:
+ return Event{F8, 0, nil}
+ case tcell.KeyF9:
+ return Event{F9, 0, nil}
+ case tcell.KeyF10:
+ return Event{F10, 0, nil}
+ case tcell.KeyF11:
+ return Event{F11, 0, nil}
+ case tcell.KeyF12:
+ return Event{F12, 0, nil}
+
+ // section 6: (Ctrl+Alt)+'rune'
+ case tcell.KeyRune:
+ r := ev.Rune()
+
+ switch {
+ // translate native key events to ascii control characters
+ case r == ' ' && ctrl:
+ return Event{CtrlSpace, 0, nil}
+ // handle AltGr characters
+ case ctrlAlt:
+ return Event{Rune, r, nil} // dropping modifiers
+ // simple characters (possibly with modifier)
+ case alt:
+ return AltKey(r)
+ default:
+ return Event{Rune, r, nil}
+ }
+
+ // section 7: Esc
+ case tcell.KeyEsc:
+ return Event{ESC, 0, nil}
+ }
+ }
+
+ // section 8: Invalid
+ return Event{Invalid, 0, nil}
+}
+
+func (r *FullscreenRenderer) Pause(clear bool) {
+ if clear {
+ _screen.Fini()
+ }
+}
+
+func (r *FullscreenRenderer) Resume(clear bool, sigcont bool) {
+ if clear {
+ r.initScreen()
+ }
+}
+
+func (r *FullscreenRenderer) Close() {
+ _screen.Fini()
+}
+
+func (r *FullscreenRenderer) RefreshWindows(windows []Window) {
+ // TODO
+ for _, w := range windows {
+ w.Refresh()
+ }
+ _screen.Show()
+}
+
+func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window {
+ normal := ColNormal
+ if preview {
+ normal = ColPreview
+ }
+ return &TcellWindow{
+ color: r.theme.Colored,
+ preview: preview,
+ top: top,
+ left: left,
+ width: width,
+ height: height,
+ normal: normal,
+ borderStyle: borderStyle}
+}
+
+func (w *TcellWindow) Close() {
+ // TODO
+}
+
+func fill(x, y, w, h int, n ColorPair, r rune) {
+ for ly := 0; ly <= h; ly++ {
+ for lx := 0; lx <= w; lx++ {
+ _screen.SetContent(x+lx, y+ly, r, nil, n.style())
+ }
+ }
+}
+
+func (w *TcellWindow) Erase() {
+ fill(w.left-1, w.top, w.width+1, w.height, w.normal, ' ')
+}
+
+func (w *TcellWindow) Enclose(y int, x int) bool {
+ return x >= w.left && x < (w.left+w.width) &&
+ y >= w.top && y < (w.top+w.height)
+}
+
+func (w *TcellWindow) Move(y int, x int) {
+ w.lastX = x
+ w.lastY = y
+ w.moveCursor = true
+}
+
+func (w *TcellWindow) MoveAndClear(y int, x int) {
+ w.Move(y, x)
+ for i := w.lastX; i < w.width; i++ {
+ _screen.SetContent(i+w.left, w.lastY+w.top, rune(' '), nil, w.normal.style())
+ }
+ w.lastX = x
+}
+
+func (w *TcellWindow) Print(text string) {
+ w.printString(text, w.normal)
+}
+
+func (w *TcellWindow) printString(text string, pair ColorPair) {
+ lx := 0
+ a := pair.Attr()
+
+ style := pair.style()
+ if a&AttrClear == 0 {
+ style = style.
+ Reverse(a&Attr(tcell.AttrReverse) != 0).
+ Underline(a&Attr(tcell.AttrUnderline) != 0).
+ StrikeThrough(a&Attr(tcell.AttrStrikeThrough) != 0).
+ Italic(a&Attr(tcell.AttrItalic) != 0).
+ Blink(a&Attr(tcell.AttrBlink) != 0).
+ Dim(a&Attr(tcell.AttrDim) != 0)
+ }
+
+ gr := uniseg.NewGraphemes(text)
+ for gr.Next() {
+ rs := gr.Runes()
+
+ if len(rs) == 1 {
+ r := rs[0]
+ if r < rune(' ') { // ignore control characters
+ continue
+ } else if r == '\n' {
+ w.lastY++
+ lx = 0
+ continue
+ } else if r == '\u000D' { // skip carriage return
+ continue
+ }
+ }
+ var xPos = w.left + w.lastX + lx
+ var yPos = w.top + w.lastY
+ if xPos < (w.left+w.width) && yPos < (w.top+w.height) {
+ _screen.SetContent(xPos, yPos, rs[0], rs[1:], style)
+ }
+ lx += runewidth.StringWidth(string(rs))
+ }
+ w.lastX += lx
+}
+
+func (w *TcellWindow) CPrint(pair ColorPair, text string) {
+ w.printString(text, pair)
+}
+
+func (w *TcellWindow) fillString(text string, pair ColorPair) FillReturn {
+ lx := 0
+ a := pair.Attr()
+
+ var style tcell.Style
+ if w.color {
+ style = pair.style()
+ } else {
+ style = w.normal.style()
+ }
+ style = style.
+ Blink(a&Attr(tcell.AttrBlink) != 0).
+ Bold(a&Attr(tcell.AttrBold) != 0).
+ Dim(a&Attr(tcell.AttrDim) != 0).
+ Reverse(a&Attr(tcell.AttrReverse) != 0).
+ Underline(a&Attr(tcell.AttrUnderline) != 0).
+ StrikeThrough(a&Attr(tcell.AttrStrikeThrough) != 0).
+ Italic(a&Attr(tcell.AttrItalic) != 0)
+
+ gr := uniseg.NewGraphemes(text)
+ for gr.Next() {
+ rs := gr.Runes()
+ if len(rs) == 1 && rs[0] == '\n' {
+ w.lastY++
+ w.lastX = 0
+ lx = 0
+ continue
+ }
+
+ // word wrap:
+ xPos := w.left + w.lastX + lx
+ if xPos >= (w.left + w.width) {
+ w.lastY++
+ w.lastX = 0
+ lx = 0
+ xPos = w.left
+ }
+
+ yPos := w.top + w.lastY
+ if yPos >= (w.top + w.height) {
+ return FillSuspend
+ }
+
+ _screen.SetContent(xPos, yPos, rs[0], rs[1:], style)
+ lx += runewidth.StringWidth(string(rs))
+ }
+ w.lastX += lx
+ if w.lastX == w.width {
+ w.lastY++
+ w.lastX = 0
+ return FillNextLine
+ }
+
+ return FillContinue
+}
+
+func (w *TcellWindow) Fill(str string) FillReturn {
+ return w.fillString(str, w.normal)
+}
+
+func (w *TcellWindow) CFill(fg Color, bg Color, a Attr, str string) FillReturn {
+ if fg == colDefault {
+ fg = w.normal.Fg()
+ }
+ if bg == colDefault {
+ bg = w.normal.Bg()
+ }
+ return w.fillString(str, NewColorPair(fg, bg, a))
+}
+
+func (w *TcellWindow) drawBorder() {
+ shape := w.borderStyle.shape
+ if shape == BorderNone {
+ return
+ }
+
+ left := w.left
+ right := left + w.width
+ top := w.top
+ bot := top + w.height
+
+ var style tcell.Style
+ if w.color {
+ if w.preview {
+ style = ColPreviewBorder.style()
+ } else {
+ style = ColBorder.style()
+ }
+ } else {
+ style = w.normal.style()
+ }
+
+ switch shape {
+ case BorderRounded, BorderSharp, BorderHorizontal, BorderTop:
+ for x := left; x < right; x++ {
+ _screen.SetContent(x, top, w.borderStyle.horizontal, nil, style)
+ }
+ }
+ switch shape {
+ case BorderRounded, BorderSharp, BorderHorizontal, BorderBottom:
+ for x := left; x < right; x++ {
+ _screen.SetContent(x, bot-1, w.borderStyle.horizontal, nil, style)
+ }
+ }
+ switch shape {
+ case BorderRounded, BorderSharp, BorderVertical, BorderLeft:
+ for y := top; y < bot; y++ {
+ _screen.SetContent(left, y, w.borderStyle.vertical, nil, style)
+ }
+ }
+ switch shape {
+ case BorderRounded, BorderSharp, BorderVertical, BorderRight:
+ for y := top; y < bot; y++ {
+ _screen.SetContent(right-1, y, w.borderStyle.vertical, nil, style)
+ }
+ }
+ switch shape {
+ case BorderRounded, BorderSharp:
+ _screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
+ _screen.SetContent(right-1, top, w.borderStyle.topRight, nil, style)
+ _screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
+ _screen.SetContent(right-1, bot-1, w.borderStyle.bottomRight, nil, style)
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tcell_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tcell_test.go
new file mode 100644
index 00000000..0d50bb76
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tcell_test.go
@@ -0,0 +1,392 @@
+//go:build tcell || windows
+
+package tui
+
+import (
+ "testing"
+
+ "github.com/gdamore/tcell/v2"
+ "github.com/junegunn/fzf/src/util"
+)
+
+func assert(t *testing.T, context string, got interface{}, want interface{}) bool {
+ if got == want {
+ return true
+ } else {
+ t.Errorf("%s = (%T)%v, want (%T)%v", context, got, got, want, want)
+ return false
+ }
+}
+
+// Test the handling of the tcell keyboard events.
+func TestGetCharEventKey(t *testing.T) {
+ if util.ToTty() {
+ // This test is skipped when output goes to terminal, because it causes
+ // some glitches:
+ // - output lines may not start at the beginning of a row which makes
+ // the output unreadable
+ // - terminal may get cleared which prevents you from seeing results of
+ // previous tests
+ // Good ways to prevent the glitches are piping the output to a pager
+ // or redirecting to a file. I've found `less +G` to be trouble-free.
+ t.Skip("Skipped because this test misbehaves in terminal, pipe to a pager or redirect output to a file to run it safely.")
+ } else if testing.Verbose() {
+ // I have observed a behaviour when this test outputted more than 8192
+ // bytes (32*256) into the 'less' pager, both the go's test executable
+ // and the pager hanged. The go's executable was blocking on printing.
+ // I was able to create minimal working example of that behaviour, but
+ // that example hanged after 12256 bytes (32*(256+127)).
+ t.Log("If you are piping this test to a pager and it hangs, make the pager greedy for input, e.g. 'less +G'.")
+ }
+
+ if !HasFullscreenRenderer() {
+ t.Skip("Can't test FullscreenRenderer.")
+ }
+
+ // construct test cases
+ type giveKey struct {
+ Type tcell.Key
+ Char rune
+ Mods tcell.ModMask
+ }
+ type wantKey = Event
+ type testCase struct {
+ giveKey
+ wantKey
+ }
+ /*
+ Some test cases are marked "fabricated". It means that giveKey value
+ is valid, but it is not what you get when you press the keys. For
+ example Ctrl+C will NOT give you tcell.KeyCtrlC, but tcell.KeyETX
+ (End-Of-Text character, causing SIGINT).
+ I was trying to accompany the fabricated test cases with real ones.
+
+ Some test cases are marked "unhandled". It means that giveKey.Type
+ is not present in tcell.go source code. It can still be handled via
+ implicit or explicit alias.
+
+ If not said otherwise, test cases are for US keyboard.
+
+ (tabstop=44)
+ */
+ tests := []testCase{
+
+ // section 1: Ctrl+(Alt)+[a-z]
+ {giveKey{tcell.KeyCtrlA, rune(tcell.KeyCtrlA), tcell.ModCtrl}, wantKey{CtrlA, 0, nil}},
+ {giveKey{tcell.KeyCtrlC, rune(tcell.KeyCtrlC), tcell.ModCtrl}, wantKey{CtrlC, 0, nil}}, // fabricated
+ {giveKey{tcell.KeyETX, rune(tcell.KeyETX), tcell.ModCtrl}, wantKey{CtrlC, 0, nil}}, // this is SIGINT (Ctrl+C)
+ {giveKey{tcell.KeyCtrlZ, rune(tcell.KeyCtrlZ), tcell.ModCtrl}, wantKey{CtrlZ, 0, nil}}, // fabricated
+ // KeyTab is alias for KeyTAB
+ {giveKey{tcell.KeyCtrlI, rune(tcell.KeyCtrlI), tcell.ModCtrl}, wantKey{Tab, 0, nil}}, // fabricated
+ {giveKey{tcell.KeyTab, rune(tcell.KeyTab), tcell.ModNone}, wantKey{Tab, 0, nil}}, // unhandled, actual "Tab" keystroke
+ {giveKey{tcell.KeyTAB, rune(tcell.KeyTAB), tcell.ModNone}, wantKey{Tab, 0, nil}}, // fabricated, unhandled
+ // KeyEnter is alias for KeyCR
+ {giveKey{tcell.KeyCtrlM, rune(tcell.KeyCtrlM), tcell.ModNone}, wantKey{CtrlM, 0, nil}}, // actual "Enter" keystroke
+ {giveKey{tcell.KeyCR, rune(tcell.KeyCR), tcell.ModNone}, wantKey{CtrlM, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone}, wantKey{CtrlM, 0, nil}}, // fabricated, unhandled
+ // Ctrl+Alt keys
+ {giveKey{tcell.KeyCtrlA, rune(tcell.KeyCtrlA), tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAlt, 'a', nil}}, // fabricated
+ {giveKey{tcell.KeyCtrlA, rune(tcell.KeyCtrlA), tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{CtrlAlt, 'a', nil}}, // fabricated
+
+ // section 2: Ctrl+[ \]_]
+ {giveKey{tcell.KeyCtrlSpace, rune(tcell.KeyCtrlSpace), tcell.ModCtrl}, wantKey{CtrlSpace, 0, nil}}, // fabricated
+ {giveKey{tcell.KeyNUL, rune(tcell.KeyNUL), tcell.ModNone}, wantKey{CtrlSpace, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyRune, ' ', tcell.ModCtrl}, wantKey{CtrlSpace, 0, nil}}, // actual Ctrl+' '
+ {giveKey{tcell.KeyCtrlBackslash, rune(tcell.KeyCtrlBackslash), tcell.ModCtrl}, wantKey{CtrlBackSlash, 0, nil}},
+ {giveKey{tcell.KeyCtrlRightSq, rune(tcell.KeyCtrlRightSq), tcell.ModCtrl}, wantKey{CtrlRightBracket, 0, nil}},
+ {giveKey{tcell.KeyCtrlCarat, rune(tcell.KeyCtrlCarat), tcell.ModShift | tcell.ModCtrl}, wantKey{CtrlCaret, 0, nil}}, // fabricated
+ {giveKey{tcell.KeyRS, rune(tcell.KeyRS), tcell.ModShift | tcell.ModCtrl}, wantKey{CtrlCaret, 0, nil}}, // actual Ctrl+Shift+6 (i.e. Ctrl+^) keystroke
+ {giveKey{tcell.KeyCtrlUnderscore, rune(tcell.KeyCtrlUnderscore), tcell.ModShift | tcell.ModCtrl}, wantKey{CtrlSlash, 0, nil}},
+
+ // section 3: (Alt)+Backspace2
+ // KeyBackspace2 is alias for KeyDEL = 0x7F (ASCII) (allegedly unused by Windows)
+ // KeyDelete = 0x2E (VK_DELETE constant in Windows)
+ // KeyBackspace is alias for KeyBS = 0x08 (ASCII) (implicit alias with KeyCtrlH)
+ {giveKey{tcell.KeyBackspace2, 0, tcell.ModNone}, wantKey{BSpace, 0, nil}}, // fabricated
+ {giveKey{tcell.KeyBackspace2, 0, tcell.ModAlt}, wantKey{AltBS, 0, nil}}, // fabricated
+ {giveKey{tcell.KeyDEL, 0, tcell.ModNone}, wantKey{BSpace, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyDelete, 0, tcell.ModNone}, wantKey{Del, 0, nil}},
+ {giveKey{tcell.KeyDelete, 0, tcell.ModAlt}, wantKey{Del, 0, nil}},
+ {giveKey{tcell.KeyBackspace, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyBS, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyCtrlH, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModNone}, wantKey{BSpace, 0, nil}}, // actual "Backspace" keystroke
+ {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModAlt}, wantKey{AltBS, 0, nil}}, // actual "Alt+Backspace" keystroke
+ {giveKey{tcell.KeyDEL, rune(tcell.KeyDEL), tcell.ModCtrl}, wantKey{BSpace, 0, nil}}, // actual "Ctrl+Backspace" keystroke
+ {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift}, wantKey{BSpace, 0, nil}}, // actual "Shift+Backspace" keystroke
+ {giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt}, wantKey{BSpace, 0, nil}}, // actual "Ctrl+Alt+Backspace" keystroke
+ {giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModShift}, wantKey{BSpace, 0, nil}}, // actual "Ctrl+Shift+Backspace" keystroke
+ {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModShift | tcell.ModAlt}, wantKey{AltBS, 0, nil}}, // actual "Shift+Alt+Backspace" keystroke
+ {giveKey{tcell.KeyCtrlH, 0, tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{BSpace, 0, nil}}, // actual "Ctrl+Shift+Alt+Backspace" keystroke
+ {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+H" keystroke
+ {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt}, wantKey{CtrlAlt, 'h', nil}}, // fabricated "Ctrl+Alt+H" keystroke
+ {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModShift}, wantKey{CtrlH, 0, nil}}, // actual "Ctrl+Shift+H" keystroke
+ {giveKey{tcell.KeyCtrlH, rune(tcell.KeyCtrlH), tcell.ModCtrl | tcell.ModAlt | tcell.ModShift}, wantKey{CtrlAlt, 'h', nil}}, // fabricated "Ctrl+Shift+Alt+H" keystroke
+
+ // section 4: (Alt+Shift)+Key(Up|Down|Left|Right)
+ {giveKey{tcell.KeyUp, 0, tcell.ModNone}, wantKey{Up, 0, nil}},
+ {giveKey{tcell.KeyDown, 0, tcell.ModAlt}, wantKey{AltDown, 0, nil}},
+ {giveKey{tcell.KeyLeft, 0, tcell.ModShift}, wantKey{SLeft, 0, nil}},
+ {giveKey{tcell.KeyRight, 0, tcell.ModShift | tcell.ModAlt}, wantKey{AltSRight, 0, nil}},
+ {giveKey{tcell.KeyUpLeft, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyUpRight, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyDownLeft, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyDownRight, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyCenter, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ // section 5: (Insert|Home|Delete|End|PgUp|PgDn|BackTab|F1-F12)
+ {giveKey{tcell.KeyInsert, 0, tcell.ModNone}, wantKey{Insert, 0, nil}},
+ {giveKey{tcell.KeyF1, 0, tcell.ModNone}, wantKey{F1, 0, nil}},
+ // section 6: (Ctrl+Alt)+'rune'
+ {giveKey{tcell.KeyRune, 'a', tcell.ModNone}, wantKey{Rune, 'a', nil}},
+ {giveKey{tcell.KeyRune, 'a', tcell.ModCtrl}, wantKey{Rune, 'a', nil}}, // fabricated
+ {giveKey{tcell.KeyRune, 'a', tcell.ModAlt}, wantKey{Alt, 'a', nil}},
+ {giveKey{tcell.KeyRune, 'A', tcell.ModAlt}, wantKey{Alt, 'A', nil}},
+ {giveKey{tcell.KeyRune, '`', tcell.ModAlt}, wantKey{Alt, '`', nil}},
+ /*
+ "Input method" in Windows Language options:
+ US: "US Keyboard" does not generate any characters (and thus any events) in Ctrl+Alt+[a-z] range
+ CS: "Czech keyboard"
+ DE: "German keyboard"
+
+ Note that right Alt is not just `tcell.ModAlt` on foreign language keyboards, but it is the AltGr `tcell.ModCtrl|tcell.ModAlt`.
+ */
+ {giveKey{tcell.KeyRune, '{', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '{', nil}}, // CS: Ctrl+Alt+b = "{" // Note that this does not interfere with CtrlB, since the "b" is replaced with "{" on OS level
+ {giveKey{tcell.KeyRune, '$', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '$', nil}}, // CS: Ctrl+Alt+ů = "$"
+ {giveKey{tcell.KeyRune, '~', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '~', nil}}, // CS: Ctrl+Alt++ = "~"
+ {giveKey{tcell.KeyRune, '`', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '`', nil}}, // CS: Ctrl+Alt+ý,Space = "`" // this is dead key, space is required to emit the char
+
+ {giveKey{tcell.KeyRune, '{', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '{', nil}}, // DE: Ctrl+Alt+7 = "{"
+ {giveKey{tcell.KeyRune, '@', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, '@', nil}}, // DE: Ctrl+Alt+q = "@"
+ {giveKey{tcell.KeyRune, 'µ', tcell.ModCtrl | tcell.ModAlt}, wantKey{Rune, 'µ', nil}}, // DE: Ctrl+Alt+m = "µ"
+
+ // section 7: Esc
+ // KeyEsc and KeyEscape are aliases for KeyESC
+ {giveKey{tcell.KeyEsc, rune(tcell.KeyEsc), tcell.ModNone}, wantKey{ESC, 0, nil}}, // fabricated
+ {giveKey{tcell.KeyESC, rune(tcell.KeyESC), tcell.ModNone}, wantKey{ESC, 0, nil}}, // unhandled
+ {giveKey{tcell.KeyEscape, rune(tcell.KeyEscape), tcell.ModNone}, wantKey{ESC, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyESC, rune(tcell.KeyESC), tcell.ModCtrl}, wantKey{ESC, 0, nil}}, // actual Ctrl+[ keystroke
+ {giveKey{tcell.KeyCtrlLeftSq, rune(tcell.KeyCtrlLeftSq), tcell.ModCtrl}, wantKey{ESC, 0, nil}}, // fabricated, unhandled
+
+ // section 8: Invalid
+ {giveKey{tcell.KeyRune, 'a', tcell.ModMeta}, wantKey{Rune, 'a', nil}}, // fabricated
+ {giveKey{tcell.KeyF24, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}},
+ {giveKey{tcell.KeyHelp, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyExit, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyClear, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // unhandled, actual keystroke Numpad_5 with Numlock OFF
+ {giveKey{tcell.KeyCancel, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyPrint, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // fabricated, unhandled
+ {giveKey{tcell.KeyPause, 0, tcell.ModNone}, wantKey{Invalid, 0, nil}}, // unhandled
+
+ }
+ r := NewFullscreenRenderer(&ColorTheme{}, false, false)
+ r.Init()
+
+ // run and evaluate the tests
+ for _, test := range tests {
+ // generate key event
+ giveEvent := tcell.NewEventKey(test.giveKey.Type, test.giveKey.Char, test.giveKey.Mods)
+ _screen.PostEventWait(giveEvent)
+ t.Logf("giveEvent = %T{key: %v, ch: %q (%[3]v), mod: %#04b}\n", giveEvent, giveEvent.Key(), giveEvent.Rune(), giveEvent.Modifiers())
+
+ // process the event in fzf and evaluate the test
+ gotEvent := r.GetChar()
+ // skip Resize events, those are sometimes put in the buffer outside of this test
+ for gotEvent.Type == Resize {
+ t.Logf("Resize swallowed")
+ gotEvent = r.GetChar()
+ }
+ t.Logf("wantEvent = %T{Type: %v, Char: %q (%[3]v)}\n", test.wantKey, test.wantKey.Type, test.wantKey.Char)
+ t.Logf("gotEvent = %T{Type: %v, Char: %q (%[3]v)}\n", gotEvent, gotEvent.Type, gotEvent.Char)
+
+ assert(t, "r.GetChar().Type", gotEvent.Type, test.wantKey.Type)
+ assert(t, "r.GetChar().Char", gotEvent.Char, test.wantKey.Char)
+ }
+
+ r.Close()
+}
+
+/*
+Quick reference
+---------------
+
+(tabstop=18)
+(this is not mapping table, it merely puts multiple constants ranges in one table)
+
+¹) the two columns are each other implicit alias
+²) explicit aliases here
+
+%v section # tcell ctrl key¹ tcell ctrl char¹ tcell alias² tui constants tcell named keys tcell mods
+-- --------- -------------- --------------- ----------- ------------- ---------------- ----------
+0 2 KeyCtrlSpace KeyNUL = ^@ Rune ModNone
+1 1 KeyCtrlA KeySOH = ^A CtrlA ModShift
+2 1 KeyCtrlB KeySTX = ^B CtrlB ModCtrl
+3 1 KeyCtrlC KeyETX = ^C CtrlC
+4 1 KeyCtrlD KeyEOT = ^D CtrlD ModAlt
+5 1 KeyCtrlE KeyENQ = ^E CtrlE
+6 1 KeyCtrlF KeyACK = ^F CtrlF
+7 1 KeyCtrlG KeyBEL = ^G CtrlG
+8 1 KeyCtrlH KeyBS = ^H KeyBackspace CtrlH ModMeta
+9 1 KeyCtrlI KeyTAB = ^I KeyTab Tab
+10 1 KeyCtrlJ KeyLF = ^J CtrlJ
+11 1 KeyCtrlK KeyVT = ^K CtrlK
+12 1 KeyCtrlL KeyFF = ^L CtrlL
+13 1 KeyCtrlM KeyCR = ^M KeyEnter CtrlM
+14 1 KeyCtrlN KeySO = ^N CtrlN
+15 1 KeyCtrlO KeySI = ^O CtrlO
+16 1 KeyCtrlP KeyDLE = ^P CtrlP
+17 1 KeyCtrlQ KeyDC1 = ^Q CtrlQ
+18 1 KeyCtrlR KeyDC2 = ^R CtrlR
+19 1 KeyCtrlS KeyDC3 = ^S CtrlS
+20 1 KeyCtrlT KeyDC4 = ^T CtrlT
+21 1 KeyCtrlU KeyNAK = ^U CtrlU
+22 1 KeyCtrlV KeySYN = ^V CtrlV
+23 1 KeyCtrlW KeyETB = ^W CtrlW
+24 1 KeyCtrlX KeyCAN = ^X CtrlX
+25 1 KeyCtrlY KeyEM = ^Y CtrlY
+26 1 KeyCtrlZ KeySUB = ^Z CtrlZ
+27 7 KeyCtrlLeftSq KeyESC = ^[ KeyEsc, KeyEscape ESC
+28 2 KeyCtrlBackslash KeyFS = ^\ CtrlSpace
+29 2 KeyCtrlRightSq KeyGS = ^] CtrlBackSlash
+30 2 KeyCtrlCarat KeyRS = ^^ CtrlRightBracket
+31 2 KeyCtrlUnderscore KeyUS = ^_ CtrlCaret
+32 CtrlSlash
+33 Invalid
+34 Resize
+35 Mouse
+36 DoubleClick
+37 LeftClick
+38 RightClick
+39 BTab
+40 BSpace
+41 Del
+42 PgUp
+43 PgDn
+44 Up
+45 Down
+46 Left
+47 Right
+48 Home
+49 End
+50 Insert
+51 SUp
+52 SDown
+53 SLeft
+54 SRight
+55 F1
+56 F2
+57 F3
+58 F4
+59 F5
+60 F6
+61 F7
+62 F8
+63 F9
+64 F10
+65 F11
+66 F12
+67 Change
+68 BackwardEOF
+69 AltBS
+70 AltUp
+71 AltDown
+72 AltLeft
+73 AltRight
+74 AltSUp
+75 AltSDown
+76 AltSLeft
+77 AltSRight
+78 Alt
+79 CtrlAlt
+..
+127 3 KeyDEL KeyBackspace2
+..
+256 6 KeyRune
+257 4 KeyUp
+258 4 KeyDown
+259 4 KeyRight
+260 4 KeyLeft
+261 8 KeyUpLeft
+262 8 KeyUpRight
+263 8 KeyDownLeft
+264 8 KeyDownRight
+265 8 KeyCenter
+266 5 KeyPgUp
+267 5 KeyPgDn
+268 5 KeyHome
+269 5 KeyEnd
+270 5 KeyInsert
+271 5 KeyDelete
+272 8 KeyHelp
+273 8 KeyExit
+274 8 KeyClear
+275 8 KeyCancel
+276 8 KeyPrint
+277 8 KeyPause
+278 5 KeyBacktab
+279 5 KeyF1
+280 5 KeyF2
+281 5 KeyF3
+282 5 KeyF4
+283 5 KeyF5
+284 5 KeyF6
+285 5 KeyF7
+286 5 KeyF8
+287 5 KeyF9
+288 5 KeyF10
+289 5 KeyF11
+290 5 KeyF12
+291 8 KeyF13
+292 8 KeyF14
+293 8 KeyF15
+294 8 KeyF16
+295 8 KeyF17
+296 8 KeyF18
+297 8 KeyF19
+298 8 KeyF20
+299 8 KeyF21
+300 8 KeyF22
+301 8 KeyF23
+302 8 KeyF24
+303 8 KeyF25
+304 8 KeyF26
+305 8 KeyF27
+306 8 KeyF28
+307 8 KeyF29
+308 8 KeyF30
+309 8 KeyF31
+310 8 KeyF32
+311 8 KeyF33
+312 8 KeyF34
+313 8 KeyF35
+314 8 KeyF36
+315 8 KeyF37
+316 8 KeyF38
+317 8 KeyF39
+318 8 KeyF40
+319 8 KeyF41
+320 8 KeyF42
+321 8 KeyF43
+322 8 KeyF44
+323 8 KeyF45
+324 8 KeyF46
+325 8 KeyF47
+326 8 KeyF48
+327 8 KeyF49
+328 8 KeyF50
+329 8 KeyF51
+330 8 KeyF52
+331 8 KeyF53
+332 8 KeyF54
+333 8 KeyF55
+334 8 KeyF56
+335 8 KeyF57
+336 8 KeyF58
+337 8 KeyF59
+338 8 KeyF60
+339 8 KeyF61
+340 8 KeyF62
+341 8 KeyF63
+342 8 KeyF64
+-- --------- -------------- --------------- ----------- ------------- ---------------- ----------
+%v section # tcell ctrl key tcell ctrl char tcell alias tui constants tcell named keys tcell mods
+*/
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/ttyname_unix.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/ttyname_unix.go
new file mode 100644
index 00000000..b5f47416
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/ttyname_unix.go
@@ -0,0 +1,47 @@
+//go:build !windows
+
+package tui
+
+import (
+ "io/ioutil"
+ "os"
+ "syscall"
+)
+
+var devPrefixes = [...]string{"/dev/pts/", "/dev/"}
+
+func ttyname() string {
+ var stderr syscall.Stat_t
+ if syscall.Fstat(2, &stderr) != nil {
+ return ""
+ }
+
+ for _, prefix := range devPrefixes {
+ files, err := ioutil.ReadDir(prefix)
+ if err != nil {
+ continue
+ }
+
+ for _, file := range files {
+ if stat, ok := file.Sys().(*syscall.Stat_t); ok && stat.Rdev == stderr.Rdev {
+ return prefix + file.Name()
+ }
+ }
+ }
+ return ""
+}
+
+// TtyIn returns terminal device to be used as STDIN, falls back to os.Stdin
+func TtyIn() *os.File {
+ in, err := os.OpenFile(consoleDevice, syscall.O_RDONLY, 0)
+ if err != nil {
+ tty := ttyname()
+ if len(tty) > 0 {
+ if in, err := os.OpenFile(tty, syscall.O_RDONLY, 0); err == nil {
+ return in
+ }
+ }
+ return os.Stdin
+ }
+ return in
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/ttyname_windows.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/ttyname_windows.go
new file mode 100644
index 00000000..39b84f70
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/ttyname_windows.go
@@ -0,0 +1,14 @@
+//go:build windows
+
+package tui
+
+import "os"
+
+func ttyname() string {
+ return ""
+}
+
+// TtyIn on Windows returns os.Stdin
+func TtyIn() *os.File {
+ return os.Stdin
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tui.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tui.go
new file mode 100644
index 00000000..eb09da40
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tui.go
@@ -0,0 +1,625 @@
+package tui
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "time"
+)
+
+// Types of user action
+type EventType int
+
+const (
+ Rune EventType = iota
+
+ CtrlA
+ CtrlB
+ CtrlC
+ CtrlD
+ CtrlE
+ CtrlF
+ CtrlG
+ CtrlH
+ Tab
+ CtrlJ
+ CtrlK
+ CtrlL
+ CtrlM
+ CtrlN
+ CtrlO
+ CtrlP
+ CtrlQ
+ CtrlR
+ CtrlS
+ CtrlT
+ CtrlU
+ CtrlV
+ CtrlW
+ CtrlX
+ CtrlY
+ CtrlZ
+ ESC
+ CtrlSpace
+
+ // https://apple.stackexchange.com/questions/24261/how-do-i-send-c-that-is-control-slash-to-the-terminal
+ CtrlBackSlash
+ CtrlRightBracket
+ CtrlCaret
+ CtrlSlash
+
+ Invalid
+ Resize
+ Mouse
+ DoubleClick
+ LeftClick
+ RightClick
+
+ BTab
+ BSpace
+
+ Del
+ PgUp
+ PgDn
+
+ Up
+ Down
+ Left
+ Right
+ Home
+ End
+ Insert
+
+ SUp
+ SDown
+ SLeft
+ SRight
+
+ F1
+ F2
+ F3
+ F4
+ F5
+ F6
+ F7
+ F8
+ F9
+ F10
+ F11
+ F12
+
+ Change
+ BackwardEOF
+
+ AltBS
+
+ AltUp
+ AltDown
+ AltLeft
+ AltRight
+
+ AltSUp
+ AltSDown
+ AltSLeft
+ AltSRight
+
+ Alt
+ CtrlAlt
+)
+
+func (t EventType) AsEvent() Event {
+ return Event{t, 0, nil}
+}
+
+func (t EventType) Int() int {
+ return int(t)
+}
+
+func (t EventType) Byte() byte {
+ return byte(t)
+}
+
+func (e Event) Comparable() Event {
+ // Ignore MouseEvent pointer
+ return Event{e.Type, e.Char, nil}
+}
+
+func Key(r rune) Event {
+ return Event{Rune, r, nil}
+}
+
+func AltKey(r rune) Event {
+ return Event{Alt, r, nil}
+}
+
+func CtrlAltKey(r rune) Event {
+ return Event{CtrlAlt, r, nil}
+}
+
+const (
+ doubleClickDuration = 500 * time.Millisecond
+)
+
+type Color int32
+
+func (c Color) IsDefault() bool {
+ return c == colDefault
+}
+
+func (c Color) is24() bool {
+ return c > 0 && (c&(1<<24)) > 0
+}
+
+type ColorAttr struct {
+ Color Color
+ Attr Attr
+}
+
+func NewColorAttr() ColorAttr {
+ return ColorAttr{Color: colUndefined, Attr: AttrUndefined}
+}
+
+const (
+ colUndefined Color = -2
+ colDefault Color = -1
+)
+
+const (
+ colBlack Color = iota
+ colRed
+ colGreen
+ colYellow
+ colBlue
+ colMagenta
+ colCyan
+ colWhite
+)
+
+type FillReturn int
+
+const (
+ FillContinue FillReturn = iota
+ FillNextLine
+ FillSuspend
+)
+
+type ColorPair struct {
+ fg Color
+ bg Color
+ attr Attr
+}
+
+func HexToColor(rrggbb string) Color {
+ r, _ := strconv.ParseInt(rrggbb[1:3], 16, 0)
+ g, _ := strconv.ParseInt(rrggbb[3:5], 16, 0)
+ b, _ := strconv.ParseInt(rrggbb[5:7], 16, 0)
+ return Color((1 << 24) + (r << 16) + (g << 8) + b)
+}
+
+func NewColorPair(fg Color, bg Color, attr Attr) ColorPair {
+ return ColorPair{fg, bg, attr}
+}
+
+func (p ColorPair) Fg() Color {
+ return p.fg
+}
+
+func (p ColorPair) Bg() Color {
+ return p.bg
+}
+
+func (p ColorPair) Attr() Attr {
+ return p.attr
+}
+
+func (p ColorPair) HasBg() bool {
+ return p.attr&Reverse == 0 && p.bg != colDefault ||
+ p.attr&Reverse > 0 && p.fg != colDefault
+}
+
+func (p ColorPair) merge(other ColorPair, except Color) ColorPair {
+ dup := p
+ dup.attr = dup.attr.Merge(other.attr)
+ if other.fg != except {
+ dup.fg = other.fg
+ }
+ if other.bg != except {
+ dup.bg = other.bg
+ }
+ return dup
+}
+
+func (p ColorPair) WithAttr(attr Attr) ColorPair {
+ dup := p
+ dup.attr = dup.attr.Merge(attr)
+ return dup
+}
+
+func (p ColorPair) MergeAttr(other ColorPair) ColorPair {
+ return p.WithAttr(other.attr)
+}
+
+func (p ColorPair) Merge(other ColorPair) ColorPair {
+ return p.merge(other, colUndefined)
+}
+
+func (p ColorPair) MergeNonDefault(other ColorPair) ColorPair {
+ return p.merge(other, colDefault)
+}
+
+type ColorTheme struct {
+ Colored bool
+ Input ColorAttr
+ Disabled ColorAttr
+ Fg ColorAttr
+ Bg ColorAttr
+ PreviewFg ColorAttr
+ PreviewBg ColorAttr
+ DarkBg ColorAttr
+ Gutter ColorAttr
+ Prompt ColorAttr
+ Match ColorAttr
+ Current ColorAttr
+ CurrentMatch ColorAttr
+ Spinner ColorAttr
+ Info ColorAttr
+ Cursor ColorAttr
+ Selected ColorAttr
+ Header ColorAttr
+ Border ColorAttr
+}
+
+type Event struct {
+ Type EventType
+ Char rune
+ MouseEvent *MouseEvent
+}
+
+type MouseEvent struct {
+ Y int
+ X int
+ S int
+ Left bool
+ Down bool
+ Double bool
+ Mod bool
+}
+
+type BorderShape int
+
+const (
+ BorderNone BorderShape = iota
+ BorderRounded
+ BorderSharp
+ BorderHorizontal
+ BorderVertical
+ BorderTop
+ BorderBottom
+ BorderLeft
+ BorderRight
+)
+
+type BorderStyle struct {
+ shape BorderShape
+ horizontal rune
+ vertical rune
+ topLeft rune
+ topRight rune
+ bottomLeft rune
+ bottomRight rune
+}
+
+type BorderCharacter int
+
+func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
+ if unicode {
+ if shape == BorderRounded {
+ return BorderStyle{
+ shape: shape,
+ horizontal: '─',
+ vertical: '│',
+ topLeft: '╭',
+ topRight: '╮',
+ bottomLeft: '╰',
+ bottomRight: '╯',
+ }
+ }
+ return BorderStyle{
+ shape: shape,
+ horizontal: '─',
+ vertical: '│',
+ topLeft: '┌',
+ topRight: '┐',
+ bottomLeft: '└',
+ bottomRight: '┘',
+ }
+ }
+ return BorderStyle{
+ shape: shape,
+ horizontal: '-',
+ vertical: '|',
+ topLeft: '+',
+ topRight: '+',
+ bottomLeft: '+',
+ bottomRight: '+',
+ }
+}
+
+func MakeTransparentBorder() BorderStyle {
+ return BorderStyle{
+ shape: BorderRounded,
+ horizontal: ' ',
+ vertical: ' ',
+ topLeft: ' ',
+ topRight: ' ',
+ bottomLeft: ' ',
+ bottomRight: ' '}
+}
+
+type Renderer interface {
+ Init()
+ Pause(clear bool)
+ Resume(clear bool, sigcont bool)
+ Clear()
+ RefreshWindows(windows []Window)
+ Refresh()
+ Close()
+
+ GetChar() Event
+
+ MaxX() int
+ MaxY() int
+
+ NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window
+}
+
+type Window interface {
+ Top() int
+ Left() int
+ Width() int
+ Height() int
+
+ Refresh()
+ FinishFill()
+ Close()
+
+ X() int
+ Y() int
+ Enclose(y int, x int) bool
+
+ Move(y int, x int)
+ MoveAndClear(y int, x int)
+ Print(text string)
+ CPrint(color ColorPair, text string)
+ Fill(text string) FillReturn
+ CFill(fg Color, bg Color, attr Attr, text string) FillReturn
+ Erase()
+}
+
+type FullscreenRenderer struct {
+ theme *ColorTheme
+ mouse bool
+ forceBlack bool
+ prevDownTime time.Time
+ clickY []int
+}
+
+func NewFullscreenRenderer(theme *ColorTheme, forceBlack bool, mouse bool) Renderer {
+ r := &FullscreenRenderer{
+ theme: theme,
+ mouse: mouse,
+ forceBlack: forceBlack,
+ prevDownTime: time.Unix(0, 0),
+ clickY: []int{}}
+ return r
+}
+
+var (
+ Default16 *ColorTheme
+ Dark256 *ColorTheme
+ Light256 *ColorTheme
+
+ ColPrompt ColorPair
+ ColNormal ColorPair
+ ColInput ColorPair
+ ColDisabled ColorPair
+ ColMatch ColorPair
+ ColCursor ColorPair
+ ColCursorEmpty ColorPair
+ ColSelected ColorPair
+ ColCurrent ColorPair
+ ColCurrentMatch ColorPair
+ ColCurrentCursor ColorPair
+ ColCurrentCursorEmpty ColorPair
+ ColCurrentSelected ColorPair
+ ColCurrentSelectedEmpty ColorPair
+ ColSpinner ColorPair
+ ColInfo ColorPair
+ ColHeader ColorPair
+ ColBorder ColorPair
+ ColPreview ColorPair
+ ColPreviewBorder ColorPair
+)
+
+func EmptyTheme() *ColorTheme {
+ return &ColorTheme{
+ Colored: true,
+ Input: ColorAttr{colUndefined, AttrUndefined},
+ Disabled: ColorAttr{colUndefined, AttrUndefined},
+ Fg: ColorAttr{colUndefined, AttrUndefined},
+ Bg: ColorAttr{colUndefined, AttrUndefined},
+ PreviewFg: ColorAttr{colUndefined, AttrUndefined},
+ PreviewBg: ColorAttr{colUndefined, AttrUndefined},
+ DarkBg: ColorAttr{colUndefined, AttrUndefined},
+ Gutter: ColorAttr{colUndefined, AttrUndefined},
+ Prompt: ColorAttr{colUndefined, AttrUndefined},
+ Match: ColorAttr{colUndefined, AttrUndefined},
+ Current: ColorAttr{colUndefined, AttrUndefined},
+ CurrentMatch: ColorAttr{colUndefined, AttrUndefined},
+ Spinner: ColorAttr{colUndefined, AttrUndefined},
+ Info: ColorAttr{colUndefined, AttrUndefined},
+ Cursor: ColorAttr{colUndefined, AttrUndefined},
+ Selected: ColorAttr{colUndefined, AttrUndefined},
+ Header: ColorAttr{colUndefined, AttrUndefined},
+ Border: ColorAttr{colUndefined, AttrUndefined}}
+}
+
+func NoColorTheme() *ColorTheme {
+ return &ColorTheme{
+ Colored: false,
+ Input: ColorAttr{colDefault, AttrRegular},
+ Disabled: ColorAttr{colDefault, AttrRegular},
+ Fg: ColorAttr{colDefault, AttrRegular},
+ Bg: ColorAttr{colDefault, AttrRegular},
+ PreviewFg: ColorAttr{colDefault, AttrRegular},
+ PreviewBg: ColorAttr{colDefault, AttrRegular},
+ DarkBg: ColorAttr{colDefault, AttrRegular},
+ Gutter: ColorAttr{colDefault, AttrRegular},
+ Prompt: ColorAttr{colDefault, AttrRegular},
+ Match: ColorAttr{colDefault, Underline},
+ Current: ColorAttr{colDefault, Reverse},
+ CurrentMatch: ColorAttr{colDefault, Reverse | Underline},
+ Spinner: ColorAttr{colDefault, AttrRegular},
+ Info: ColorAttr{colDefault, AttrRegular},
+ Cursor: ColorAttr{colDefault, AttrRegular},
+ Selected: ColorAttr{colDefault, AttrRegular},
+ Header: ColorAttr{colDefault, AttrRegular},
+ Border: ColorAttr{colDefault, AttrRegular}}
+}
+
+func errorExit(message string) {
+ fmt.Fprintln(os.Stderr, message)
+ os.Exit(2)
+}
+
+func init() {
+ Default16 = &ColorTheme{
+ Colored: true,
+ Input: ColorAttr{colDefault, AttrUndefined},
+ Disabled: ColorAttr{colUndefined, AttrUndefined},
+ Fg: ColorAttr{colDefault, AttrUndefined},
+ Bg: ColorAttr{colDefault, AttrUndefined},
+ PreviewFg: ColorAttr{colUndefined, AttrUndefined},
+ PreviewBg: ColorAttr{colUndefined, AttrUndefined},
+ DarkBg: ColorAttr{colBlack, AttrUndefined},
+ Gutter: ColorAttr{colUndefined, AttrUndefined},
+ Prompt: ColorAttr{colBlue, AttrUndefined},
+ Match: ColorAttr{colGreen, AttrUndefined},
+ Current: ColorAttr{colYellow, AttrUndefined},
+ CurrentMatch: ColorAttr{colGreen, AttrUndefined},
+ Spinner: ColorAttr{colGreen, AttrUndefined},
+ Info: ColorAttr{colWhite, AttrUndefined},
+ Cursor: ColorAttr{colRed, AttrUndefined},
+ Selected: ColorAttr{colMagenta, AttrUndefined},
+ Header: ColorAttr{colCyan, AttrUndefined},
+ Border: ColorAttr{colBlack, AttrUndefined}}
+ Dark256 = &ColorTheme{
+ Colored: true,
+ Input: ColorAttr{colDefault, AttrUndefined},
+ Disabled: ColorAttr{colUndefined, AttrUndefined},
+ Fg: ColorAttr{colDefault, AttrUndefined},
+ Bg: ColorAttr{colDefault, AttrUndefined},
+ PreviewFg: ColorAttr{colUndefined, AttrUndefined},
+ PreviewBg: ColorAttr{colUndefined, AttrUndefined},
+ DarkBg: ColorAttr{236, AttrUndefined},
+ Gutter: ColorAttr{colUndefined, AttrUndefined},
+ Prompt: ColorAttr{110, AttrUndefined},
+ Match: ColorAttr{108, AttrUndefined},
+ Current: ColorAttr{254, AttrUndefined},
+ CurrentMatch: ColorAttr{151, AttrUndefined},
+ Spinner: ColorAttr{148, AttrUndefined},
+ Info: ColorAttr{144, AttrUndefined},
+ Cursor: ColorAttr{161, AttrUndefined},
+ Selected: ColorAttr{168, AttrUndefined},
+ Header: ColorAttr{109, AttrUndefined},
+ Border: ColorAttr{59, AttrUndefined}}
+ Light256 = &ColorTheme{
+ Colored: true,
+ Input: ColorAttr{colDefault, AttrUndefined},
+ Disabled: ColorAttr{colUndefined, AttrUndefined},
+ Fg: ColorAttr{colDefault, AttrUndefined},
+ Bg: ColorAttr{colDefault, AttrUndefined},
+ PreviewFg: ColorAttr{colUndefined, AttrUndefined},
+ PreviewBg: ColorAttr{colUndefined, AttrUndefined},
+ DarkBg: ColorAttr{251, AttrUndefined},
+ Gutter: ColorAttr{colUndefined, AttrUndefined},
+ Prompt: ColorAttr{25, AttrUndefined},
+ Match: ColorAttr{66, AttrUndefined},
+ Current: ColorAttr{237, AttrUndefined},
+ CurrentMatch: ColorAttr{23, AttrUndefined},
+ Spinner: ColorAttr{65, AttrUndefined},
+ Info: ColorAttr{101, AttrUndefined},
+ Cursor: ColorAttr{161, AttrUndefined},
+ Selected: ColorAttr{168, AttrUndefined},
+ Header: ColorAttr{31, AttrUndefined},
+ Border: ColorAttr{145, AttrUndefined}}
+}
+
+func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
+ if forceBlack {
+ theme.Bg = ColorAttr{colBlack, AttrUndefined}
+ }
+
+ o := func(a ColorAttr, b ColorAttr) ColorAttr {
+ c := a
+ if b.Color != colUndefined {
+ c.Color = b.Color
+ }
+ if b.Attr != AttrUndefined {
+ c.Attr = b.Attr
+ }
+ return c
+ }
+ theme.Input = o(baseTheme.Input, theme.Input)
+ theme.Disabled = o(theme.Input, o(baseTheme.Disabled, theme.Disabled))
+ theme.Fg = o(baseTheme.Fg, theme.Fg)
+ theme.Bg = o(baseTheme.Bg, theme.Bg)
+ theme.PreviewFg = o(theme.Fg, o(baseTheme.PreviewFg, theme.PreviewFg))
+ theme.PreviewBg = o(theme.Bg, o(baseTheme.PreviewBg, theme.PreviewBg))
+ theme.DarkBg = o(baseTheme.DarkBg, theme.DarkBg)
+ theme.Gutter = o(theme.DarkBg, o(baseTheme.Gutter, theme.Gutter))
+ theme.Prompt = o(baseTheme.Prompt, theme.Prompt)
+ theme.Match = o(baseTheme.Match, theme.Match)
+ theme.Current = o(baseTheme.Current, theme.Current)
+ theme.CurrentMatch = o(baseTheme.CurrentMatch, theme.CurrentMatch)
+ theme.Spinner = o(baseTheme.Spinner, theme.Spinner)
+ theme.Info = o(baseTheme.Info, theme.Info)
+ theme.Cursor = o(baseTheme.Cursor, theme.Cursor)
+ theme.Selected = o(baseTheme.Selected, theme.Selected)
+ theme.Header = o(baseTheme.Header, theme.Header)
+ theme.Border = o(baseTheme.Border, theme.Border)
+
+ initPalette(theme)
+}
+
+func initPalette(theme *ColorTheme) {
+ pair := func(fg, bg ColorAttr) ColorPair {
+ if fg.Color == colDefault && (fg.Attr&Reverse) > 0 {
+ bg.Color = colDefault
+ }
+ return ColorPair{fg.Color, bg.Color, fg.Attr}
+ }
+ blank := theme.Fg
+ blank.Attr = AttrRegular
+
+ ColPrompt = pair(theme.Prompt, theme.Bg)
+ ColNormal = pair(theme.Fg, theme.Bg)
+ ColInput = pair(theme.Input, theme.Bg)
+ ColDisabled = pair(theme.Disabled, theme.Bg)
+ ColMatch = pair(theme.Match, theme.Bg)
+ ColCursor = pair(theme.Cursor, theme.Gutter)
+ ColCursorEmpty = pair(blank, theme.Gutter)
+ ColSelected = pair(theme.Selected, theme.Gutter)
+ ColCurrent = pair(theme.Current, theme.DarkBg)
+ ColCurrentMatch = pair(theme.CurrentMatch, theme.DarkBg)
+ ColCurrentCursor = pair(theme.Cursor, theme.DarkBg)
+ ColCurrentCursorEmpty = pair(blank, theme.DarkBg)
+ ColCurrentSelected = pair(theme.Selected, theme.DarkBg)
+ ColCurrentSelectedEmpty = pair(blank, theme.DarkBg)
+ ColSpinner = pair(theme.Spinner, theme.Bg)
+ ColInfo = pair(theme.Info, theme.Bg)
+ ColHeader = pair(theme.Header, theme.Bg)
+ ColBorder = pair(theme.Border, theme.Bg)
+ ColPreview = pair(theme.PreviewFg, theme.PreviewBg)
+ ColPreviewBorder = pair(theme.Border, theme.PreviewBg)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tui_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tui_test.go
new file mode 100644
index 00000000..3ba9bf35
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/tui/tui_test.go
@@ -0,0 +1,20 @@
+package tui
+
+import "testing"
+
+func TestHexToColor(t *testing.T) {
+ assert := func(expr string, r, g, b int) {
+ color := HexToColor(expr)
+ if !color.is24() ||
+ int((color>>16)&0xff) != r ||
+ int((color>>8)&0xff) != g ||
+ int((color)&0xff) != b {
+ t.Fail()
+ }
+ }
+
+ assert("#ff0000", 255, 0, 0)
+ assert("#010203", 1, 2, 3)
+ assert("#102030", 16, 32, 48)
+ assert("#ffffff", 255, 255, 255)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/atomicbool.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/atomicbool.go
new file mode 100644
index 00000000..c5c7e690
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/atomicbool.go
@@ -0,0 +1,34 @@
+package util
+
+import (
+ "sync/atomic"
+)
+
+func convertBoolToInt32(b bool) int32 {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+// AtomicBool is a boxed-class that provides synchronized access to the
+// underlying boolean value
+type AtomicBool struct {
+ state int32 // "1" is true, "0" is false
+}
+
+// NewAtomicBool returns a new AtomicBool
+func NewAtomicBool(initialState bool) *AtomicBool {
+ return &AtomicBool{state: convertBoolToInt32(initialState)}
+}
+
+// Get returns the current boolean value synchronously
+func (a *AtomicBool) Get() bool {
+ return atomic.LoadInt32(&a.state) == 1
+}
+
+// Set updates the boolean value synchronously
+func (a *AtomicBool) Set(newState bool) bool {
+ atomic.StoreInt32(&a.state, convertBoolToInt32(newState))
+ return newState
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/atomicbool_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/atomicbool_test.go
new file mode 100644
index 00000000..1feff79c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/atomicbool_test.go
@@ -0,0 +1,17 @@
+package util
+
+import "testing"
+
+func TestAtomicBool(t *testing.T) {
+ if !NewAtomicBool(true).Get() || NewAtomicBool(false).Get() {
+ t.Error("Invalid initial value")
+ }
+
+ ab := NewAtomicBool(true)
+ if ab.Set(false) {
+ t.Error("Invalid return value")
+ }
+ if ab.Get() {
+ t.Error("Invalid state")
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/chars.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/chars.go
new file mode 100644
index 00000000..41de9243
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/chars.go
@@ -0,0 +1,198 @@
+package util
+
+import (
+ "fmt"
+ "unicode"
+ "unicode/utf8"
+ "unsafe"
+)
+
+const (
+ overflow64 uint64 = 0x8080808080808080
+ overflow32 uint32 = 0x80808080
+)
+
+type Chars struct {
+ slice []byte // or []rune
+ inBytes bool
+ trimLengthKnown bool
+ trimLength uint16
+
+ // XXX Piggybacking item index here is a horrible idea. But I'm trying to
+ // minimize the memory footprint by not wasting padded spaces.
+ Index int32
+}
+
+func checkAscii(bytes []byte) (bool, int) {
+ i := 0
+ for ; i <= len(bytes)-8; i += 8 {
+ if (overflow64 & *(*uint64)(unsafe.Pointer(&bytes[i]))) > 0 {
+ return false, i
+ }
+ }
+ for ; i <= len(bytes)-4; i += 4 {
+ if (overflow32 & *(*uint32)(unsafe.Pointer(&bytes[i]))) > 0 {
+ return false, i
+ }
+ }
+ for ; i < len(bytes); i++ {
+ if bytes[i] >= utf8.RuneSelf {
+ return false, i
+ }
+ }
+ return true, 0
+}
+
+// ToChars converts byte array into rune array
+func ToChars(bytes []byte) Chars {
+ inBytes, bytesUntil := checkAscii(bytes)
+ if inBytes {
+ return Chars{slice: bytes, inBytes: inBytes}
+ }
+
+ runes := make([]rune, bytesUntil, len(bytes))
+ for i := 0; i < bytesUntil; i++ {
+ runes[i] = rune(bytes[i])
+ }
+ for i := bytesUntil; i < len(bytes); {
+ r, sz := utf8.DecodeRune(bytes[i:])
+ i += sz
+ runes = append(runes, r)
+ }
+ return RunesToChars(runes)
+}
+
+func RunesToChars(runes []rune) Chars {
+ return Chars{slice: *(*[]byte)(unsafe.Pointer(&runes)), inBytes: false}
+}
+
+func (chars *Chars) IsBytes() bool {
+ return chars.inBytes
+}
+
+func (chars *Chars) Bytes() []byte {
+ return chars.slice
+}
+
+func (chars *Chars) optionalRunes() []rune {
+ if chars.inBytes {
+ return nil
+ }
+ return *(*[]rune)(unsafe.Pointer(&chars.slice))
+}
+
+func (chars *Chars) Get(i int) rune {
+ if runes := chars.optionalRunes(); runes != nil {
+ return runes[i]
+ }
+ return rune(chars.slice[i])
+}
+
+func (chars *Chars) Length() int {
+ if runes := chars.optionalRunes(); runes != nil {
+ return len(runes)
+ }
+ return len(chars.slice)
+}
+
+// String returns the string representation of a Chars object.
+func (chars *Chars) String() string {
+ return fmt.Sprintf("Chars{slice: []byte(%q), inBytes: %v, trimLengthKnown: %v, trimLength: %d, Index: %d}", chars.slice, chars.inBytes, chars.trimLengthKnown, chars.trimLength, chars.Index)
+}
+
+// TrimLength returns the length after trimming leading and trailing whitespaces
+func (chars *Chars) TrimLength() uint16 {
+ if chars.trimLengthKnown {
+ return chars.trimLength
+ }
+ chars.trimLengthKnown = true
+ var i int
+ len := chars.Length()
+ for i = len - 1; i >= 0; i-- {
+ char := chars.Get(i)
+ if !unicode.IsSpace(char) {
+ break
+ }
+ }
+ // Completely empty
+ if i < 0 {
+ return 0
+ }
+
+ var j int
+ for j = 0; j < len; j++ {
+ char := chars.Get(j)
+ if !unicode.IsSpace(char) {
+ break
+ }
+ }
+ chars.trimLength = AsUint16(i - j + 1)
+ return chars.trimLength
+}
+
+func (chars *Chars) LeadingWhitespaces() int {
+ whitespaces := 0
+ for i := 0; i < chars.Length(); i++ {
+ char := chars.Get(i)
+ if !unicode.IsSpace(char) {
+ break
+ }
+ whitespaces++
+ }
+ return whitespaces
+}
+
+func (chars *Chars) TrailingWhitespaces() int {
+ whitespaces := 0
+ for i := chars.Length() - 1; i >= 0; i-- {
+ char := chars.Get(i)
+ if !unicode.IsSpace(char) {
+ break
+ }
+ whitespaces++
+ }
+ return whitespaces
+}
+
+func (chars *Chars) TrimTrailingWhitespaces() {
+ whitespaces := chars.TrailingWhitespaces()
+ chars.slice = chars.slice[0 : len(chars.slice)-whitespaces]
+}
+
+func (chars *Chars) ToString() string {
+ if runes := chars.optionalRunes(); runes != nil {
+ return string(runes)
+ }
+ return string(chars.slice)
+}
+
+func (chars *Chars) ToRunes() []rune {
+ if runes := chars.optionalRunes(); runes != nil {
+ return runes
+ }
+ bytes := chars.slice
+ runes := make([]rune, len(bytes))
+ for idx, b := range bytes {
+ runes[idx] = rune(b)
+ }
+ return runes
+}
+
+func (chars *Chars) CopyRunes(dest []rune) {
+ if runes := chars.optionalRunes(); runes != nil {
+ copy(dest, runes)
+ return
+ }
+ for idx, b := range chars.slice[:len(dest)] {
+ dest[idx] = rune(b)
+ }
+}
+
+func (chars *Chars) Prepend(prefix string) {
+ if runes := chars.optionalRunes(); runes != nil {
+ runes = append([]rune(prefix), runes...)
+ chars.slice = *(*[]byte)(unsafe.Pointer(&runes))
+ } else {
+ chars.slice = append([]byte(prefix), chars.slice...)
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/chars_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/chars_test.go
new file mode 100644
index 00000000..b7983f30
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/chars_test.go
@@ -0,0 +1,46 @@
+package util
+
+import "testing"
+
+func TestToCharsAscii(t *testing.T) {
+ chars := ToChars([]byte("foobar"))
+ if !chars.inBytes || chars.ToString() != "foobar" || !chars.inBytes {
+ t.Error()
+ }
+}
+
+func TestCharsLength(t *testing.T) {
+ chars := ToChars([]byte("\tabc한글 "))
+ if chars.inBytes || chars.Length() != 8 || chars.TrimLength() != 5 {
+ t.Error()
+ }
+}
+
+func TestCharsToString(t *testing.T) {
+ text := "\tabc한글 "
+ chars := ToChars([]byte(text))
+ if chars.ToString() != text {
+ t.Error()
+ }
+}
+
+func TestTrimLength(t *testing.T) {
+ check := func(str string, exp uint16) {
+ chars := ToChars([]byte(str))
+ trimmed := chars.TrimLength()
+ if trimmed != exp {
+ t.Errorf("Invalid TrimLength result for '%s': %d (expected %d)",
+ str, trimmed, exp)
+ }
+ }
+ check("hello", 5)
+ check("hello ", 5)
+ check("hello ", 5)
+ check(" hello", 5)
+ check(" hello", 5)
+ check(" hello ", 5)
+ check(" hello ", 5)
+ check("h o", 5)
+ check(" h o ", 5)
+ check(" ", 0)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/eventbox.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/eventbox.go
new file mode 100644
index 00000000..b710cf1e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/eventbox.go
@@ -0,0 +1,96 @@
+package util
+
+import "sync"
+
+// EventType is the type for fzf events
+type EventType int
+
+// Events is a type that associates EventType to any data
+type Events map[EventType]interface{}
+
+// EventBox is used for coordinating events
+type EventBox struct {
+ events Events
+ cond *sync.Cond
+ ignore map[EventType]bool
+}
+
+// NewEventBox returns a new EventBox
+func NewEventBox() *EventBox {
+ return &EventBox{
+ events: make(Events),
+ cond: sync.NewCond(&sync.Mutex{}),
+ ignore: make(map[EventType]bool)}
+}
+
+// Wait blocks the goroutine until signaled
+func (b *EventBox) Wait(callback func(*Events)) {
+ b.cond.L.Lock()
+
+ if len(b.events) == 0 {
+ b.cond.Wait()
+ }
+
+ callback(&b.events)
+ b.cond.L.Unlock()
+}
+
+// Set turns on the event type on the box
+func (b *EventBox) Set(event EventType, value interface{}) {
+ b.cond.L.Lock()
+ b.events[event] = value
+ if _, found := b.ignore[event]; !found {
+ b.cond.Broadcast()
+ }
+ b.cond.L.Unlock()
+}
+
+// Clear clears the events
+// Unsynchronized; should be called within Wait routine
+func (events *Events) Clear() {
+ for event := range *events {
+ delete(*events, event)
+ }
+}
+
+// Peek peeks at the event box if the given event is set
+func (b *EventBox) Peek(event EventType) bool {
+ b.cond.L.Lock()
+ _, ok := b.events[event]
+ b.cond.L.Unlock()
+ return ok
+}
+
+// Watch deletes the events from the ignore list
+func (b *EventBox) Watch(events ...EventType) {
+ b.cond.L.Lock()
+ for _, event := range events {
+ delete(b.ignore, event)
+ }
+ b.cond.L.Unlock()
+}
+
+// Unwatch adds the events to the ignore list
+func (b *EventBox) Unwatch(events ...EventType) {
+ b.cond.L.Lock()
+ for _, event := range events {
+ b.ignore[event] = true
+ }
+ b.cond.L.Unlock()
+}
+
+// WaitFor blocks the execution until the event is received
+func (b *EventBox) WaitFor(event EventType) {
+ looping := true
+ for looping {
+ b.Wait(func(events *Events) {
+ for evt := range *events {
+ switch evt {
+ case event:
+ looping = false
+ return
+ }
+ }
+ })
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/eventbox_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/eventbox_test.go
new file mode 100644
index 00000000..5a9dc302
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/eventbox_test.go
@@ -0,0 +1,61 @@
+package util
+
+import "testing"
+
+// fzf events
+const (
+ EvtReadNew EventType = iota
+ EvtReadFin
+ EvtSearchNew
+ EvtSearchProgress
+ EvtSearchFin
+ EvtClose
+)
+
+func TestEventBox(t *testing.T) {
+ eb := NewEventBox()
+
+ // Wait should return immediately
+ ch := make(chan bool)
+
+ go func() {
+ eb.Set(EvtReadNew, 10)
+ ch <- true
+ <-ch
+ eb.Set(EvtSearchNew, 10)
+ eb.Set(EvtSearchNew, 15)
+ eb.Set(EvtSearchNew, 20)
+ eb.Set(EvtSearchProgress, 30)
+ ch <- true
+ <-ch
+ eb.Set(EvtSearchFin, 40)
+ ch <- true
+ <-ch
+ }()
+
+ count := 0
+ sum := 0
+ looping := true
+ for looping {
+ <-ch
+ eb.Wait(func(events *Events) {
+ for _, value := range *events {
+ switch val := value.(type) {
+ case int:
+ sum += val
+ looping = sum < 100
+ }
+ }
+ events.Clear()
+ })
+ ch <- true
+ count++
+ }
+
+ if count != 3 {
+ t.Error("Invalid number of events", count)
+ }
+ if sum != 100 {
+ t.Error("Invalid sum", sum)
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/slab.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/slab.go
new file mode 100644
index 00000000..0c49d2d9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/slab.go
@@ -0,0 +1,12 @@
+package util
+
+type Slab struct {
+ I16 []int16
+ I32 []int32
+}
+
+func MakeSlab(size16 int, size32 int) *Slab {
+ return &Slab{
+ I16: make([]int16, size16),
+ I32: make([]int32, size32)}
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/util.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/util.go
new file mode 100644
index 00000000..a1c37f7a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/util.go
@@ -0,0 +1,155 @@
+package util
+
+import (
+ "math"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/mattn/go-isatty"
+ "github.com/mattn/go-runewidth"
+ "github.com/rivo/uniseg"
+)
+
+// RunesWidth returns runes width
+func RunesWidth(runes []rune, prefixWidth int, tabstop int, limit int) (int, int) {
+ width := 0
+ gr := uniseg.NewGraphemes(string(runes))
+ idx := 0
+ for gr.Next() {
+ rs := gr.Runes()
+ var w int
+ if len(rs) == 1 && rs[0] == '\t' {
+ w = tabstop - (prefixWidth+width)%tabstop
+ } else {
+ s := string(rs)
+ w = runewidth.StringWidth(s) + strings.Count(s, "\n")
+ }
+ width += w
+ if width > limit {
+ return width, idx
+ }
+ idx += len(rs)
+ }
+ return width, -1
+}
+
+// Truncate returns the truncated runes and its width
+func Truncate(input string, limit int) ([]rune, int) {
+ runes := []rune{}
+ width := 0
+ gr := uniseg.NewGraphemes(input)
+ for gr.Next() {
+ rs := gr.Runes()
+ w := runewidth.StringWidth(string(rs))
+ if width+w > limit {
+ return runes, width
+ }
+ width += w
+ runes = append(runes, rs...)
+ }
+ return runes, width
+}
+
+// Max returns the largest integer
+func Max(first int, second int) int {
+ if first >= second {
+ return first
+ }
+ return second
+}
+
+// Max16 returns the largest integer
+func Max16(first int16, second int16) int16 {
+ if first >= second {
+ return first
+ }
+ return second
+}
+
+// Max32 returns the largest 32-bit integer
+func Max32(first int32, second int32) int32 {
+ if first > second {
+ return first
+ }
+ return second
+}
+
+// Min returns the smallest integer
+func Min(first int, second int) int {
+ if first <= second {
+ return first
+ }
+ return second
+}
+
+// Min32 returns the smallest 32-bit integer
+func Min32(first int32, second int32) int32 {
+ if first <= second {
+ return first
+ }
+ return second
+}
+
+// Constrain32 limits the given 32-bit integer with the upper and lower bounds
+func Constrain32(val int32, min int32, max int32) int32 {
+ if val < min {
+ return min
+ }
+ if val > max {
+ return max
+ }
+ return val
+}
+
+// Constrain limits the given integer with the upper and lower bounds
+func Constrain(val int, min int, max int) int {
+ if val < min {
+ return min
+ }
+ if val > max {
+ return max
+ }
+ return val
+}
+
+func AsUint16(val int) uint16 {
+ if val > math.MaxUint16 {
+ return math.MaxUint16
+ } else if val < 0 {
+ return 0
+ }
+ return uint16(val)
+}
+
+// DurWithin limits the given time.Duration with the upper and lower bounds
+func DurWithin(
+ val time.Duration, min time.Duration, max time.Duration) time.Duration {
+ if val < min {
+ return min
+ }
+ if val > max {
+ return max
+ }
+ return val
+}
+
+// IsTty returns true if stdin is a terminal
+func IsTty() bool {
+ return isatty.IsTerminal(os.Stdin.Fd())
+}
+
+// ToTty returns true if stdout is a terminal
+func ToTty() bool {
+ return isatty.IsTerminal(os.Stdout.Fd())
+}
+
+// Once returns a function that returns the specified boolean value only once
+func Once(nextResponse bool) func() bool {
+ state := nextResponse
+ return func() bool {
+ prevState := state
+ state = false
+ return prevState
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/util_test.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/util_test.go
new file mode 100644
index 00000000..20bdb92a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/util_test.go
@@ -0,0 +1,66 @@
+package util
+
+import "testing"
+
+func TestMax(t *testing.T) {
+ if Max(-2, 5) != 5 {
+ t.Error("Invalid result")
+ }
+}
+
+func TestContrain(t *testing.T) {
+ if Constrain(-3, -1, 3) != -1 {
+ t.Error("Expected", -1)
+ }
+ if Constrain(2, -1, 3) != 2 {
+ t.Error("Expected", 2)
+ }
+
+ if Constrain(5, -1, 3) != 3 {
+ t.Error("Expected", 3)
+ }
+}
+
+func TestOnce(t *testing.T) {
+ o := Once(false)
+ if o() {
+ t.Error("Expected: false")
+ }
+ if o() {
+ t.Error("Expected: false")
+ }
+
+ o = Once(true)
+ if !o() {
+ t.Error("Expected: true")
+ }
+ if o() {
+ t.Error("Expected: false")
+ }
+}
+
+func TestRunesWidth(t *testing.T) {
+ for _, args := range [][]int{
+ {100, 5, -1},
+ {3, 4, 3},
+ {0, 1, 0},
+ } {
+ width, overflowIdx := RunesWidth([]rune("hello"), 0, 0, args[0])
+ if width != args[1] {
+ t.Errorf("Expected width: %d, actual: %d", args[1], width)
+ }
+ if overflowIdx != args[2] {
+ t.Errorf("Expected overflow index: %d, actual: %d", args[2], overflowIdx)
+ }
+ }
+}
+
+func TestTruncate(t *testing.T) {
+ truncated, width := Truncate("가나다라마", 7)
+ if string(truncated) != "가나다" {
+ t.Errorf("Expected: 가나다, actual: %s", string(truncated))
+ }
+ if width != 6 {
+ t.Errorf("Expected: 6, actual: %d", width)
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/util_unix.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/util_unix.go
new file mode 100644
index 00000000..a76f770a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/util_unix.go
@@ -0,0 +1,47 @@
+//go:build !windows
+
+package util
+
+import (
+ "os"
+ "os/exec"
+ "syscall"
+)
+
+// ExecCommand executes the given command with $SHELL
+func ExecCommand(command string, setpgid bool) *exec.Cmd {
+ shell := os.Getenv("SHELL")
+ if len(shell) == 0 {
+ shell = "sh"
+ }
+ return ExecCommandWith(shell, command, setpgid)
+}
+
+// ExecCommandWith executes the given command with the specified shell
+func ExecCommandWith(shell string, command string, setpgid bool) *exec.Cmd {
+ cmd := exec.Command(shell, "-c", command)
+ if setpgid {
+ cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
+ }
+ return cmd
+}
+
+// KillCommand kills the process for the given command
+func KillCommand(cmd *exec.Cmd) error {
+ return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
+}
+
+// IsWindows returns true on Windows
+func IsWindows() bool {
+ return false
+}
+
+// SetNonblock executes syscall.SetNonblock on file descriptor
+func SetNonblock(file *os.File, nonblock bool) {
+ syscall.SetNonblock(int(file.Fd()), nonblock)
+}
+
+// Read executes syscall.Read on file descriptor
+func Read(fd int, b []byte) (int, error) {
+ return syscall.Read(int(fd), b)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/src/util/util_windows.go b/dot-oh-my-zsh/custom/plugins/fzf/src/util/util_windows.go
new file mode 100644
index 00000000..b3f4e016
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/src/util/util_windows.go
@@ -0,0 +1,83 @@
+//go:build windows
+
+package util
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+ "sync/atomic"
+ "syscall"
+)
+
+var shellPath atomic.Value
+
+// ExecCommand executes the given command with $SHELL
+func ExecCommand(command string, setpgid bool) *exec.Cmd {
+ var shell string
+ if cached := shellPath.Load(); cached != nil {
+ shell = cached.(string)
+ } else {
+ shell = os.Getenv("SHELL")
+ if len(shell) == 0 {
+ shell = "cmd"
+ } else if strings.Contains(shell, "/") {
+ out, err := exec.Command("cygpath", "-w", shell).Output()
+ if err == nil {
+ shell = strings.Trim(string(out), "\n")
+ }
+ }
+ shellPath.Store(shell)
+ }
+ return ExecCommandWith(shell, command, setpgid)
+}
+
+// ExecCommandWith executes the given command with the specified shell
+// FIXME: setpgid is unused. We set it in the Unix implementation so that we
+// can kill preview process with its child processes at once.
+// NOTE: For "powershell", we should ideally set output encoding to UTF8,
+// but it is left as is now because no adverse effect has been observed.
+func ExecCommandWith(shell string, command string, setpgid bool) *exec.Cmd {
+ var cmd *exec.Cmd
+ if strings.Contains(shell, "cmd") {
+ cmd = exec.Command(shell)
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ HideWindow: false,
+ CmdLine: fmt.Sprintf(` /v:on/s/c "%s"`, command),
+ CreationFlags: 0,
+ }
+ return cmd
+ }
+
+ if strings.Contains(shell, "pwsh") || strings.Contains(shell, "powershell") {
+ cmd = exec.Command(shell, "-NoProfile", "-Command", command)
+ } else {
+ cmd = exec.Command(shell, "-c", command)
+ }
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ HideWindow: false,
+ CreationFlags: 0,
+ }
+ return cmd
+}
+
+// KillCommand kills the process for the given command
+func KillCommand(cmd *exec.Cmd) error {
+ return cmd.Process.Kill()
+}
+
+// IsWindows returns true on Windows
+func IsWindows() bool {
+ return true
+}
+
+// SetNonblock executes syscall.SetNonblock on file descriptor
+func SetNonblock(file *os.File, nonblock bool) {
+ syscall.SetNonblock(syscall.Handle(file.Fd()), nonblock)
+}
+
+// Read executes syscall.Read on file descriptor
+func Read(fd int, b []byte) (int, error) {
+ return syscall.Read(syscall.Handle(fd), b)
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/test/fzf.vader b/dot-oh-my-zsh/custom/plugins/fzf/test/fzf.vader
new file mode 100644
index 00000000..07f0c8de
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/test/fzf.vader
@@ -0,0 +1,175 @@
+Execute (Setup):
+ let g:dir = fnamemodify(g:vader_file, ':p:h')
+ unlet! g:fzf_layout g:fzf_action g:fzf_history_dir
+ Log 'Test directory: ' . g:dir
+ Save &acd
+
+Execute (fzf#run with dir option):
+ let cwd = getcwd()
+ let result = fzf#run({ 'source': 'git ls-files', 'options': '--filter=vdr', 'dir': g:dir })
+ AssertEqual ['fzf.vader'], result
+ AssertEqual 0, haslocaldir()
+ AssertEqual getcwd(), cwd
+
+ execute 'lcd' fnameescape(cwd)
+ let result = sort(fzf#run({ 'source': 'git ls-files', 'options': '--filter e', 'dir': g:dir }))
+ AssertEqual ['fzf.vader', 'test_go.rb'], result
+ AssertEqual 1, haslocaldir()
+ AssertEqual getcwd(), cwd
+
+Execute (fzf#run with Funcref command):
+ let g:ret = []
+ function! g:FzfTest(e)
+ call add(g:ret, a:e)
+ endfunction
+ let result = sort(fzf#run({ 'source': 'git ls-files', 'sink': function('g:FzfTest'), 'options': '--filter e', 'dir': g:dir }))
+ AssertEqual ['fzf.vader', 'test_go.rb'], result
+ AssertEqual ['fzf.vader', 'test_go.rb'], sort(g:ret)
+
+Execute (fzf#run with string source):
+ let result = sort(fzf#run({ 'source': 'echo hi', 'options': '-f i' }))
+ AssertEqual ['hi'], result
+
+Execute (fzf#run with list source):
+ let result = sort(fzf#run({ 'source': ['hello', 'world'], 'options': '-f e' }))
+ AssertEqual ['hello'], result
+ let result = sort(fzf#run({ 'source': ['hello', 'world'], 'options': '-f o' }))
+ AssertEqual ['hello', 'world'], result
+
+Execute (fzf#run with string source):
+ let result = sort(fzf#run({ 'source': 'echo hi', 'options': '-f i' }))
+ AssertEqual ['hi'], result
+
+Execute (fzf#run with dir option and noautochdir):
+ set noacd
+ let cwd = getcwd()
+ call fzf#run({'source': ['/foobar'], 'sink': 'e', 'dir': '/tmp', 'options': '-1'})
+ " No change in working directory
+ AssertEqual cwd, getcwd()
+
+ call fzf#run({'source': ['/foobar'], 'sink': 'tabe', 'dir': '/tmp', 'options': '-1'})
+ AssertEqual cwd, getcwd()
+ tabclose
+ AssertEqual cwd, getcwd()
+
+Execute (Incomplete fzf#run with dir option and autochdir):
+ set acd
+ let cwd = getcwd()
+ call fzf#run({'source': [], 'sink': 'e', 'dir': '/tmp', 'options': '-0'})
+ " No change in working directory even if &acd is set
+ AssertEqual cwd, getcwd()
+
+Execute (FIXME: fzf#run with dir option and autochdir):
+ set acd
+ call fzf#run({'source': ['/foobar'], 'sink': 'e', 'dir': '/tmp', 'options': '-1'})
+ " Working directory changed due to &acd
+ AssertEqual '/foobar', expand('%')
+ AssertEqual '/', getcwd()
+
+Execute (fzf#run with dir option and autochdir when final cwd is same as dir):
+ set acd
+ cd /tmp
+ call fzf#run({'source': ['/foobar'], 'sink': 'e', 'dir': '/', 'options': '-1'})
+ " Working directory changed due to &acd
+ AssertEqual '/', getcwd()
+
+Execute (fzf#wrap):
+ AssertThrows fzf#wrap({'foo': 'bar'})
+
+ let opts = fzf#wrap('foobar')
+ Log opts
+ AssertEqual '~40%', opts.down
+ Assert opts.options =~ '--expect='
+ Assert !has_key(opts, 'sink')
+ Assert has_key(opts, 'sink*')
+
+ let opts = fzf#wrap('foobar', {}, 0)
+ Log opts
+ AssertEqual '~40%', opts.down
+
+ let opts = fzf#wrap('foobar', {}, 1)
+ Log opts
+ Assert !has_key(opts, 'down')
+
+ let opts = fzf#wrap('foobar', {'down': '50%'})
+ Log opts
+ AssertEqual '50%', opts.down
+
+ let opts = fzf#wrap('foobar', {'down': '50%'}, 1)
+ Log opts
+ Assert !has_key(opts, 'down')
+
+ let opts = fzf#wrap('foobar', {'sink': 'e'})
+ Log opts
+ AssertEqual 'e', opts.sink
+ Assert !has_key(opts, 'sink*')
+
+ let opts = fzf#wrap('foobar', {'options': '--reverse'})
+ Log opts
+ Assert opts.options =~ '--expect='
+ Assert opts.options =~ '--reverse'
+
+ let g:fzf_layout = {'window': 'enew'}
+ let opts = fzf#wrap('foobar')
+ Log opts
+ AssertEqual 'enew', opts.window
+
+ let opts = fzf#wrap('foobar', {}, 1)
+ Log opts
+ Assert !has_key(opts, 'window')
+
+ let opts = fzf#wrap('foobar', {'right': '50%'})
+ Log opts
+ Assert !has_key(opts, 'window')
+ AssertEqual '50%', opts.right
+
+ let opts = fzf#wrap('foobar', {'right': '50%'}, 1)
+ Log opts
+ Assert !has_key(opts, 'window')
+ Assert !has_key(opts, 'right')
+
+ let g:fzf_action = {'a': 'tabe'}
+ let opts = fzf#wrap('foobar')
+ Log opts
+ Assert opts.options =~ '--expect=a'
+ Assert !has_key(opts, 'sink')
+ Assert has_key(opts, 'sink*')
+
+ let opts = fzf#wrap('foobar', {'sink': 'e'})
+ Log opts
+ AssertEqual 'e', opts.sink
+ Assert !has_key(opts, 'sink*')
+
+ let g:fzf_history_dir = '/tmp'
+ let opts = fzf#wrap('foobar', {'options': '--color light'})
+ Log opts
+ Assert opts.options =~ "--history '/tmp/foobar'"
+ Assert opts.options =~ '--color light'
+
+ let g:fzf_colors = { 'fg': ['fg', 'Error'] }
+ let opts = fzf#wrap({})
+ Assert opts.options =~ '^--color=fg:'
+
+Execute (fzf#shellescape with sh):
+ AssertEqual '''''', fzf#shellescape('', 'sh')
+ AssertEqual '''\''', fzf#shellescape('\', 'sh')
+ AssertEqual '''""''', fzf#shellescape('""', 'sh')
+ AssertEqual '''foobar>''', fzf#shellescape('foobar>', 'sh')
+ AssertEqual '''\\\"\\\''', fzf#shellescape('\\\"\\\', 'sh')
+ AssertEqual '''echo ''\''''a''\'''' && echo ''\''''b''\''''''', fzf#shellescape('echo ''a'' && echo ''b''', 'sh')
+
+Execute (fzf#shellescape with cmd.exe):
+ AssertEqual '^"^"', fzf#shellescape('', 'cmd.exe')
+ AssertEqual '^"\\^"', fzf#shellescape('\', 'cmd.exe')
+ AssertEqual '^"\^"\^"^"', fzf#shellescape('""', 'cmd.exe')
+ AssertEqual '^"foobar^>^"', fzf#shellescape('foobar>', 'cmd.exe')
+ AssertEqual '^"\\\\\\\^"\\\\\\^"', fzf#shellescape('\\\"\\\', 'cmd.exe')
+ AssertEqual '^"echo ''a'' ^&^& echo ''b''^"', fzf#shellescape('echo ''a'' && echo ''b''', 'cmd.exe')
+
+ AssertEqual '^"C:\Program Files ^(x86^)\\^"', fzf#shellescape('C:\Program Files (x86)\', 'cmd.exe')
+ AssertEqual '^"C:/Program Files ^(x86^)/^"', fzf#shellescape('C:/Program Files (x86)/', 'cmd.exe')
+ AssertEqual '^"%%USERPROFILE%%^"', fzf#shellescape('%USERPROFILE%', 'cmd.exe')
+
+Execute (Cleanup):
+ unlet g:dir
+ Restore
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/test/test_go.rb b/dot-oh-my-zsh/custom/plugins/fzf/test/test_go.rb
new file mode 100755
index 00000000..6371e0e2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/test/test_go.rb
@@ -0,0 +1,2729 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require 'minitest/autorun'
+require 'fileutils'
+require 'English'
+require 'shellwords'
+require 'erb'
+require 'tempfile'
+
+TEMPLATE = DATA.read
+UNSETS = %w[
+ FZF_DEFAULT_COMMAND FZF_DEFAULT_OPTS
+ FZF_TMUX FZF_TMUX_OPTS
+ FZF_CTRL_T_COMMAND FZF_CTRL_T_OPTS
+ FZF_ALT_C_COMMAND
+ FZF_ALT_C_OPTS FZF_CTRL_R_OPTS
+ fish_history
+].freeze
+DEFAULT_TIMEOUT = 10
+
+FILE = File.expand_path(__FILE__)
+BASE = File.expand_path('..', __dir__)
+Dir.chdir(BASE)
+FZF = "FZF_DEFAULT_OPTS= FZF_DEFAULT_COMMAND= #{BASE}/bin/fzf"
+
+def wait
+ since = Time.now
+ begin
+ yield or raise Minitest::Assertion, 'Assertion failure'
+ rescue Minitest::Assertion
+ raise if Time.now - since > DEFAULT_TIMEOUT
+
+ sleep(0.05)
+ retry
+ end
+end
+
+class Shell
+ class << self
+ def bash
+ @bash ||=
+ begin
+ bashrc = '/tmp/fzf.bash'
+ File.open(bashrc, 'w') do |f|
+ f.puts ERB.new(TEMPLATE).result(binding)
+ end
+
+ "bash --rcfile #{bashrc}"
+ end
+ end
+
+ def zsh
+ @zsh ||=
+ begin
+ zdotdir = '/tmp/fzf-zsh'
+ FileUtils.rm_rf(zdotdir)
+ FileUtils.mkdir_p(zdotdir)
+ File.open("#{zdotdir}/.zshrc", 'w') do |f|
+ f.puts ERB.new(TEMPLATE).result(binding)
+ end
+ "ZDOTDIR=#{zdotdir} zsh"
+ end
+ end
+
+ def fish
+ UNSETS.map { |v| v + '= ' }.join + 'fish'
+ end
+ end
+end
+
+class Tmux
+ attr_reader :win
+
+ def initialize(shell = :bash)
+ @win = go(%W[new-window -d -P -F #I #{Shell.send(shell)}]).first
+ go(%W[set-window-option -t #{@win} pane-base-index 0])
+ return unless shell == :fish
+
+ send_keys 'function fish_prompt; end; clear', :Enter
+ self.until(&:empty?)
+ end
+
+ def kill
+ go(%W[kill-window -t #{win}])
+ end
+
+ def focus
+ go(%W[select-window -t #{win}])
+ end
+
+ def send_keys(*args)
+ go(%W[send-keys -t #{win}] + args.map(&:to_s))
+ end
+
+ def paste(str)
+ system('tmux', 'setb', str, ';', 'pasteb', '-t', win, ';', 'send-keys', '-t', win, 'Enter')
+ end
+
+ def capture
+ go(%W[capture-pane -p -J -t #{win}]).map(&:rstrip).reverse.drop_while(&:empty?).reverse
+ end
+
+ def until(refresh = false)
+ lines = nil
+ begin
+ wait do
+ lines = capture
+ class << lines
+ def counts
+ lazy
+ .map { |l| l.scan(%r{^. ([0-9]+)/([0-9]+)( \(([0-9]+)\))?}) }
+ .reject(&:empty?)
+ .first&.first&.map(&:to_i)&.values_at(0, 1, 3) || [0, 0, 0]
+ end
+
+ def match_count
+ counts[0]
+ end
+
+ def item_count
+ counts[1]
+ end
+
+ def select_count
+ counts[2]
+ end
+
+ def any_include?(val)
+ method = val.is_a?(Regexp) ? :match : :include?
+ find { |line| line.send(method, val) }
+ end
+ end
+ yield(lines).tap do |ok|
+ send_keys 'C-l' if refresh && !ok
+ end
+ end
+ rescue Minitest::Assertion
+ puts $ERROR_INFO.backtrace
+ puts '>' * 80
+ puts lines
+ puts '<' * 80
+ raise
+ end
+ lines
+ end
+
+ def prepare
+ tries = 0
+ begin
+ self.until(true) do |lines|
+ message = "Prepare[#{tries}]"
+ send_keys ' ', 'C-u', :Enter, message, :Left, :Right
+ lines[-1] == message
+ end
+ rescue Minitest::Assertion
+ (tries += 1) < 5 ? retry : raise
+ end
+ send_keys 'C-u', 'C-l'
+ end
+
+ private
+
+ def go(args)
+ IO.popen(%w[tmux] + args) { |io| io.readlines(chomp: true) }
+ end
+end
+
+class TestBase < Minitest::Test
+ TEMPNAME = '/tmp/output'
+
+ attr_reader :tmux
+
+ def tempname
+ @temp_suffix ||= 0
+ [TEMPNAME,
+ caller_locations.map(&:label).find { |l| l.start_with?('test_') },
+ @temp_suffix].join('-')
+ end
+
+ def writelines(path, lines)
+ File.unlink(path) while File.exist?(path)
+ File.open(path, 'w') { |f| f.puts lines }
+ end
+
+ def readonce
+ wait { assert_path_exists tempname }
+ File.read(tempname)
+ ensure
+ File.unlink(tempname) while File.exist?(tempname)
+ @temp_suffix += 1
+ tmux.prepare
+ end
+
+ def fzf(*opts)
+ fzf!(*opts) + " > #{tempname}.tmp; mv #{tempname}.tmp #{tempname}"
+ end
+
+ def fzf!(*opts)
+ opts = opts.map do |o|
+ case o
+ when Symbol
+ o = o.to_s
+ o.length > 1 ? "--#{o.tr('_', '-')}" : "-#{o}"
+ when String, Numeric
+ o.to_s
+ end
+ end.compact
+ "#{FZF} #{opts.join(' ')}"
+ end
+end
+
+class TestGoFZF < TestBase
+ def setup
+ super
+ @tmux = Tmux.new
+ end
+
+ def teardown
+ @tmux.kill
+ end
+
+ def test_vanilla
+ tmux.send_keys "seq 1 100000 | #{fzf}", :Enter
+ tmux.until do |lines|
+ assert_equal '>', lines.last
+ assert_equal ' 100000/100000', lines[-2]
+ end
+ lines = tmux.capture
+ assert_equal ' 2', lines[-4]
+ assert_equal '> 1', lines[-3]
+ assert_equal ' 100000/100000', lines[-2]
+ assert_equal '>', lines[-1]
+
+ # Testing basic key bindings
+ tmux.send_keys '99', 'C-a', '1', 'C-f', '3', 'C-b', 'C-h', 'C-u', 'C-e', 'C-y', 'C-k', 'Tab', 'BTab'
+ tmux.until do |lines|
+ assert_equal '> 3910', lines[-4]
+ assert_equal ' 391', lines[-3]
+ assert_equal ' 856/100000', lines[-2]
+ assert_equal '> 391', lines[-1]
+ end
+
+ tmux.send_keys :Enter
+ assert_equal '3910', readonce.chomp
+ end
+
+ def test_fzf_default_command
+ tmux.send_keys fzf.sub('FZF_DEFAULT_COMMAND=', "FZF_DEFAULT_COMMAND='echo hello'"), :Enter
+ tmux.until { |lines| assert_equal '> hello', lines[-3] }
+
+ tmux.send_keys :Enter
+ assert_equal 'hello', readonce.chomp
+ end
+
+ def test_fzf_default_command_failure
+ tmux.send_keys fzf.sub('FZF_DEFAULT_COMMAND=', 'FZF_DEFAULT_COMMAND=false'), :Enter
+ tmux.until { |lines| assert_equal ' [Command failed: false]', lines[-2] }
+ tmux.send_keys :Enter
+ end
+
+ def test_key_bindings
+ tmux.send_keys "#{FZF} -q 'foo bar foo-bar'", :Enter
+ tmux.until { |lines| assert_equal '> foo bar foo-bar', lines.last }
+
+ # CTRL-A
+ tmux.send_keys 'C-A', '('
+ tmux.until { |lines| assert_equal '> (foo bar foo-bar', lines.last }
+
+ # META-F
+ tmux.send_keys :Escape, :f, ')'
+ tmux.until { |lines| assert_equal '> (foo) bar foo-bar', lines.last }
+
+ # CTRL-B
+ tmux.send_keys 'C-B', 'var'
+ tmux.until { |lines| assert_equal '> (foovar) bar foo-bar', lines.last }
+
+ # Left, CTRL-D
+ tmux.send_keys :Left, :Left, 'C-D'
+ tmux.until { |lines| assert_equal '> (foovr) bar foo-bar', lines.last }
+
+ # META-BS
+ tmux.send_keys :Escape, :BSpace
+ tmux.until { |lines| assert_equal '> (r) bar foo-bar', lines.last }
+
+ # CTRL-Y
+ tmux.send_keys 'C-Y', 'C-Y'
+ tmux.until { |lines| assert_equal '> (foovfoovr) bar foo-bar', lines.last }
+
+ # META-B
+ tmux.send_keys :Escape, :b, :Space, :Space
+ tmux.until { |lines| assert_equal '> ( foovfoovr) bar foo-bar', lines.last }
+
+ # CTRL-F / Right
+ tmux.send_keys 'C-F', :Right, '/'
+ tmux.until { |lines| assert_equal '> ( fo/ovfoovr) bar foo-bar', lines.last }
+
+ # CTRL-H / BS
+ tmux.send_keys 'C-H', :BSpace
+ tmux.until { |lines| assert_equal '> ( fovfoovr) bar foo-bar', lines.last }
+
+ # CTRL-E
+ tmux.send_keys 'C-E', 'baz'
+ tmux.until { |lines| assert_equal '> ( fovfoovr) bar foo-barbaz', lines.last }
+
+ # CTRL-U
+ tmux.send_keys 'C-U'
+ tmux.until { |lines| assert_equal '>', lines.last }
+
+ # CTRL-Y
+ tmux.send_keys 'C-Y'
+ tmux.until { |lines| assert_equal '> ( fovfoovr) bar foo-barbaz', lines.last }
+
+ # CTRL-W
+ tmux.send_keys 'C-W', 'bar-foo'
+ tmux.until { |lines| assert_equal '> ( fovfoovr) bar bar-foo', lines.last }
+
+ # META-D
+ tmux.send_keys :Escape, :b, :Escape, :b, :Escape, :d, 'C-A', 'C-Y'
+ tmux.until { |lines| assert_equal '> bar( fovfoovr) bar -foo', lines.last }
+
+ # CTRL-M
+ tmux.send_keys 'C-M'
+ tmux.until { |lines| refute_equal '>', lines.last }
+ end
+
+ def test_file_word
+ tmux.send_keys "#{FZF} -q '--/foo bar/foo-bar/baz' --filepath-word", :Enter
+ tmux.until { |lines| assert_equal '> --/foo bar/foo-bar/baz', lines.last }
+
+ tmux.send_keys :Escape, :b
+ tmux.send_keys :Escape, :b
+ tmux.send_keys :Escape, :b
+ tmux.send_keys :Escape, :d
+ tmux.send_keys :Escape, :f
+ tmux.send_keys :Escape, :BSpace
+ tmux.until { |lines| assert_equal '> --///baz', lines.last }
+ end
+
+ def test_multi_order
+ tmux.send_keys "seq 1 10 | #{fzf(:multi)}", :Enter
+ tmux.until { |lines| assert_equal '>', lines.last }
+
+ tmux.send_keys :Tab, :Up, :Up, :Tab, :Tab, :Tab, # 3, 2
+ 'C-K', 'C-K', 'C-K', 'C-K', :BTab, :BTab, # 5, 6
+ :PgUp, 'C-J', :Down, :Tab, :Tab # 8, 7
+ tmux.until { |lines| assert_equal ' 10/10 (6)', lines[-2] }
+ tmux.send_keys 'C-M'
+ assert_equal %w[3 2 5 6 8 7], readonce.lines(chomp: true)
+ end
+
+ def test_multi_max
+ tmux.send_keys "seq 1 10 | #{FZF} -m 3 --bind A:select-all,T:toggle-all --preview 'echo [{+}]/{}'", :Enter
+
+ tmux.until { |lines| assert_equal 10, lines.item_count }
+
+ tmux.send_keys '1'
+ tmux.until do |lines|
+ assert_includes lines[1], ' [1]/1 '
+ assert lines[-2]&.start_with?(' 2/10 ')
+ end
+
+ tmux.send_keys 'A'
+ tmux.until do |lines|
+ assert_includes lines[1], ' [1 10]/1 '
+ assert lines[-2]&.start_with?(' 2/10 (2/3)')
+ end
+
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert lines[-2]&.start_with?(' 10/10 (2/3)') }
+
+ tmux.send_keys 'T'
+ tmux.until do |lines|
+ assert_includes lines[1], ' [2 3 4]/1 '
+ assert lines[-2]&.start_with?(' 10/10 (3/3)')
+ end
+
+ %w[T A].each do |key|
+ tmux.send_keys key
+ tmux.until do |lines|
+ assert_includes lines[1], ' [1 5 6]/1 '
+ assert lines[-2]&.start_with?(' 10/10 (3/3)')
+ end
+ end
+
+ tmux.send_keys :BTab
+ tmux.until do |lines|
+ assert_includes lines[1], ' [5 6]/2 '
+ assert lines[-2]&.start_with?(' 10/10 (2/3)')
+ end
+
+ [:BTab, :BTab, 'A'].each do |key|
+ tmux.send_keys key
+ tmux.until do |lines|
+ assert_includes lines[1], ' [5 6 2]/3 '
+ assert lines[-2]&.start_with?(' 10/10 (3/3)')
+ end
+ end
+
+ tmux.send_keys '2'
+ tmux.until { |lines| assert lines[-2]&.start_with?(' 1/10 (3/3)') }
+
+ tmux.send_keys 'T'
+ tmux.until do |lines|
+ assert_includes lines[1], ' [5 6]/2 '
+ assert lines[-2]&.start_with?(' 1/10 (2/3)')
+ end
+
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert lines[-2]&.start_with?(' 10/10 (2/3)') }
+
+ tmux.send_keys 'A'
+ tmux.until do |lines|
+ assert_includes lines[1], ' [5 6 1]/1 '
+ assert lines[-2]&.start_with?(' 10/10 (3/3)')
+ end
+ end
+
+ def test_with_nth
+ [true, false].each do |multi|
+ tmux.send_keys "(echo ' 1st 2nd 3rd/';
+ echo ' first second third/') |
+ #{fzf(multi && :multi, :x, :nth, 2, :with_nth, '2,-1,1')}",
+ :Enter
+ tmux.until { |lines| assert_equal multi ? ' 2/2 (0)' : ' 2/2', lines[-2] }
+
+ # Transformed list
+ lines = tmux.capture
+ assert_equal ' second third/first', lines[-4]
+ assert_equal '> 2nd 3rd/1st', lines[-3]
+
+ # However, the output must not be transformed
+ if multi
+ tmux.send_keys :BTab, :BTab
+ tmux.until { |lines| assert_equal ' 2/2 (2)', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal [' 1st 2nd 3rd/', ' first second third/'], readonce.lines(chomp: true)
+ else
+ tmux.send_keys '^', '3'
+ tmux.until { |lines| assert_equal ' 1/2', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal [' 1st 2nd 3rd/'], readonce.lines(chomp: true)
+ end
+ end
+ end
+
+ def test_scroll
+ [true, false].each do |rev|
+ tmux.send_keys "seq 1 100 | #{fzf(rev && :reverse)}", :Enter
+ tmux.until { |lines| assert_includes lines, ' 100/100' }
+ tmux.send_keys(*Array.new(110) { rev ? :Down : :Up })
+ tmux.until { |lines| assert_includes lines, '> 100' }
+ tmux.send_keys :Enter
+ assert_equal '100', readonce.chomp
+ end
+ end
+
+ def test_select_1
+ tmux.send_keys "seq 1 100 | #{fzf(:with_nth, '..,..', :print_query, :q, 5555, :'1')}", :Enter
+ assert_equal %w[5555 55], readonce.lines(chomp: true)
+ end
+
+ def test_exit_0
+ tmux.send_keys "seq 1 100 | #{fzf(:with_nth, '..,..', :print_query, :q, 555_555, :'0')}", :Enter
+ assert_equal %w[555555], readonce.lines(chomp: true)
+ end
+
+ def test_select_1_exit_0_fail
+ [:'0', :'1', %i[1 0]].each do |opt|
+ tmux.send_keys "seq 1 100 | #{fzf(:print_query, :multi, :q, 5, *opt)}", :Enter
+ tmux.until { |lines| assert_equal '> 5', lines.last }
+ tmux.send_keys :BTab, :BTab, :BTab
+ tmux.until { |lines| assert_equal ' 19/100 (3)', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal %w[5 5 50 51], readonce.lines(chomp: true)
+ end
+ end
+
+ def test_query_unicode
+ tmux.paste "(echo abc; echo $'\\352\\260\\200\\353\\202\\230\\353\\213\\244') | #{fzf(:query, "$'\\352\\260\\200\\353\\213\\244'")}"
+ tmux.until { |lines| assert_equal ' 1/2', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal %w[가나다], readonce.lines(chomp: true)
+ end
+
+ def test_sync
+ tmux.send_keys "seq 1 100 | #{fzf!(:multi)} | awk '{print $1 $1}' | #{fzf(:sync)}", :Enter
+ tmux.until { |lines| assert_equal '>', lines[-1] }
+ tmux.send_keys 9
+ tmux.until { |lines| assert_equal ' 19/100 (0)', lines[-2] }
+ tmux.send_keys :BTab, :BTab, :BTab
+ tmux.until { |lines| assert_equal ' 19/100 (3)', lines[-2] }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal '>', lines[-1] }
+ tmux.send_keys 'C-K', :Enter
+ assert_equal %w[9090], readonce.lines(chomp: true)
+ end
+
+ def test_tac
+ tmux.send_keys "seq 1 1000 | #{fzf(:tac, :multi)}", :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000 (0)', lines[-2] }
+ tmux.send_keys :BTab, :BTab, :BTab
+ tmux.until { |lines| assert_equal ' 1000/1000 (3)', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal %w[1000 999 998], readonce.lines(chomp: true)
+ end
+
+ def test_tac_sort
+ tmux.send_keys "seq 1 1000 | #{fzf(:tac, :multi)}", :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000 (0)', lines[-2] }
+ tmux.send_keys '99'
+ tmux.until { |lines| assert_equal ' 28/1000 (0)', lines[-2] }
+ tmux.send_keys :BTab, :BTab, :BTab
+ tmux.until { |lines| assert_equal ' 28/1000 (3)', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal %w[99 999 998], readonce.lines(chomp: true)
+ end
+
+ def test_tac_nosort
+ tmux.send_keys "seq 1 1000 | #{fzf(:tac, :no_sort, :multi)}", :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000 (0)', lines[-2] }
+ tmux.send_keys '00'
+ tmux.until { |lines| assert_equal ' 10/1000 (0)', lines[-2] }
+ tmux.send_keys :BTab, :BTab, :BTab
+ tmux.until { |lines| assert_equal ' 10/1000 (3)', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal %w[1000 900 800], readonce.lines(chomp: true)
+ end
+
+ def test_expect
+ test = lambda do |key, feed, expected = key|
+ tmux.send_keys "seq 1 100 | #{fzf(:expect, key)}", :Enter
+ tmux.until { |lines| assert_equal ' 100/100', lines[-2] }
+ tmux.send_keys '55'
+ tmux.until { |lines| assert_equal ' 1/100', lines[-2] }
+ tmux.send_keys(*feed)
+ tmux.prepare
+ assert_equal [expected, '55'], readonce.lines(chomp: true)
+ end
+ test.call('ctrl-t', 'C-T')
+ test.call('ctrl-t', 'Enter', '')
+ test.call('alt-c', %i[Escape c])
+ test.call('f1', 'f1')
+ test.call('f2', 'f2')
+ test.call('f3', 'f3')
+ test.call('f2,f4', 'f2', 'f2')
+ test.call('f2,f4', 'f4', 'f4')
+ test.call('alt-/', %i[Escape /])
+ %w[f5 f6 f7 f8 f9 f10].each do |key|
+ test.call('f5,f6,f7,f8,f9,f10', key, key)
+ end
+ test.call('@', '@')
+ end
+
+ def test_expect_print_query
+ tmux.send_keys "seq 1 100 | #{fzf('--expect=alt-z', :print_query)}", :Enter
+ tmux.until { |lines| assert_equal ' 100/100', lines[-2] }
+ tmux.send_keys '55'
+ tmux.until { |lines| assert_equal ' 1/100', lines[-2] }
+ tmux.send_keys :Escape, :z
+ assert_equal %w[55 alt-z 55], readonce.lines(chomp: true)
+ end
+
+ def test_expect_printable_character_print_query
+ tmux.send_keys "seq 1 100 | #{fzf('--expect=z --print-query')}", :Enter
+ tmux.until { |lines| assert_equal ' 100/100', lines[-2] }
+ tmux.send_keys '55'
+ tmux.until { |lines| assert_equal ' 1/100', lines[-2] }
+ tmux.send_keys 'z'
+ assert_equal %w[55 z 55], readonce.lines(chomp: true)
+ end
+
+ def test_expect_print_query_select_1
+ tmux.send_keys "seq 1 100 | #{fzf('-q55 -1 --expect=alt-z --print-query')}", :Enter
+ assert_equal ['55', '', '55'], readonce.lines(chomp: true)
+ end
+
+ def test_toggle_sort
+ ['--toggle-sort=ctrl-r', '--bind=ctrl-r:toggle-sort'].each do |opt|
+ tmux.send_keys "seq 1 111 | #{fzf("-m +s --tac #{opt} -q11")}", :Enter
+ tmux.until { |lines| assert_equal '> 111', lines[-3] }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal ' 4/111 -S (1)', lines[-2] }
+ tmux.send_keys 'C-R'
+ tmux.until { |lines| assert_equal '> 11', lines[-3] }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal ' 4/111 +S (2)', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal %w[111 11], readonce.lines(chomp: true)
+ end
+ end
+
+ def test_unicode_case
+ writelines(tempname, %w[строКА1 СТРОКА2 строка3 Строка4])
+ assert_equal %w[СТРОКА2 Строка4], `#{FZF} -fС < #{tempname}`.lines(chomp: true)
+ assert_equal %w[строКА1 СТРОКА2 строка3 Строка4], `#{FZF} -fс < #{tempname}`.lines(chomp: true)
+ end
+
+ def test_tiebreak
+ input = %w[
+ --foobar--------
+ -----foobar---
+ ----foobar--
+ -------foobar-
+ ]
+ writelines(tempname, input)
+
+ assert_equal input, `#{FZF} -ffoobar --tiebreak=index < #{tempname}`.lines(chomp: true)
+
+ by_length = %w[
+ ----foobar--
+ -----foobar---
+ -------foobar-
+ --foobar--------
+ ]
+ assert_equal by_length, `#{FZF} -ffoobar < #{tempname}`.lines(chomp: true)
+ assert_equal by_length, `#{FZF} -ffoobar --tiebreak=length < #{tempname}`.lines(chomp: true)
+
+ by_begin = %w[
+ --foobar--------
+ ----foobar--
+ -----foobar---
+ -------foobar-
+ ]
+ assert_equal by_begin, `#{FZF} -ffoobar --tiebreak=begin < #{tempname}`.lines(chomp: true)
+ assert_equal by_begin, `#{FZF} -f"!z foobar" -x --tiebreak begin < #{tempname}`.lines(chomp: true)
+
+ assert_equal %w[
+ -------foobar-
+ ----foobar--
+ -----foobar---
+ --foobar--------
+ ], `#{FZF} -ffoobar --tiebreak end < #{tempname}`.lines(chomp: true)
+
+ assert_equal input, `#{FZF} -f"!z" -x --tiebreak end < #{tempname}`.lines(chomp: true)
+ end
+
+ def test_tiebreak_index_begin
+ writelines(tempname, [
+ 'xoxxxxxoxx',
+ 'xoxxxxxox',
+ 'xxoxxxoxx',
+ 'xxxoxoxxx',
+ 'xxxxoxox',
+ ' xxoxoxxx'
+ ])
+
+ assert_equal [
+ 'xxxxoxox',
+ ' xxoxoxxx',
+ 'xxxoxoxxx',
+ 'xxoxxxoxx',
+ 'xoxxxxxox',
+ 'xoxxxxxoxx'
+ ], `#{FZF} -foo < #{tempname}`.lines(chomp: true)
+
+ assert_equal [
+ 'xxxoxoxxx',
+ 'xxxxoxox',
+ ' xxoxoxxx',
+ 'xxoxxxoxx',
+ 'xoxxxxxoxx',
+ 'xoxxxxxox'
+ ], `#{FZF} -foo --tiebreak=index < #{tempname}`.lines(chomp: true)
+
+ # Note that --tiebreak=begin is now based on the first occurrence of the
+ # first character on the pattern
+ assert_equal [
+ ' xxoxoxxx',
+ 'xxxoxoxxx',
+ 'xxxxoxox',
+ 'xxoxxxoxx',
+ 'xoxxxxxoxx',
+ 'xoxxxxxox'
+ ], `#{FZF} -foo --tiebreak=begin < #{tempname}`.lines(chomp: true)
+
+ assert_equal [
+ ' xxoxoxxx',
+ 'xxxoxoxxx',
+ 'xxxxoxox',
+ 'xxoxxxoxx',
+ 'xoxxxxxox',
+ 'xoxxxxxoxx'
+ ], `#{FZF} -foo --tiebreak=begin,length < #{tempname}`.lines(chomp: true)
+ end
+
+ def test_tiebreak_begin_algo_v2
+ writelines(tempname, [
+ 'baz foo bar',
+ 'foo bar baz'
+ ])
+ assert_equal [
+ 'foo bar baz',
+ 'baz foo bar'
+ ], `#{FZF} -fbar --tiebreak=begin --algo=v2 < #{tempname}`.lines(chomp: true)
+ end
+
+ def test_tiebreak_end
+ writelines(tempname, [
+ 'xoxxxxxxxx',
+ 'xxoxxxxxxx',
+ 'xxxoxxxxxx',
+ 'xxxxoxxxx',
+ 'xxxxxoxxx',
+ ' xxxxoxxx'
+ ])
+
+ assert_equal [
+ ' xxxxoxxx',
+ 'xxxxoxxxx',
+ 'xxxxxoxxx',
+ 'xoxxxxxxxx',
+ 'xxoxxxxxxx',
+ 'xxxoxxxxxx'
+ ], `#{FZF} -fo < #{tempname}`.lines(chomp: true)
+
+ assert_equal [
+ 'xxxxxoxxx',
+ ' xxxxoxxx',
+ 'xxxxoxxxx',
+ 'xxxoxxxxxx',
+ 'xxoxxxxxxx',
+ 'xoxxxxxxxx'
+ ], `#{FZF} -fo --tiebreak=end < #{tempname}`.lines(chomp: true)
+
+ assert_equal [
+ 'xxxxxoxxx',
+ ' xxxxoxxx',
+ 'xxxxoxxxx',
+ 'xxxoxxxxxx',
+ 'xxoxxxxxxx',
+ 'xoxxxxxxxx'
+ ], `#{FZF} -fo --tiebreak=end,length,begin < #{tempname}`.lines(chomp: true)
+ end
+
+ def test_tiebreak_length_with_nth
+ input = %w[
+ 1:hell
+ 123:hello
+ 12345:he
+ 1234567:h
+ ]
+ writelines(tempname, input)
+
+ output = %w[
+ 1:hell
+ 12345:he
+ 123:hello
+ 1234567:h
+ ]
+ assert_equal output, `#{FZF} -fh < #{tempname}`.lines(chomp: true)
+
+ # Since 0.16.8, --nth doesn't affect --tiebreak
+ assert_equal output, `#{FZF} -fh -n2 -d: < #{tempname}`.lines(chomp: true)
+ end
+
+ def test_tiebreak_chunk
+ writelines(tempname, [
+ '1 foobarbaz ba',
+ '2 foobar baz',
+ '3 foo barbaz'
+ ])
+
+ assert_equal [
+ '3 foo barbaz',
+ '2 foobar baz',
+ '1 foobarbaz ba'
+ ], `#{FZF} -fo --tiebreak=chunk < #{tempname}`.lines(chomp: true)
+
+ assert_equal [
+ '1 foobarbaz ba',
+ '2 foobar baz',
+ '3 foo barbaz'
+ ], `#{FZF} -fba --tiebreak=chunk < #{tempname}`.lines(chomp: true)
+ end
+
+ def test_invalid_cache
+ tmux.send_keys "(echo d; echo D; echo x) | #{fzf('-q d')}", :Enter
+ tmux.until { |lines| assert_equal ' 2/3', lines[-2] }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert_equal ' 3/3', lines[-2] }
+ tmux.send_keys :D
+ tmux.until { |lines| assert_equal ' 1/3', lines[-2] }
+ tmux.send_keys :Enter
+ end
+
+ def test_invalid_cache_query_type
+ command = %[(echo 'foo$bar'; echo 'barfoo'; echo 'foo^bar'; echo "foo'1-2"; seq 100) | #{fzf}]
+
+ # Suffix match
+ tmux.send_keys command, :Enter
+ tmux.until { |lines| assert_equal 104, lines.match_count }
+ tmux.send_keys 'foo$'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys 'bar'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Enter
+
+ # Prefix match
+ tmux.prepare
+ tmux.send_keys command, :Enter
+ tmux.until { |lines| assert_equal 104, lines.match_count }
+ tmux.send_keys '^bar'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys 'C-a', 'foo'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Enter
+
+ # Exact match
+ tmux.prepare
+ tmux.send_keys command, :Enter
+ tmux.until { |lines| assert_equal 104, lines.match_count }
+ tmux.send_keys "'12"
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys 'C-a', 'foo'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ end
+
+ def test_smart_case_for_each_term
+ assert_equal 1, `echo Foo bar | #{FZF} -x -f "foo Fbar" | wc -l`.to_i
+ end
+
+ def test_bind
+ tmux.send_keys "seq 1 1000 | #{fzf('-m --bind=ctrl-j:accept,u:up,T:toggle-up,t:toggle')}", :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000 (0)', lines[-2] }
+ tmux.send_keys 'uuu', 'TTT', 'tt', 'uu', 'ttt', 'C-j'
+ assert_equal %w[4 5 6 9], readonce.lines(chomp: true)
+ end
+
+ def test_bind_print_query
+ tmux.send_keys "seq 1 1000 | #{fzf('-m --bind=ctrl-j:print-query')}", :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000 (0)', lines[-2] }
+ tmux.send_keys 'print-my-query', 'C-j'
+ assert_equal %w[print-my-query], readonce.lines(chomp: true)
+ end
+
+ def test_bind_replace_query
+ tmux.send_keys "seq 1 1000 | #{fzf('--print-query --bind=ctrl-j:replace-query')}", :Enter
+ tmux.send_keys '1'
+ tmux.until { |lines| assert_equal ' 272/1000', lines[-2] }
+ tmux.send_keys 'C-k', 'C-j'
+ tmux.until { |lines| assert_equal ' 29/1000', lines[-2] }
+ tmux.until { |lines| assert_equal '> 10', lines[-1] }
+ end
+
+ def test_long_line
+ data = '.' * 256 * 1024
+ File.open(tempname, 'w') do |f|
+ f << data
+ end
+ assert_equal data, `#{FZF} -f . < #{tempname}`.chomp
+ end
+
+ def test_read0
+ lines = `find .`.lines(chomp: true)
+ assert_equal lines.last, `find . | #{FZF} -e -f "^#{lines.last}$"`.chomp
+ assert_equal \
+ lines.last,
+ `find . -print0 | #{FZF} --read0 -e -f "^#{lines.last}$"`.chomp
+ end
+
+ def test_select_all_deselect_all_toggle_all
+ tmux.send_keys "seq 100 | #{fzf('--bind ctrl-a:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all --multi')}", :Enter
+ tmux.until { |lines| assert_equal ' 100/100 (0)', lines[-2] }
+ tmux.send_keys :BTab, :BTab, :BTab
+ tmux.until { |lines| assert_equal ' 100/100 (3)', lines[-2] }
+ tmux.send_keys 'C-t'
+ tmux.until { |lines| assert_equal ' 100/100 (97)', lines[-2] }
+ tmux.send_keys 'C-a'
+ tmux.until { |lines| assert_equal ' 100/100 (100)', lines[-2] }
+ tmux.send_keys :Tab, :Tab
+ tmux.until { |lines| assert_equal ' 100/100 (98)', lines[-2] }
+ tmux.send_keys '100'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys 'C-d'
+ tmux.until { |lines| assert_equal ' 1/100 (97)', lines[-2] }
+ tmux.send_keys 'C-u'
+ tmux.until { |lines| assert_equal 100, lines.match_count }
+ tmux.send_keys 'C-d'
+ tmux.until { |lines| assert_equal ' 100/100 (0)', lines[-2] }
+ tmux.send_keys :BTab, :BTab
+ tmux.until { |lines| assert_equal ' 100/100 (2)', lines[-2] }
+ tmux.send_keys 0
+ tmux.until { |lines| assert_equal ' 10/100 (2)', lines[-2] }
+ tmux.send_keys 'C-a'
+ tmux.until { |lines| assert_equal ' 10/100 (12)', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal %w[1 2 10 20 30 40 50 60 70 80 90 100],
+ readonce.lines(chomp: true)
+ end
+
+ def test_history
+ history_file = '/tmp/fzf-test-history'
+
+ # History with limited number of entries
+ begin
+ File.unlink(history_file)
+ rescue StandardError
+ nil
+ end
+ opts = "--history=#{history_file} --history-size=4"
+ input = %w[00 11 22 33 44]
+ input.each do |keys|
+ tmux.prepare
+ tmux.send_keys "seq 100 | #{fzf(opts)}", :Enter
+ tmux.until { |lines| assert_equal ' 100/100', lines[-2] }
+ tmux.send_keys keys
+ tmux.until { |lines| assert_equal ' 1/100', lines[-2] }
+ tmux.send_keys :Enter
+ end
+ wait do
+ assert_path_exists history_file
+ assert_equal input[1..-1], File.readlines(history_file, chomp: true)
+ end
+
+ # Update history entries (not changed on disk)
+ tmux.send_keys "seq 100 | #{fzf(opts)}", :Enter
+ tmux.until { |lines| assert_equal ' 100/100', lines[-2] }
+ tmux.send_keys 'C-p'
+ tmux.until { |lines| assert_equal '> 44', lines[-1] }
+ tmux.send_keys 'C-p'
+ tmux.until { |lines| assert_equal '> 33', lines[-1] }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert_equal '> 3', lines[-1] }
+ tmux.send_keys 1
+ tmux.until { |lines| assert_equal '> 31', lines[-1] }
+ tmux.send_keys 'C-p'
+ tmux.until { |lines| assert_equal '> 22', lines[-1] }
+ tmux.send_keys 'C-n'
+ tmux.until { |lines| assert_equal '> 31', lines[-1] }
+ tmux.send_keys 0
+ tmux.until { |lines| assert_equal '> 310', lines[-1] }
+ tmux.send_keys :Enter
+ wait do
+ assert_path_exists history_file
+ assert_equal %w[22 33 44 310], File.readlines(history_file, chomp: true)
+ end
+
+ # Respect --bind option
+ tmux.send_keys "seq 100 | #{fzf(opts + ' --bind ctrl-p:next-history,ctrl-n:previous-history')}", :Enter
+ tmux.until { |lines| assert_equal ' 100/100', lines[-2] }
+ tmux.send_keys 'C-n', 'C-n', 'C-n', 'C-n', 'C-p'
+ tmux.until { |lines| assert_equal '> 33', lines[-1] }
+ tmux.send_keys :Enter
+ ensure
+ File.unlink(history_file)
+ end
+
+ def test_execute
+ output = '/tmp/fzf-test-execute'
+ opts = %[--bind "alt-a:execute(echo /{}/ >> #{output}),alt-b:execute[echo /{}{}/ >> #{output}],C:execute:echo /{}{}{}/ >> #{output}"]
+ writelines(tempname, %w[foo'bar foo"bar foo$bar])
+ tmux.send_keys "cat #{tempname} | #{fzf(opts)}", :Enter
+ tmux.until { |lines| assert_equal ' 3/3', lines[-2] }
+ tmux.send_keys :Escape, :a
+ tmux.send_keys :Escape, :a
+ tmux.send_keys :Up
+ tmux.send_keys :Escape, :b
+ tmux.send_keys :Escape, :b
+ tmux.send_keys :Up
+ tmux.send_keys :C
+ tmux.send_keys 'barfoo'
+ tmux.until { |lines| assert_equal ' 0/3', lines[-2] }
+ tmux.send_keys :Escape, :a
+ tmux.send_keys :Escape, :b
+ wait do
+ assert_path_exists output
+ assert_equal %w[
+ /foo'bar/ /foo'bar/
+ /foo"barfoo"bar/ /foo"barfoo"bar/
+ /foo$barfoo$barfoo$bar/
+ ], File.readlines(output, chomp: true)
+ end
+ ensure
+ begin
+ File.unlink(output)
+ rescue StandardError
+ nil
+ end
+ end
+
+ def test_execute_multi
+ output = '/tmp/fzf-test-execute-multi'
+ opts = %[--multi --bind "alt-a:execute-multi(echo {}/{+} >> #{output})"]
+ writelines(tempname, %w[foo'bar foo"bar foo$bar foobar])
+ tmux.send_keys "cat #{tempname} | #{fzf(opts)}", :Enter
+ tmux.until { |lines| assert_equal ' 4/4 (0)', lines[-2] }
+ tmux.send_keys :Escape, :a
+ tmux.send_keys :BTab, :BTab, :BTab
+ tmux.until { |lines| assert_equal ' 4/4 (3)', lines[-2] }
+ tmux.send_keys :Escape, :a
+ tmux.send_keys :Tab, :Tab
+ tmux.until { |lines| assert_equal ' 4/4 (3)', lines[-2] }
+ tmux.send_keys :Escape, :a
+ wait do
+ assert_path_exists output
+ assert_equal [
+ %(foo'bar/foo'bar),
+ %(foo'bar foo"bar foo$bar/foo'bar foo"bar foo$bar),
+ %(foo'bar foo"bar foobar/foo'bar foo"bar foobar)
+ ], File.readlines(output, chomp: true)
+ end
+ ensure
+ begin
+ File.unlink(output)
+ rescue StandardError
+ nil
+ end
+ end
+
+ def test_execute_plus_flag
+ output = tempname + '.tmp'
+ begin
+ File.unlink(output)
+ rescue StandardError
+ nil
+ end
+ writelines(tempname, ['foo bar', '123 456'])
+
+ tmux.send_keys "cat #{tempname} | #{FZF} --multi --bind 'x:execute-silent(echo {+}/{}/{+2}/{2} >> #{output})'", :Enter
+
+ tmux.until { |lines| assert_equal ' 2/2 (0)', lines[-2] }
+ tmux.send_keys 'xy'
+ tmux.until { |lines| assert_equal ' 0/2 (0)', lines[-2] }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert_equal ' 2/2 (0)', lines[-2] }
+
+ tmux.send_keys :Up
+ tmux.send_keys :Tab
+ tmux.send_keys 'xy'
+ tmux.until { |lines| assert_equal ' 0/2 (1)', lines[-2] }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert_equal ' 2/2 (1)', lines[-2] }
+
+ tmux.send_keys :Tab
+ tmux.send_keys 'xy'
+ tmux.until { |lines| assert_equal ' 0/2 (2)', lines[-2] }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert_equal ' 2/2 (2)', lines[-2] }
+
+ wait do
+ assert_path_exists output
+ assert_equal [
+ %(foo bar/foo bar/bar/bar),
+ %(123 456/foo bar/456/bar),
+ %(123 456 foo bar/foo bar/456 bar/bar)
+ ], File.readlines(output, chomp: true)
+ end
+ rescue StandardError
+ begin
+ File.unlink(output)
+ rescue StandardError
+ nil
+ end
+ end
+
+ def test_execute_shell
+ # Custom script to use as $SHELL
+ output = tempname + '.out'
+ begin
+ File.unlink(output)
+ rescue StandardError
+ nil
+ end
+ writelines(tempname,
+ ['#!/usr/bin/env bash', "echo $1 / $2 > #{output}"])
+ system("chmod +x #{tempname}")
+
+ tmux.send_keys "echo foo | SHELL=#{tempname} fzf --bind 'enter:execute:{}bar'", :Enter
+ tmux.until { |lines| assert_equal ' 1/1', lines[-2] }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal ' 1/1', lines[-2] }
+ wait do
+ assert_path_exists output
+ assert_equal ["-c / 'foo'bar"], File.readlines(output, chomp: true)
+ end
+ ensure
+ begin
+ File.unlink(output)
+ rescue StandardError
+ nil
+ end
+ end
+
+ def test_cycle
+ tmux.send_keys "seq 8 | #{fzf(:cycle)}", :Enter
+ tmux.until { |lines| assert_equal ' 8/8', lines[-2] }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal '> 8', lines[-10] }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal '> 7', lines[-9] }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal '> 8', lines[-10] }
+ tmux.send_keys :PgUp
+ tmux.until { |lines| assert_equal '> 8', lines[-10] }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal '> 1', lines[-3] }
+ tmux.send_keys :PgDn
+ tmux.until { |lines| assert_equal '> 1', lines[-3] }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal '> 8', lines[-10] }
+ end
+
+ def test_header_lines
+ tmux.send_keys "seq 100 | #{fzf('--header-lines=10 -q 5')}", :Enter
+ 2.times do
+ tmux.until do |lines|
+ assert_equal ' 18/90', lines[-2]
+ assert_equal ' 1', lines[-3]
+ assert_equal ' 2', lines[-4]
+ assert_equal '> 50', lines[-13]
+ end
+ tmux.send_keys :Down
+ end
+ tmux.send_keys :Enter
+ assert_equal '50', readonce.chomp
+ end
+
+ def test_header_lines_reverse
+ tmux.send_keys "seq 100 | #{fzf('--header-lines=10 -q 5 --reverse')}", :Enter
+ 2.times do
+ tmux.until do |lines|
+ assert_equal ' 18/90', lines[1]
+ assert_equal ' 1', lines[2]
+ assert_equal ' 2', lines[3]
+ assert_equal '> 50', lines[12]
+ end
+ tmux.send_keys :Up
+ end
+ tmux.send_keys :Enter
+ assert_equal '50', readonce.chomp
+ end
+
+ def test_header_lines_reverse_list
+ tmux.send_keys "seq 100 | #{fzf('--header-lines=10 -q 5 --layout=reverse-list')}", :Enter
+ 2.times do
+ tmux.until do |lines|
+ assert_equal '> 50', lines[0]
+ assert_equal ' 2', lines[-4]
+ assert_equal ' 1', lines[-3]
+ assert_equal ' 18/90', lines[-2]
+ end
+ tmux.send_keys :Up
+ end
+ tmux.send_keys :Enter
+ assert_equal '50', readonce.chomp
+ end
+
+ def test_header_lines_overflow
+ tmux.send_keys "seq 100 | #{fzf('--header-lines=200')}", :Enter
+ tmux.until do |lines|
+ assert_equal ' 0/0', lines[-2]
+ assert_equal ' 1', lines[-3]
+ end
+ tmux.send_keys :Enter
+ assert_equal '', readonce.chomp
+ end
+
+ def test_header_lines_with_nth
+ tmux.send_keys "seq 100 | #{fzf('--header-lines 5 --with-nth 1,1,1,1,1')}", :Enter
+ tmux.until do |lines|
+ assert_equal ' 95/95', lines[-2]
+ assert_equal ' 11111', lines[-3]
+ assert_equal ' 55555', lines[-7]
+ assert_equal '> 66666', lines[-8]
+ end
+ tmux.send_keys :Enter
+ assert_equal '6', readonce.chomp
+ end
+
+ def test_header
+ tmux.send_keys "seq 100 | #{fzf("--header \"$(head -5 #{FILE})\"")}", :Enter
+ header = File.readlines(FILE, chomp: true).take(5)
+ tmux.until do |lines|
+ assert_equal ' 100/100', lines[-2]
+ assert_equal header.map { |line| " #{line}".rstrip }, lines[-7..-3]
+ assert_equal '> 1', lines[-8]
+ end
+ end
+
+ def test_header_reverse
+ tmux.send_keys "seq 100 | #{fzf("--header \"$(head -5 #{FILE})\" --reverse")}", :Enter
+ header = File.readlines(FILE, chomp: true).take(5)
+ tmux.until do |lines|
+ assert_equal ' 100/100', lines[1]
+ assert_equal header.map { |line| " #{line}".rstrip }, lines[2..6]
+ assert_equal '> 1', lines[7]
+ end
+ end
+
+ def test_header_reverse_list
+ tmux.send_keys "seq 100 | #{fzf("--header \"$(head -5 #{FILE})\" --layout=reverse-list")}", :Enter
+ header = File.readlines(FILE, chomp: true).take(5)
+ tmux.until do |lines|
+ assert_equal ' 100/100', lines[-2]
+ assert_equal header.map { |line| " #{line}".rstrip }, lines[-7..-3]
+ assert_equal '> 1', lines[0]
+ end
+ end
+
+ def test_header_and_header_lines
+ tmux.send_keys "seq 100 | #{fzf("--header-lines 10 --header \"$(head -5 #{FILE})\"")}", :Enter
+ header = File.readlines(FILE, chomp: true).take(5)
+ tmux.until do |lines|
+ assert_equal ' 90/90', lines[-2]
+ assert_equal header.map { |line| " #{line}".rstrip }, lines[-7...-2]
+ assert_equal (' 1'..' 10').to_a.reverse, lines[-17...-7]
+ end
+ end
+
+ def test_header_and_header_lines_reverse
+ tmux.send_keys "seq 100 | #{fzf("--reverse --header-lines 10 --header \"$(head -5 #{FILE})\"")}", :Enter
+ header = File.readlines(FILE, chomp: true).take(5)
+ tmux.until do |lines|
+ assert_equal ' 90/90', lines[1]
+ assert_equal header.map { |line| " #{line}".rstrip }, lines[2...7]
+ assert_equal (' 1'..' 10').to_a, lines[7...17]
+ end
+ end
+
+ def test_header_and_header_lines_reverse_list
+ tmux.send_keys "seq 100 | #{fzf("--layout=reverse-list --header-lines 10 --header \"$(head -5 #{FILE})\"")}", :Enter
+ header = File.readlines(FILE, chomp: true).take(5)
+ tmux.until do |lines|
+ assert_equal ' 90/90', lines[-2]
+ assert_equal header.map { |line| " #{line}".rstrip }, lines[-7...-2]
+ assert_equal (' 1'..' 10').to_a.reverse, lines[-17...-7]
+ end
+ end
+
+ def test_cancel
+ tmux.send_keys "seq 10 | #{fzf('--bind 2:cancel')}", :Enter
+ tmux.until { |lines| assert_equal ' 10/10', lines[-2] }
+ tmux.send_keys '123'
+ tmux.until do |lines|
+ assert_equal '> 3', lines[-1]
+ assert_equal ' 1/10', lines[-2]
+ end
+ tmux.send_keys 'C-y', 'C-y'
+ tmux.until { |lines| assert_equal '> 311', lines[-1] }
+ tmux.send_keys 2
+ tmux.until { |lines| assert_equal '>', lines[-1] }
+ tmux.send_keys 2
+ tmux.prepare
+ end
+
+ def test_margin
+ tmux.send_keys "yes | head -1000 | #{fzf('--margin 5,3')}", :Enter
+ tmux.until do |lines|
+ assert_equal '', lines[4]
+ assert_equal ' y', lines[5]
+ end
+ tmux.send_keys :Enter
+ end
+
+ def test_margin_reverse
+ tmux.send_keys "seq 1000 | #{fzf('--margin 7,5 --reverse')}", :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000', lines[1 + 7] }
+ tmux.send_keys :Enter
+ end
+
+ def test_margin_reverse_list
+ tmux.send_keys "yes | head -1000 | #{fzf('--margin 5,3 --layout=reverse-list')}", :Enter
+ tmux.until do |lines|
+ assert_equal '', lines[4]
+ assert_equal ' > y', lines[5]
+ end
+ tmux.send_keys :Enter
+ end
+
+ def test_tabstop
+ writelines(tempname, %W[f\too\tba\tr\tbaz\tbarfooq\tux])
+ {
+ 1 => '> f oo ba r baz barfooq ux',
+ 2 => '> f oo ba r baz barfooq ux',
+ 3 => '> f oo ba r baz barfooq ux',
+ 4 => '> f oo ba r baz barfooq ux',
+ 5 => '> f oo ba r baz barfooq ux',
+ 6 => '> f oo ba r baz barfooq ux',
+ 7 => '> f oo ba r baz barfooq ux',
+ 8 => '> f oo ba r baz barfooq ux',
+ 9 => '> f oo ba r baz barfooq ux'
+ }.each do |ts, exp|
+ tmux.prepare
+ tmux.send_keys %(cat #{tempname} | fzf --tabstop=#{ts}), :Enter
+ tmux.until(true) do |lines|
+ assert_equal exp, lines[-3]
+ end
+ tmux.send_keys :Enter
+ end
+ end
+
+ def test_with_nth_basic
+ writelines(tempname, ['hello world ', 'byebye'])
+ assert_equal \
+ 'hello world ',
+ `#{FZF} -f"^he hehe" -x -n 2.. --with-nth 2,1,1 < #{tempname}`.chomp
+ end
+
+ def test_with_nth_ansi
+ writelines(tempname, ["\x1b[33mhello \x1b[34;1mworld\x1b[m ", 'byebye'])
+ assert_equal \
+ 'hello world ',
+ `#{FZF} -f"^he hehe" -x -n 2.. --with-nth 2,1,1 --ansi < #{tempname}`.chomp
+ end
+
+ def test_with_nth_no_ansi
+ src = "\x1b[33mhello \x1b[34;1mworld\x1b[m "
+ writelines(tempname, [src, 'byebye'])
+ assert_equal \
+ src,
+ `#{FZF} -fhehe -x -n 2.. --with-nth 2,1,1 --no-ansi < #{tempname}`.chomp
+ end
+
+ def test_exit_0_exit_code
+ `echo foo | #{FZF} -q bar -0`
+ assert_equal 1, $CHILD_STATUS.exitstatus
+ end
+
+ def test_invalid_option
+ lines = `#{FZF} --foobar 2>&1`
+ assert_equal 2, $CHILD_STATUS.exitstatus
+ assert_includes lines, 'unknown option: --foobar'
+ end
+
+ def test_filter_exitstatus
+ # filter / streaming filter
+ ['', '--no-sort'].each do |opts|
+ assert_includes `echo foo | #{FZF} -f foo #{opts}`, 'foo'
+ assert_equal 0, $CHILD_STATUS.exitstatus
+
+ assert_empty `echo foo | #{FZF} -f bar #{opts}`
+ assert_equal 1, $CHILD_STATUS.exitstatus
+ end
+ end
+
+ def test_exitstatus_empty
+ { '99' => '0', '999' => '1' }.each do |query, status|
+ tmux.send_keys "seq 100 | #{FZF} -q #{query}; echo --$?--", :Enter
+ tmux.until { |lines| assert_match %r{ [10]/100}, lines[-2] }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal "--#{status}--", lines.last }
+ end
+ end
+
+ def test_default_extended
+ assert_equal '100', `seq 100 | #{FZF} -f "1 00$"`.chomp
+ assert_equal '', `seq 100 | #{FZF} -f "1 00$" +x`.chomp
+ end
+
+ def test_exact
+ assert_equal 4, `seq 123 | #{FZF} -f 13`.lines.length
+ assert_equal 2, `seq 123 | #{FZF} -f 13 -e`.lines.length
+ assert_equal 4, `seq 123 | #{FZF} -f 13 +e`.lines.length
+ end
+
+ def test_or_operator
+ assert_equal %w[1 5 10], `seq 10 | #{FZF} -f "1 | 5"`.lines(chomp: true)
+ assert_equal %w[1 10 2 3 4 5 6 7 8 9],
+ `seq 10 | #{FZF} -f '1 | !1'`.lines(chomp: true)
+ end
+
+ def test_hscroll_off
+ writelines(tempname, ['=' * 10_000 + '0123456789'])
+ [0, 3, 6].each do |off|
+ tmux.prepare
+ tmux.send_keys "#{FZF} --hscroll-off=#{off} -q 0 < #{tempname}", :Enter
+ tmux.until { |lines| assert lines[-3]&.end_with?((0..off).to_a.join + '..') }
+ tmux.send_keys '9'
+ tmux.until { |lines| assert lines[-3]&.end_with?('789') }
+ tmux.send_keys :Enter
+ end
+ end
+
+ def test_partial_caching
+ tmux.send_keys 'seq 1000 | fzf -e', :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000', lines[-2] }
+ tmux.send_keys 11
+ tmux.until { |lines| assert_equal ' 19/1000', lines[-2] }
+ tmux.send_keys 'C-a', "'"
+ tmux.until { |lines| assert_equal ' 28/1000', lines[-2] }
+ tmux.send_keys :Enter
+ end
+
+ def test_jump
+ tmux.send_keys "seq 1000 | #{fzf("--multi --jump-labels 12345 --bind 'ctrl-j:jump'")}", :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000 (0)', lines[-2] }
+ tmux.send_keys 'C-j'
+ tmux.until { |lines| assert_equal '5 5', lines[-7] }
+ tmux.until { |lines| assert_equal ' 6', lines[-8] }
+ tmux.send_keys '5'
+ tmux.until { |lines| assert_equal '> 5', lines[-7] }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal ' >5', lines[-7] }
+ tmux.send_keys 'C-j'
+ tmux.until { |lines| assert_equal '5>5', lines[-7] }
+ tmux.send_keys '2'
+ tmux.until { |lines| assert_equal '> 2', lines[-4] }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal ' >2', lines[-4] }
+ tmux.send_keys 'C-j'
+ tmux.until { |lines| assert_equal '5>5', lines[-7] }
+
+ # Press any key other than jump labels to cancel jump
+ tmux.send_keys '6'
+ tmux.until { |lines| assert_equal '> 1', lines[-3] }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal '>>1', lines[-3] }
+ tmux.send_keys :Enter
+ assert_equal %w[5 2 1], readonce.lines(chomp: true)
+ end
+
+ def test_jump_accept
+ tmux.send_keys "seq 1000 | #{fzf("--multi --jump-labels 12345 --bind 'ctrl-j:jump-accept'")}", :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000 (0)', lines[-2] }
+ tmux.send_keys 'C-j'
+ tmux.until { |lines| assert_equal '5 5', lines[-7] }
+ tmux.send_keys '3'
+ assert_equal '3', readonce.chomp
+ end
+
+ def test_pointer
+ tmux.send_keys "seq 10 | #{fzf("--pointer '>>'")}", :Enter
+ # Assert that specified pointer is displayed
+ tmux.until { |lines| assert_equal '>> 1', lines[-3] }
+ end
+
+ def test_pointer_with_jump
+ tmux.send_keys "seq 10 | #{fzf("--multi --jump-labels 12345 --bind 'ctrl-j:jump' --pointer '>>'")}", :Enter
+ tmux.until { |lines| assert_equal ' 10/10 (0)', lines[-2] }
+ tmux.send_keys 'C-j'
+ # Correctly padded jump label should appear
+ tmux.until { |lines| assert_equal '5 5', lines[-7] }
+ tmux.until { |lines| assert_equal ' 6', lines[-8] }
+ tmux.send_keys '5'
+ # Assert that specified pointer is displayed
+ tmux.until { |lines| assert_equal '>> 5', lines[-7] }
+ end
+
+ def test_marker
+ tmux.send_keys "seq 10 | #{fzf("--multi --marker '>>'")}", :Enter
+ tmux.until { |lines| assert_equal ' 10/10 (0)', lines[-2] }
+ tmux.send_keys :BTab
+ # Assert that specified marker is displayed
+ tmux.until { |lines| assert_equal ' >>1', lines[-3] }
+ end
+
+ def test_preview
+ tmux.send_keys %(seq 1000 | sed s/^2$// | #{FZF} -m --preview 'sleep 0.2; echo {{}-{+}}' --bind ?:toggle-preview), :Enter
+ tmux.until { |lines| assert_includes lines[1], ' {1-1} ' }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_includes lines[1], ' {-} ' }
+ tmux.send_keys '555'
+ tmux.until { |lines| assert_includes lines[1], ' {555-555} ' }
+ tmux.send_keys '?'
+ tmux.until { |lines| refute_includes lines[1], ' {555-555} ' }
+ tmux.send_keys '?'
+ tmux.until { |lines| assert_includes lines[1], ' {555-555} ' }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert lines[-2]&.start_with?(' 28/1000 ') }
+ tmux.send_keys 'foobar'
+ tmux.until { |lines| refute_includes lines[1], ' {55-55} ' }
+ tmux.send_keys 'C-u'
+ tmux.until { |lines| assert_equal 1000, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], ' {1-1} ' }
+ tmux.send_keys :BTab
+ tmux.until { |lines| assert_includes lines[1], ' {-1} ' }
+ tmux.send_keys :BTab
+ tmux.until { |lines| assert_includes lines[1], ' {3-1 } ' }
+ tmux.send_keys :BTab
+ tmux.until { |lines| assert_includes lines[1], ' {4-1 3} ' }
+ tmux.send_keys :BTab
+ tmux.until { |lines| assert_includes lines[1], ' {5-1 3 4} ' }
+ end
+
+ def test_preview_hidden
+ tmux.send_keys %(seq 1000 | #{FZF} --preview 'echo {{}-{}-$FZF_PREVIEW_LINES-$FZF_PREVIEW_COLUMNS}' --preview-window down:1:hidden --bind ?:toggle-preview), :Enter
+ tmux.until { |lines| assert_equal '>', lines[-1] }
+ tmux.send_keys '?'
+ tmux.until { |lines| assert_match(/ {1-1-1-[0-9]+}/, lines[-2]) }
+ tmux.send_keys '555'
+ tmux.until { |lines| assert_match(/ {555-555-1-[0-9]+}/, lines[-2]) }
+ tmux.send_keys '?'
+ tmux.until { |lines| assert_equal '> 555', lines[-1] }
+ end
+
+ def test_preview_size_0
+ begin
+ File.unlink(tempname)
+ rescue StandardError
+ nil
+ end
+ tmux.send_keys %(seq 100 | #{FZF} --reverse --preview 'echo {} >> #{tempname}; echo ' --preview-window 0), :Enter
+ tmux.until do |lines|
+ assert_equal 100, lines.item_count
+ assert_equal ' 100/100', lines[1]
+ assert_equal '> 1', lines[2]
+ end
+ wait do
+ assert_path_exists tempname
+ assert_equal %w[1], File.readlines(tempname, chomp: true)
+ end
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal '> 2', lines[3] }
+ wait do
+ assert_path_exists tempname
+ assert_equal %w[1 2], File.readlines(tempname, chomp: true)
+ end
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal '> 3', lines[4] }
+ wait do
+ assert_path_exists tempname
+ assert_equal %w[1 2 3], File.readlines(tempname, chomp: true)
+ end
+ end
+
+ def test_preview_flags
+ tmux.send_keys %(seq 10 | sed 's/^/:: /; s/$/ /' |
+ #{FZF} --multi --preview 'echo {{2}/{s2}/{+2}/{+s2}/{q}/{n}/{+n}}'), :Enter
+ tmux.until { |lines| assert_includes lines[1], ' {1/1 /1/1 //0/0} ' }
+ tmux.send_keys '123'
+ tmux.until { |lines| assert_includes lines[1], ' {////123//} ' }
+ tmux.send_keys 'C-u', '1'
+ tmux.until { |lines| assert_equal 2, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], ' {1/1 /1/1 /1/0/0} ' }
+ tmux.send_keys :BTab
+ tmux.until { |lines| assert_includes lines[1], ' {10/10 /1/1 /1/9/0} ' }
+ tmux.send_keys :BTab
+ tmux.until { |lines| assert_includes lines[1], ' {10/10 /1 10/1 10 /1/9/0 9} ' }
+ tmux.send_keys '2'
+ tmux.until { |lines| assert_includes lines[1], ' {//1 10/1 10 /12//0 9} ' }
+ tmux.send_keys '3'
+ tmux.until { |lines| assert_includes lines[1], ' {//1 10/1 10 /123//0 9} ' }
+ end
+
+ def test_preview_file
+ tmux.send_keys %[(echo foo bar; echo bar foo) | #{FZF} --multi --preview 'cat {+f} {+f2} {+nf} {+fn}' --print0], :Enter
+ tmux.until { |lines| assert_includes lines[1], ' foo barbar00 ' }
+ tmux.send_keys :BTab
+ tmux.until { |lines| assert_includes lines[1], ' foo barbar00 ' }
+ tmux.send_keys :BTab
+ tmux.until { |lines| assert_includes lines[1], ' foo barbar foobarfoo0101 ' }
+ end
+
+ def test_preview_q_no_match
+ tmux.send_keys %(: | #{FZF} --preview 'echo foo {q}'), :Enter
+ tmux.until { |lines| assert_equal 0, lines.match_count }
+ tmux.until { |lines| refute_includes lines[1], ' foo ' }
+ tmux.send_keys 'bar'
+ tmux.until { |lines| assert_includes lines[1], ' foo bar ' }
+ tmux.send_keys 'C-u'
+ tmux.until { |lines| refute_includes lines[1], ' foo ' }
+ end
+
+ def test_preview_q_no_match_with_initial_query
+ tmux.send_keys %(: | #{FZF} --preview 'echo foo {q}{q}' --query foo), :Enter
+ tmux.until { |lines| assert_equal 0, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], ' foofoo ' }
+ end
+
+ def test_no_clear
+ tmux.send_keys "seq 10 | fzf --no-clear --inline-info --height 5 > #{tempname}", :Enter
+ prompt = '> < 10/10'
+ tmux.until { |lines| assert_equal prompt, lines[-1] }
+ tmux.send_keys :Enter
+ wait do
+ assert_path_exists tempname
+ assert_equal %w[1], File.readlines(tempname, chomp: true)
+ end
+ tmux.until { |lines| assert_equal prompt, lines[-1] }
+ end
+
+ def test_info_hidden
+ tmux.send_keys 'seq 10 | fzf --info=hidden', :Enter
+ tmux.until { |lines| assert_equal '> 1', lines[-2] }
+ end
+
+ def test_change_first_last
+ tmux.send_keys %(seq 1000 | #{FZF} --bind change:first,alt-Z:last), :Enter
+ tmux.until { |lines| assert_equal 1000, lines.match_count }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal '> 2', lines[-4] }
+ tmux.send_keys 1
+ tmux.until { |lines| assert_equal '> 1', lines[-3] }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal '> 10', lines[-4] }
+ tmux.send_keys 1
+ tmux.until { |lines| assert_equal '> 11', lines[-3] }
+ tmux.send_keys 'C-u'
+ tmux.until { |lines| assert_equal '> 1', lines[-3] }
+ tmux.send_keys :Escape, 'Z'
+ tmux.until { |lines| assert_equal '> 1000', lines[0] }
+ tmux.send_keys :Enter
+ end
+
+ def test_accept_non_empty
+ tmux.send_keys %(seq 1000 | #{fzf('--print-query --bind enter:accept-non-empty')}), :Enter
+ tmux.until { |lines| assert_equal 1000, lines.match_count }
+ tmux.send_keys 'foo'
+ tmux.until { |lines| assert_equal ' 0/1000', lines[-2] }
+ # fzf doesn't exit since there's no selection
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal ' 0/1000', lines[-2] }
+ tmux.send_keys 'C-u'
+ tmux.until { |lines| assert_equal ' 1000/1000', lines[-2] }
+ tmux.send_keys '999'
+ tmux.until { |lines| assert_equal ' 1/1000', lines[-2] }
+ tmux.send_keys :Enter
+ assert_equal %w[999 999], readonce.lines(chomp: true)
+ end
+
+ def test_accept_non_empty_with_multi_selection
+ tmux.send_keys %(seq 1000 | #{fzf('-m --print-query --bind enter:accept-non-empty')}), :Enter
+ tmux.until { |lines| assert_equal 1000, lines.match_count }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal ' 1000/1000 (1)', lines[-2] }
+ tmux.send_keys 'foo'
+ tmux.until { |lines| assert_equal ' 0/1000 (1)', lines[-2] }
+ # fzf will exit in this case even though there's no match for the current query
+ tmux.send_keys :Enter
+ assert_equal %w[foo 1], readonce.lines(chomp: true)
+ end
+
+ def test_accept_non_empty_with_empty_list
+ tmux.send_keys %(: | #{fzf('-q foo --print-query --bind enter:accept-non-empty')}), :Enter
+ tmux.until { |lines| assert_equal ' 0/0', lines[-2] }
+ tmux.send_keys :Enter
+ # fzf will exit anyway since input list is empty
+ assert_equal %w[foo], readonce.lines(chomp: true)
+ end
+
+ def test_preview_update_on_select
+ tmux.send_keys %(seq 10 | fzf -m --preview 'echo {+}' --bind a:toggle-all),
+ :Enter
+ tmux.until { |lines| assert_equal 10, lines.item_count }
+ tmux.send_keys 'a'
+ tmux.until { |lines| assert(lines.any? { |line| line.include?(' 1 2 3 4 5 ') }) }
+ tmux.send_keys 'a'
+ tmux.until { |lines| lines.each { |line| refute_includes line, ' 1 2 3 4 5 ' } }
+ end
+
+ def test_escaped_meta_characters
+ input = [
+ 'foo^bar',
+ 'foo$bar',
+ 'foo!bar',
+ "foo'bar",
+ 'foo bar',
+ 'bar foo'
+ ]
+ writelines(tempname, input)
+
+ assert_equal input.length, `#{FZF} -f'foo bar' < #{tempname}`.lines.length
+ assert_equal input.length - 1, `#{FZF} -f'^foo bar$' < #{tempname}`.lines.length
+ assert_equal ['foo bar'], `#{FZF} -f'foo\\ bar' < #{tempname}`.lines(chomp: true)
+ assert_equal ['foo bar'], `#{FZF} -f'^foo\\ bar$' < #{tempname}`.lines(chomp: true)
+ assert_equal input.length - 1, `#{FZF} -f'!^foo\\ bar$' < #{tempname}`.lines.length
+ end
+
+ def test_inverse_only_search_should_not_sort_the_result
+ # Filter
+ assert_equal %w[aaaaa b ccc],
+ `printf '%s\n' aaaaa b ccc BAD | #{FZF} -f '!bad'`.lines(chomp: true)
+
+ # Interactive
+ tmux.send_keys %(printf '%s\n' aaaaa b ccc BAD | #{FZF} -q '!bad'), :Enter
+ tmux.until do |lines|
+ assert_equal 4, lines.item_count
+ assert_equal 3, lines.match_count
+ end
+ tmux.until { |lines| assert_equal '> aaaaa', lines[-3] }
+ tmux.until { |lines| assert_equal ' b', lines[-4] }
+ tmux.until { |lines| assert_equal ' ccc', lines[-5] }
+ end
+
+ def test_preview_correct_tab_width_after_ansi_reset_code
+ writelines(tempname, ["\x1b[31m+\x1b[m\t\x1b[32mgreen"])
+ tmux.send_keys "#{FZF} --preview 'cat #{tempname}'", :Enter
+ tmux.until { |lines| assert_includes lines[1], ' + green ' }
+ end
+
+ def test_disabled
+ tmux.send_keys %(seq 1000 | #{FZF} --query 333 --disabled --bind a:enable-search,b:disable-search,c:toggle-search --preview 'echo {} {q}'), :Enter
+ tmux.until { |lines| assert_equal 1000, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], ' 1 333 ' }
+ tmux.send_keys 'foo'
+ tmux.until { |lines| assert_equal 1000, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], ' 1 333foo ' }
+
+ # Already disabled, no change
+ tmux.send_keys 'b'
+ tmux.until { |lines| assert_equal 1000, lines.match_count }
+
+ # Enable search
+ tmux.send_keys 'a'
+ tmux.until { |lines| assert_equal 0, lines.match_count }
+ tmux.send_keys :BSpace, :BSpace, :BSpace
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], ' 333 333 ' }
+
+ # Toggle search -> disabled again, but retains the previous result
+ tmux.send_keys 'c'
+ tmux.send_keys 'foo'
+ tmux.until { |lines| assert_includes lines[1], ' 333 333foo ' }
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+
+ # Enabled, no match
+ tmux.send_keys 'c'
+ tmux.until { |lines| assert_equal 0, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], ' 333foo ' }
+ end
+
+ def test_reload
+ tmux.send_keys %(seq 1000 | #{FZF} --bind 'change:reload(seq {q}),a:reload(seq 100),b:reload:seq 200' --header-lines 2 --multi 2), :Enter
+ tmux.until { |lines| assert_equal 998, lines.match_count }
+ tmux.send_keys 'a'
+ tmux.until do |lines|
+ assert_equal 98, lines.item_count
+ assert_equal 98, lines.match_count
+ end
+ tmux.send_keys 'b'
+ tmux.until do |lines|
+ assert_equal 198, lines.item_count
+ assert_equal 198, lines.match_count
+ end
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal ' 198/198 (1/2)', lines[-2] }
+ tmux.send_keys '555'
+ tmux.until { |lines| assert_equal ' 1/553 (0/2)', lines[-2] }
+ end
+
+ def test_reload_even_when_theres_no_match
+ tmux.send_keys %(: | #{FZF} --bind 'space:reload(seq 10)'), :Enter
+ tmux.until { |lines| assert_equal 0, lines.item_count }
+ tmux.send_keys :Space
+ tmux.until { |lines| assert_equal 10, lines.item_count }
+ end
+
+ def test_clear_list_when_header_lines_changed_due_to_reload
+ tmux.send_keys %(seq 10 | #{FZF} --header 0 --header-lines 3 --bind 'space:reload(seq 1)'), :Enter
+ tmux.until { |lines| assert_includes lines, ' 9' }
+ tmux.send_keys :Space
+ tmux.until { |lines| refute_includes lines, ' 9' }
+ end
+
+ def test_clear_query
+ tmux.send_keys %(: | #{FZF} --query foo --bind space:clear-query), :Enter
+ tmux.until { |lines| assert_equal 0, lines.item_count }
+ tmux.until { |lines| assert_equal '> foo', lines.last }
+ tmux.send_keys 'C-a', 'bar'
+ tmux.until { |lines| assert_equal '> barfoo', lines.last }
+ tmux.send_keys :Space
+ tmux.until { |lines| assert_equal '>', lines.last }
+ end
+
+ def test_clear_selection
+ tmux.send_keys %(seq 100 | #{FZF} --multi --bind space:clear-selection), :Enter
+ tmux.until { |lines| assert_equal 100, lines.match_count }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal ' 100/100 (1)', lines[-2] }
+ tmux.send_keys 'foo'
+ tmux.until { |lines| assert_equal ' 0/100 (1)', lines[-2] }
+ tmux.send_keys :Space
+ tmux.until { |lines| assert_equal ' 0/100 (0)', lines[-2] }
+ end
+
+ def test_backward_delete_char_eof
+ tmux.send_keys "seq 1000 | #{fzf("--bind 'bs:backward-delete-char/eof'")}", :Enter
+ tmux.until { |lines| assert_equal ' 1000/1000', lines[-2] }
+ tmux.send_keys '11'
+ tmux.until { |lines| assert_equal '> 11', lines[-1] }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert_equal '> 1', lines[-1] }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert_equal '>', lines[-1] }
+ tmux.send_keys :BSpace
+ tmux.prepare
+ end
+
+ def test_strip_xterm_osc_sequence
+ %W[\x07 \x1b\\].each do |esc|
+ writelines(tempname, [%(printf $1"\e]4;3;rgb:aa/bb/cc#{esc} "$2)])
+ File.chmod(0o755, tempname)
+ tmux.prepare
+ tmux.send_keys \
+ %(echo foo bar | #{FZF} --preview '#{tempname} {2} {1}'), :Enter
+
+ tmux.until { |lines| assert lines.any_include?('bar foo') }
+ tmux.send_keys :Enter
+ end
+ end
+
+ def test_keep_right
+ tmux.send_keys "seq 10000 | #{FZF} --read0 --keep-right", :Enter
+ tmux.until { |lines| assert lines.any_include?('9999 10000') }
+ end
+
+ def test_backward_eof
+ tmux.send_keys "echo foo | #{FZF} --bind 'backward-eof:reload(seq 100)'", :Enter
+ tmux.until { |lines| lines.item_count == 1 && lines.match_count == 1 }
+ tmux.send_keys 'x'
+ tmux.until { |lines| lines.item_count == 1 && lines.match_count == 0 }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| lines.item_count == 1 && lines.match_count == 1 }
+ tmux.send_keys :BSpace
+ tmux.until { |lines| lines.item_count == 100 && lines.match_count == 100 }
+ end
+
+ def test_preview_bindings_with_default_preview
+ tmux.send_keys "seq 10 | #{FZF} --preview 'echo [{}]' --bind 'a:preview(echo [{}{}]),b:preview(echo [{}{}{}]),c:refresh-preview'", :Enter
+ tmux.until { |lines| lines.item_count == 10 }
+ tmux.until { |lines| assert_includes lines[1], '[1]' }
+ tmux.send_keys 'a'
+ tmux.until { |lines| assert_includes lines[1], '[11]' }
+ tmux.send_keys 'c'
+ tmux.until { |lines| assert_includes lines[1], '[1]' }
+ tmux.send_keys 'b'
+ tmux.until { |lines| assert_includes lines[1], '[111]' }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_includes lines[1], '[2]' }
+ end
+
+ def test_preview_bindings_without_default_preview
+ tmux.send_keys "seq 10 | #{FZF} --bind 'a:preview(echo [{}{}]),b:preview(echo [{}{}{}]),c:refresh-preview'", :Enter
+ tmux.until { |lines| lines.item_count == 10 }
+ tmux.until { |lines| refute_includes lines[1], '1' }
+ tmux.send_keys 'a'
+ tmux.until { |lines| assert_includes lines[1], '[11]' }
+ tmux.send_keys 'c' # does nothing
+ tmux.until { |lines| assert_includes lines[1], '[11]' }
+ tmux.send_keys 'b'
+ tmux.until { |lines| assert_includes lines[1], '[111]' }
+ tmux.send_keys 9
+ tmux.until { |lines| lines.match_count == 1 }
+ tmux.until { |lines| refute_includes lines[1], '2' }
+ tmux.until { |lines| assert_includes lines[1], '[111]' }
+ end
+
+ def test_preview_scroll_begin_constant
+ tmux.send_keys "echo foo 123 321 | #{FZF} --preview 'seq 1000' --preview-window left:+123", :Enter
+ tmux.until { |lines| assert_match %r{1/1}, lines[-2] }
+ tmux.until { |lines| assert_match %r{123.*123/1000}, lines[1] }
+ end
+
+ def test_preview_scroll_begin_expr
+ tmux.send_keys "echo foo 123 321 | #{FZF} --preview 'seq 1000' --preview-window left:+{3}", :Enter
+ tmux.until { |lines| assert_match %r{1/1}, lines[-2] }
+ tmux.until { |lines| assert_match %r{321.*321/1000}, lines[1] }
+ end
+
+ def test_preview_scroll_begin_and_offset
+ ['echo foo 123 321', 'echo foo :123: 321'].each do |input|
+ tmux.send_keys "#{input} | #{FZF} --preview 'seq 1000' --preview-window left:+{2}-2", :Enter
+ tmux.until { |lines| assert_match %r{1/1}, lines[-2] }
+ tmux.until { |lines| assert_match %r{121.*121/1000}, lines[1] }
+ tmux.send_keys 'C-c'
+ end
+ end
+
+ def test_normalized_match
+ echoes = '(echo a; echo á; echo A; echo Á;)'
+ assert_equal %w[a á A Á], `#{echoes} | #{FZF} -f a`.lines.map(&:chomp)
+ assert_equal %w[á Á], `#{echoes} | #{FZF} -f á`.lines.map(&:chomp)
+ assert_equal %w[A Á], `#{echoes} | #{FZF} -f A`.lines.map(&:chomp)
+ assert_equal %w[Á], `#{echoes} | #{FZF} -f Á`.lines.map(&:chomp)
+ end
+
+ def test_preview_clear_screen
+ tmux.send_keys %{seq 100 | #{FZF} --preview 'for i in $(seq 300); do (( i % 200 == 0 )) && printf "\\033[2J"; echo "[$i]"; sleep 0.001; done'}, :Enter
+ tmux.until { |lines| lines.item_count == 100 }
+ tmux.until { |lines| lines[1]&.include?('[200]') }
+ end
+
+ def test_change_prompt
+ tmux.send_keys "#{FZF} --bind 'a:change-prompt(a> ),b:change-prompt:b> ' --query foo", :Enter
+ tmux.until { |lines| assert_equal '> foo', lines[-1] }
+ tmux.send_keys 'a'
+ tmux.until { |lines| assert_equal 'a> foo', lines[-1] }
+ tmux.send_keys 'b'
+ tmux.until { |lines| assert_equal 'b> foo', lines[-1] }
+ end
+
+ def test_preview_window_follow
+ tmux.send_keys "#{FZF} --preview 'seq 1000 | nl' --preview-window down:noborder:follow", :Enter
+ tmux.until { |lines| assert_equal '1000 1000', lines[-1].strip }
+ end
+
+ def test_toggle_preview_wrap
+ tmux.send_keys "#{FZF} --preview 'for i in $(seq $FZF_PREVIEW_COLUMNS); do echo -n .; done; echo wrapped; echo 2nd line' --bind ctrl-w:toggle-preview-wrap", :Enter
+ 2.times do
+ tmux.until { |lines| assert_includes lines[2], '2nd line' }
+ tmux.send_keys 'C-w'
+ tmux.until do |lines|
+ assert_includes lines[2], 'wrapped'
+ assert_includes lines[3], '2nd line'
+ end
+ tmux.send_keys 'C-w'
+ end
+ end
+
+ def test_close
+ tmux.send_keys "seq 100 | #{FZF} --preview 'echo foo' --bind ctrl-c:close", :Enter
+ tmux.until { |lines| assert_equal 100, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], 'foo' }
+ tmux.send_keys 'C-c'
+ tmux.until { |lines| refute_includes lines[1], 'foo' }
+ tmux.send_keys '10'
+ tmux.until { |lines| assert_equal 2, lines.match_count }
+ tmux.send_keys 'C-c'
+ tmux.send_keys 'C-l', 'closed'
+ tmux.until { |lines| assert_includes lines[0], 'closed' }
+ end
+
+ def test_select_deselect
+ tmux.send_keys "seq 3 | #{FZF} --multi --bind up:deselect+up,down:select+down", :Enter
+ tmux.until { |lines| assert_equal 3, lines.match_count }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal 1, lines.select_count }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal 0, lines.select_count }
+ tmux.send_keys :Down, :Down
+ tmux.until { |lines| assert_equal 2, lines.select_count }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal 1, lines.select_count }
+ tmux.send_keys :Down, :Down
+ tmux.until { |lines| assert_equal 2, lines.select_count }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal 1, lines.select_count }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal 1, lines.select_count }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal 2, lines.select_count }
+ end
+
+ def test_interrupt_execute
+ tmux.send_keys "seq 100 | #{FZF} --bind 'ctrl-l:execute:echo executing {}; sleep 100'", :Enter
+ tmux.until { |lines| assert_equal 100, lines.item_count }
+ tmux.send_keys 'C-l'
+ tmux.until { |lines| assert lines.any_include?('executing 1') }
+ tmux.send_keys 'C-c'
+ tmux.until { |lines| assert_equal 100, lines.item_count }
+ tmux.send_keys 99
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ end
+
+ def test_kill_default_command_on_abort
+ script = tempname + '.sh'
+ writelines(script,
+ ['#!/usr/bin/env bash',
+ "echo 'Started'",
+ 'while :; do sleep 1; done'])
+ system("chmod +x #{script}")
+
+ tmux.send_keys fzf.sub('FZF_DEFAULT_COMMAND=', "FZF_DEFAULT_COMMAND=#{script}"), :Enter
+ tmux.until { |lines| assert_equal 1, lines.item_count }
+ tmux.send_keys 'C-c'
+ tmux.send_keys 'C-l', 'closed'
+ tmux.until { |lines| assert_includes lines[0], 'closed' }
+ wait { refute system("pgrep -f #{script}") }
+ ensure
+ system("pkill -9 -f #{script}")
+ begin
+ File.unlink(script)
+ rescue StandardError
+ nil
+ end
+ end
+
+ def test_kill_default_command_on_accept
+ script = tempname + '.sh'
+ writelines(script,
+ ['#!/usr/bin/env bash',
+ "echo 'Started'",
+ 'while :; do sleep 1; done'])
+ system("chmod +x #{script}")
+
+ tmux.send_keys fzf.sub('FZF_DEFAULT_COMMAND=', "FZF_DEFAULT_COMMAND=#{script}"), :Enter
+ tmux.until { |lines| assert_equal 1, lines.item_count }
+ tmux.send_keys :Enter
+ assert_equal 'Started', readonce.chomp
+ wait { refute system("pgrep -f #{script}") }
+ ensure
+ system("pkill -9 -f #{script}")
+ begin
+ File.unlink(script)
+ rescue StandardError
+ nil
+ end
+ end
+
+ def test_kill_reload_command_on_abort
+ script = tempname + '.sh'
+ writelines(script,
+ ['#!/usr/bin/env bash',
+ "echo 'Started'",
+ 'while :; do sleep 1; done'])
+ system("chmod +x #{script}")
+
+ tmux.send_keys "seq 1 3 | #{fzf("--bind 'ctrl-r:reload(#{script})'")}", :Enter
+ tmux.until { |lines| assert_equal 3, lines.item_count }
+ tmux.send_keys 'C-r'
+ tmux.until { |lines| assert_equal 1, lines.item_count }
+ tmux.send_keys 'C-c'
+ tmux.send_keys 'C-l', 'closed'
+ tmux.until { |lines| assert_includes lines[0], 'closed' }
+ wait { refute system("pgrep -f #{script}") }
+ ensure
+ system("pkill -9 -f #{script}")
+ begin
+ File.unlink(script)
+ rescue StandardError
+ nil
+ end
+ end
+
+ def test_kill_reload_command_on_accept
+ script = tempname + '.sh'
+ writelines(script,
+ ['#!/usr/bin/env bash',
+ "echo 'Started'",
+ 'while :; do sleep 1; done'])
+ system("chmod +x #{script}")
+
+ tmux.send_keys "seq 1 3 | #{fzf("--bind 'ctrl-r:reload(#{script})'")}", :Enter
+ tmux.until { |lines| assert_equal 3, lines.item_count }
+ tmux.send_keys 'C-r'
+ tmux.until { |lines| assert_equal 1, lines.item_count }
+ tmux.send_keys :Enter
+ assert_equal 'Started', readonce.chomp
+ wait { refute system("pgrep -f #{script}") }
+ ensure
+ system("pkill -9 -f #{script}")
+ begin
+ File.unlink(script)
+ rescue StandardError
+ nil
+ end
+ end
+
+ def test_preview_header
+ tmux.send_keys "seq 100 | #{FZF} --bind ctrl-k:preview-up+preview-up,ctrl-j:preview-down+preview-down+preview-down --preview 'seq 1000' --preview-window 'top:+{1}:~3'", :Enter
+ tmux.until { |lines| assert_equal 100, lines.item_count }
+ top5 = ->(lines) { lines.drop(1).take(5).map { |s| s[/[0-9]+/] } }
+ tmux.until do |lines|
+ assert_includes lines[1], '4/1000'
+ assert_equal(%w[1 2 3 4 5], top5[lines])
+ end
+ tmux.send_keys '55'
+ tmux.until do |lines|
+ assert_equal 1, lines.match_count
+ assert_equal(%w[1 2 3 55 56], top5[lines])
+ end
+ tmux.send_keys 'C-J'
+ tmux.until do |lines|
+ assert_equal(%w[1 2 3 58 59], top5[lines])
+ end
+ tmux.send_keys :BSpace
+ tmux.until do |lines|
+ assert_equal 19, lines.match_count
+ assert_equal(%w[1 2 3 5 6], top5[lines])
+ end
+ tmux.send_keys 'C-K'
+ tmux.until { |lines| assert_equal(%w[1 2 3 4 5], top5[lines]) }
+ end
+
+ def test_unbind_rebind
+ tmux.send_keys "seq 100 | #{FZF} --bind 'c:clear-query,d:unbind(c,d),e:rebind(c,d)'", :Enter
+ tmux.until { |lines| assert_equal 100, lines.item_count }
+ tmux.send_keys 'ab'
+ tmux.until { |lines| assert_equal '> ab', lines[-1] }
+ tmux.send_keys 'c'
+ tmux.until { |lines| assert_equal '>', lines[-1] }
+ tmux.send_keys 'dabcd'
+ tmux.until { |lines| assert_equal '> abcd', lines[-1] }
+ tmux.send_keys 'ecabddc'
+ tmux.until { |lines| assert_equal '> abdc', lines[-1] }
+ end
+
+ def test_item_index_reset_on_reload
+ tmux.send_keys "seq 10 | #{FZF} --preview 'echo [[{n}]]' --bind 'up:last,down:first,space:reload:seq 100'", :Enter
+ tmux.until { |lines| assert_includes lines[1], '[[0]]' }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_includes lines[1], '[[9]]' }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_includes lines[1], '[[0]]' }
+ tmux.send_keys :Space
+ tmux.until do |lines|
+ assert_equal 100, lines.item_count
+ assert_includes lines[1], '[[0]]'
+ end
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_includes lines[1], '[[99]]' }
+ end
+
+ def test_reload_should_update_preview
+ tmux.send_keys "seq 3 | #{FZF} --bind 'ctrl-t:reload:echo 4' --preview 'echo {}' --preview-window 'nohidden'", :Enter
+ tmux.until { |lines| assert_includes lines[1], '1' }
+ tmux.send_keys 'C-t'
+ tmux.until { |lines| assert_includes lines[1], '4' }
+ end
+
+ def test_reload_and_change_preview_should_update_preview
+ tmux.send_keys "seq 3 | #{FZF} --bind 'ctrl-t:reload(echo 4)+change-preview(echo {})'", :Enter
+ tmux.until { |lines| assert_equal 3, lines.item_count }
+ tmux.until { |lines| refute_includes lines[1], '1' }
+ tmux.send_keys 'C-t'
+ tmux.until { |lines| assert_equal 1, lines.item_count }
+ tmux.until { |lines| assert_includes lines[1], '4' }
+ end
+
+ def test_scroll_off
+ tmux.send_keys "seq 1000 | #{FZF} --scroll-off=3 --bind l:last", :Enter
+ tmux.until { |lines| assert_equal 1000, lines.item_count }
+ height = tmux.until { |lines| lines }.first.to_i
+ tmux.send_keys :PgUp
+ tmux.until do |lines|
+ assert_equal height + 3, lines.first.to_i
+ assert_equal "> #{height}", lines[3].strip
+ end
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal "> #{height + 1}", lines[3].strip }
+ tmux.send_keys 'l'
+ tmux.until { |lines| assert_equal '> 1000', lines.first.strip }
+ tmux.send_keys :PgDn
+ tmux.until { |lines| assert_equal "> #{1000 - height + 1}", lines.reverse[5].strip }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal "> #{1000 - height}", lines.reverse[5].strip }
+ end
+
+ def test_scroll_off_large
+ tmux.send_keys "seq 1000 | #{FZF} --scroll-off=9999", :Enter
+ tmux.until { |lines| assert_equal 1000, lines.item_count }
+ height = tmux.until { |lines| lines }.first.to_i
+ tmux.send_keys :PgUp
+ tmux.until { |lines| assert_equal "> #{height}", lines[height / 2].strip }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal "> #{height + 1}", lines[height / 2].strip }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal "> #{height + 2}", lines[height / 2].strip }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal "> #{height + 1}", lines[height / 2].strip }
+ end
+
+ def test_header_first
+ tmux.send_keys "seq 1000 | #{FZF} --header foobar --header-lines 3 --header-first", :Enter
+ tmux.until do |lines|
+ expected = <<~OUTPUT
+ > 4
+ 997/997
+ >
+ 3
+ 2
+ 1
+ foobar
+ OUTPUT
+
+ assert_equal expected.chomp, lines.reverse.take(7).reverse.join("\n")
+ end
+ end
+
+ def test_header_first_reverse
+ tmux.send_keys "seq 1000 | #{FZF} --header foobar --header-lines 3 --header-first --reverse --inline-info", :Enter
+ tmux.until do |lines|
+ expected = <<~OUTPUT
+ foobar
+ 1
+ 2
+ 3
+ > < 997/997
+ > 4
+ OUTPUT
+
+ assert_equal expected.chomp, lines.take(6).join("\n")
+ end
+ end
+
+ def test_change_preview_window
+ tmux.send_keys "seq 1000 | #{FZF} --preview 'echo [[{}]]' --preview-window border-none --bind '" \
+ 'a:change-preview(echo __{}__),' \
+ 'b:change-preview-window(down)+change-preview(echo =={}==)+change-preview-window(up),' \
+ 'c:change-preview(),d:change-preview-window(hidden),' \
+ "e:preview(printf ::%${FZF_PREVIEW_COLUMNS}s{})+change-preview-window(up),f:change-preview-window(up,wrap)'", :Enter
+ tmux.until { |lines| assert_equal 1000, lines.item_count }
+ tmux.until { |lines| assert_includes lines[0], '[[1]]' }
+
+ # change-preview action permanently changes the preview command set by --preview
+ tmux.send_keys 'a'
+ tmux.until { |lines| assert_includes lines[0], '__1__' }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_includes lines[0], '__2__' }
+
+ # When multiple change-preview-window actions are bound to a single key,
+ # the last one wins and the updated options are immediately applied to the new preview
+ tmux.send_keys 'b'
+ tmux.until { |lines| assert_equal '==2==', lines[0] }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal '==3==', lines[0] }
+
+ # change-preview with an empty preview command closes the preview window
+ tmux.send_keys 'c'
+ tmux.until { |lines| refute_includes lines[0], '==' }
+
+ # change-preview again to re-open the preview window
+ tmux.send_keys 'a'
+ tmux.until { |lines| assert_equal '__3__', lines[0] }
+
+ # Hide the preview window with hidden flag
+ tmux.send_keys 'd'
+ tmux.until { |lines| refute_includes lines[0], '__3__' }
+
+ # One-off preview
+ tmux.send_keys 'e'
+ tmux.until do |lines|
+ assert_equal '::', lines[0]
+ refute_includes lines[1], '3'
+ end
+
+ # Wrapped
+ tmux.send_keys 'f'
+ tmux.until do |lines|
+ assert_equal '::', lines[0]
+ assert_equal ' 3', lines[1]
+ end
+ end
+
+ def test_change_preview_window_rotate
+ tmux.send_keys "seq 100 | #{FZF} --preview-window left,border-none --preview 'echo hello' --bind '" \
+ "a:change-preview-window(right|down|up|hidden|)'", :Enter
+ 3.times do
+ tmux.until { |lines| lines[0].start_with?('hello') }
+ tmux.send_keys 'a'
+ tmux.until { |lines| lines[0].end_with?('hello') }
+ tmux.send_keys 'a'
+ tmux.until { |lines| lines[-1].start_with?('hello') }
+ tmux.send_keys 'a'
+ tmux.until { |lines| assert_equal 'hello', lines[0] }
+ tmux.send_keys 'a'
+ tmux.until { |lines| refute_includes lines[0], 'hello' }
+ tmux.send_keys 'a'
+ end
+ end
+
+ def test_ellipsis
+ tmux.send_keys 'seq 1000 | tr "\n" , | fzf --ellipsis=SNIPSNIP -e -q500', :Enter
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.until { |lines| assert_match(/^> SNIPSNIP.*SNIPSNIP$/, lines[-3]) }
+ end
+end
+
+module TestShell
+ def setup
+ @tmux = Tmux.new(shell)
+ tmux.prepare
+ end
+
+ def teardown
+ @tmux.kill
+ end
+
+ def set_var(name, val)
+ tmux.prepare
+ tmux.send_keys "export #{name}='#{val}'", :Enter
+ tmux.prepare
+ end
+
+ def unset_var(name)
+ tmux.prepare
+ tmux.send_keys "unset #{name}", :Enter
+ tmux.prepare
+ end
+
+ def test_ctrl_t
+ set_var('FZF_CTRL_T_COMMAND', 'seq 100')
+
+ tmux.prepare
+ tmux.send_keys 'C-t'
+ tmux.until { |lines| assert_equal 100, lines.item_count }
+ tmux.send_keys :Tab, :Tab, :Tab
+ tmux.until { |lines| assert lines.any_include?(' (3)') }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert lines.any_include?('1 2 3') }
+ tmux.send_keys 'C-c'
+ end
+
+ def test_ctrl_t_unicode
+ writelines(tempname, ['fzf-unicode 테스트1', 'fzf-unicode 테스트2'])
+ set_var('FZF_CTRL_T_COMMAND', "cat #{tempname}")
+
+ tmux.prepare
+ tmux.send_keys 'echo ', 'C-t'
+ tmux.until { |lines| assert_equal 2, lines.item_count }
+ tmux.send_keys 'fzf-unicode'
+ tmux.until { |lines| assert_equal 2, lines.match_count }
+
+ tmux.send_keys '1'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal 1, lines.select_count }
+
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert_equal 2, lines.match_count }
+
+ tmux.send_keys '2'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal 2, lines.select_count }
+
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_match(/echo .*fzf-unicode.*1.* .*fzf-unicode.*2/, lines.join) }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal 'fzf-unicode 테스트1 fzf-unicode 테스트2', lines[-1] }
+ end
+
+ def test_alt_c
+ tmux.prepare
+ tmux.send_keys :Escape, :c
+ lines = tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ expected = lines.reverse.find { |l| l.start_with?('> ') }[2..-1]
+ tmux.send_keys :Enter
+ tmux.prepare
+ tmux.send_keys :pwd, :Enter
+ tmux.until { |lines| assert lines[-1]&.end_with?(expected) }
+ end
+
+ def test_alt_c_command
+ set_var('FZF_ALT_C_COMMAND', 'echo /tmp')
+
+ tmux.prepare
+ tmux.send_keys 'cd /', :Enter
+
+ tmux.prepare
+ tmux.send_keys :Escape, :c
+ tmux.until { |lines| assert_equal 1, lines.item_count }
+ tmux.send_keys :Enter
+
+ tmux.prepare
+ tmux.send_keys :pwd, :Enter
+ tmux.until { |lines| assert_equal '/tmp', lines[-1] }
+ end
+
+ def test_ctrl_r
+ tmux.prepare
+ tmux.send_keys 'echo 1st', :Enter
+ tmux.prepare
+ tmux.send_keys 'echo 2nd', :Enter
+ tmux.prepare
+ tmux.send_keys 'echo 3d', :Enter
+ tmux.prepare
+ 3.times do
+ tmux.send_keys 'echo 3rd', :Enter
+ tmux.prepare
+ end
+ tmux.send_keys 'echo 4th', :Enter
+ tmux.prepare
+ tmux.send_keys 'C-r'
+ tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ tmux.send_keys 'e3d'
+ # Duplicates removed: 3d (1) + 3rd (1) => 2 matches
+ tmux.until { |lines| assert_equal 2, lines.match_count }
+ tmux.until { |lines| assert lines[-3]&.end_with?(' echo 3d') }
+ tmux.send_keys 'C-r'
+ tmux.until { |lines| assert lines[-3]&.end_with?(' echo 3rd') }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal 'echo 3rd', lines[-1] }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal '3rd', lines[-1] }
+ end
+
+ def test_ctrl_r_multiline
+ tmux.send_keys 'echo "foo', :Enter, 'bar"', :Enter
+ tmux.until { |lines| assert_equal %w[foo bar], lines[-2..-1] }
+ tmux.prepare
+ tmux.send_keys 'C-r'
+ tmux.until { |lines| assert_equal '>', lines[-1] }
+ tmux.send_keys 'foo bar'
+ tmux.until { |lines| assert lines[-3]&.end_with?('bar"') }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert lines[-1]&.end_with?('bar"') }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal %w[foo bar], lines[-2..-1] }
+ end
+
+ def test_ctrl_r_abort
+ skip("doesn't restore the original line when search is aborted pre Bash 4") if shell == :bash && `#{Shell.bash} --version`[/(?<= version )\d+/].to_i < 4
+ %w[foo ' "].each do |query|
+ tmux.prepare
+ tmux.send_keys :Enter, query
+ tmux.until { |lines| assert lines[-1]&.start_with?(query) }
+ tmux.send_keys 'C-r'
+ tmux.until { |lines| assert_equal "> #{query}", lines[-1] }
+ tmux.send_keys 'C-g'
+ tmux.until { |lines| assert lines[-1]&.start_with?(query) }
+ end
+ end
+end
+
+module CompletionTest
+ def test_file_completion
+ FileUtils.mkdir_p('/tmp/fzf-test')
+ FileUtils.mkdir_p('/tmp/fzf test')
+ (1..100).each { |i| FileUtils.touch("/tmp/fzf-test/#{i}") }
+ ['no~such~user', '/tmp/fzf test/foobar'].each do |f|
+ FileUtils.touch(File.expand_path(f))
+ end
+ tmux.prepare
+ tmux.send_keys 'cat /tmp/fzf-test/10**', :Tab
+ tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ tmux.send_keys ' !d'
+ tmux.until { |lines| assert_equal 2, lines.match_count }
+ tmux.send_keys :Tab, :Tab
+ tmux.until { |lines| assert_equal 2, lines.select_count }
+ tmux.send_keys :Enter
+ tmux.until(true) do |lines|
+ assert_equal 'cat /tmp/fzf-test/10 /tmp/fzf-test/100', lines[-1]
+ end
+
+ # ~USERNAME**<TAB>
+ user = `whoami`.chomp
+ tmux.send_keys 'C-u'
+ tmux.send_keys "cat ~#{user}**", :Tab
+ tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ tmux.send_keys "/#{user}"
+ tmux.until { |lines| assert(lines.any? { |l| l.end_with?("/#{user}") }) }
+ tmux.send_keys :Enter
+ tmux.until(true) do |lines|
+ assert_match %r{cat .*/#{user}}, lines[-1]
+ end
+
+ # ~INVALID_USERNAME**<TAB>
+ tmux.send_keys 'C-u'
+ tmux.send_keys 'cat ~such**', :Tab
+ tmux.until(true) { |lines| assert lines.any_include?('no~such~user') }
+ tmux.send_keys :Enter
+ tmux.until(true) { |lines| assert_equal 'cat no~such~user', lines[-1] }
+
+ # /tmp/fzf\ test**<TAB>
+ tmux.send_keys 'C-u'
+ tmux.send_keys 'cat /tmp/fzf\ test/**', :Tab
+ tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ tmux.send_keys 'foobar$'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Enter
+ tmux.until(true) { |lines| assert_equal 'cat /tmp/fzf\ test/foobar', lines[-1] }
+
+ # Should include hidden files
+ (1..100).each { |i| FileUtils.touch("/tmp/fzf-test/.hidden-#{i}") }
+ tmux.send_keys 'C-u'
+ tmux.send_keys 'cat /tmp/fzf-test/hidden**', :Tab
+ tmux.until(true) do |lines|
+ assert_equal 100, lines.match_count
+ assert lines.any_include?('/tmp/fzf-test/.hidden-')
+ end
+ tmux.send_keys :Enter
+ ensure
+ ['/tmp/fzf-test', '/tmp/fzf test', '~/.fzf-home', 'no~such~user'].each do |f|
+ FileUtils.rm_rf(File.expand_path(f))
+ end
+ end
+
+ def test_file_completion_root
+ tmux.send_keys 'ls /**', :Tab
+ tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ tmux.send_keys :Enter
+ end
+
+ def test_dir_completion
+ (1..100).each do |idx|
+ FileUtils.mkdir_p("/tmp/fzf-test/d#{idx}")
+ end
+ FileUtils.touch('/tmp/fzf-test/d55/xxx')
+ tmux.prepare
+ tmux.send_keys 'cd /tmp/fzf-test/**', :Tab
+ tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ tmux.send_keys :Tab, :Tab # Tab does not work here
+ tmux.send_keys 55
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Enter
+ tmux.until(true) { |lines| assert_equal 'cd /tmp/fzf-test/d55/', lines[-1] }
+ tmux.send_keys :xx
+ tmux.until { |lines| assert_equal 'cd /tmp/fzf-test/d55/xx', lines[-1] }
+
+ # Should not match regular files (bash-only)
+ if instance_of?(TestBash)
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal 'cd /tmp/fzf-test/d55/xx', lines[-1] }
+ end
+
+ # Fail back to plusdirs
+ tmux.send_keys :BSpace, :BSpace, :BSpace
+ tmux.until { |lines| assert_equal 'cd /tmp/fzf-test/d55', lines[-1] }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal 'cd /tmp/fzf-test/d55/', lines[-1] }
+ end
+
+ def test_process_completion
+ tmux.send_keys 'sleep 12345 &', :Enter
+ lines = tmux.until { |lines| assert lines[-1]&.start_with?('[1] ') }
+ pid = lines[-1]&.split&.last
+ tmux.prepare
+ tmux.send_keys 'C-L'
+ tmux.send_keys 'kill **', :Tab
+ tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ tmux.send_keys 'sleep12345'
+ tmux.until { |lines| assert lines.any_include?('sleep 12345') }
+ tmux.send_keys :Enter
+ tmux.until(true) { |lines| assert_equal "kill #{pid}", lines[-1] }
+ ensure
+ if pid
+ begin
+ Process.kill('KILL', pid.to_i)
+ rescue StandardError
+ nil
+ end
+ end
+ end
+
+ def test_custom_completion
+ tmux.send_keys '_fzf_compgen_path() { echo "$1"; seq 10; }', :Enter
+ tmux.prepare
+ tmux.send_keys 'ls /tmp/**', :Tab
+ tmux.until { |lines| assert_equal 11, lines.match_count }
+ tmux.send_keys :Tab, :Tab, :Tab
+ tmux.until { |lines| assert_equal 3, lines.select_count }
+ tmux.send_keys :Enter
+ tmux.until(true) { |lines| assert_equal 'ls /tmp 1 2', lines[-1] }
+ end
+
+ def test_unset_completion
+ tmux.send_keys 'export FZFFOOBAR=BAZ', :Enter
+ tmux.prepare
+
+ # Using tmux
+ tmux.send_keys 'unset FZFFOOBR**', :Tab
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal 'unset FZFFOOBAR', lines[-1] }
+ tmux.send_keys 'C-c'
+
+ # FZF_TMUX=1
+ new_shell
+ tmux.focus
+ tmux.send_keys 'unset FZFFOOBR**', :Tab
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal 'unset FZFFOOBAR', lines[-1] }
+ end
+
+ def test_file_completion_unicode
+ FileUtils.mkdir_p('/tmp/fzf-test')
+ tmux.paste "cd /tmp/fzf-test; echo test3 > $'fzf-unicode \\355\\205\\214\\354\\212\\244\\355\\212\\2701'; echo test4 > $'fzf-unicode \\355\\205\\214\\354\\212\\244\\355\\212\\2702'"
+ tmux.prepare
+ tmux.send_keys 'cat fzf-unicode**', :Tab
+ tmux.until { |lines| assert_equal 2, lines.match_count }
+
+ tmux.send_keys '1'
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal 1, lines.select_count }
+
+ tmux.send_keys :BSpace
+ tmux.until { |lines| assert_equal 2, lines.match_count }
+
+ tmux.send_keys '2'
+ tmux.until { |lines| assert_equal 1, lines.select_count }
+ tmux.send_keys :Tab
+ tmux.until { |lines| assert_equal 2, lines.select_count }
+
+ tmux.send_keys :Enter
+ tmux.until(true) { |lines| assert_match(/cat .*fzf-unicode.*1.* .*fzf-unicode.*2/, lines[-1]) }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal %w[test3 test4], lines[-2..-1] }
+ end
+
+ def test_custom_completion_api
+ tmux.send_keys 'eval "_fzf$(declare -f _comprun)"', :Enter
+ %w[f g].each do |command|
+ tmux.prepare
+ tmux.send_keys "#{command} b**", :Tab
+ tmux.until do |lines|
+ assert_equal 2, lines.item_count
+ assert_equal 1, lines.match_count
+ assert lines.any_include?("prompt-#{command}")
+ assert lines.any_include?("preview-#{command}-bar")
+ end
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal "#{command} #{command}barbar", lines[-1] }
+ tmux.send_keys 'C-u'
+ end
+ ensure
+ tmux.prepare
+ tmux.send_keys 'unset -f _fzf_comprun', :Enter
+ end
+end
+
+class TestBash < TestBase
+ include TestShell
+ include CompletionTest
+
+ def shell
+ :bash
+ end
+
+ def new_shell
+ tmux.prepare
+ tmux.send_keys "FZF_TMUX=1 #{Shell.bash}", :Enter
+ tmux.prepare
+ end
+
+ def test_dynamic_completion_loader
+ tmux.paste 'touch /tmp/foo; _fzf_completion_loader=1'
+ tmux.paste '_completion_loader() { complete -o default fake; }'
+ tmux.paste 'complete -F _fzf_path_completion -o default -o bashdefault fake'
+ tmux.send_keys 'fake /tmp/foo**', :Tab
+ tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ tmux.send_keys 'C-c'
+
+ tmux.prepare
+ tmux.send_keys 'fake /tmp/foo'
+ tmux.send_keys :Tab, 'C-u'
+
+ tmux.prepare
+ tmux.send_keys 'fake /tmp/foo**', :Tab
+ tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
+ end
+end
+
+class TestZsh < TestBase
+ include TestShell
+ include CompletionTest
+
+ def shell
+ :zsh
+ end
+
+ def new_shell
+ tmux.send_keys "FZF_TMUX=1 #{Shell.zsh}", :Enter
+ tmux.prepare
+ end
+
+ def test_complete_quoted_command
+ tmux.send_keys 'export FZFFOOBAR=BAZ', :Enter
+ ['unset', '\unset', "'unset'"].each do |command|
+ tmux.prepare
+ tmux.send_keys "#{command} FZFFOOBR**", :Tab
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Enter
+ tmux.until { |lines| assert_equal "#{command} FZFFOOBAR", lines[-1] }
+ tmux.send_keys 'C-c'
+ end
+ end
+end
+
+class TestFish < TestBase
+ include TestShell
+
+ def shell
+ :fish
+ end
+
+ def new_shell
+ tmux.send_keys 'env FZF_TMUX=1 fish', :Enter
+ tmux.send_keys 'function fish_prompt; end; clear', :Enter
+ tmux.until { |lines| assert_empty lines }
+ end
+
+ def set_var(name, val)
+ tmux.prepare
+ tmux.send_keys "set -g #{name} '#{val}'", :Enter
+ tmux.prepare
+ end
+end
+
+__END__
+PS1= PROMPT_COMMAND= HISTFILE= HISTSIZE=100
+unset <%= UNSETS.join(' ') %>
+unset $(env | sed -n /^_fzf_orig/s/=.*//p)
+unset $(declare -F | sed -n "/_fzf/s/.*-f //p")
+
+# Setup fzf
+# ---------
+if [[ ! "$PATH" == *<%= BASE %>/bin* ]]; then
+ export PATH="${PATH:+${PATH}:}<%= BASE %>/bin"
+fi
+
+# Auto-completion
+# ---------------
+[[ $- == *i* ]] && source "<%= BASE %>/shell/completion.<%= __method__ %>" 2> /dev/null
+
+# Key bindings
+# ------------
+source "<%= BASE %>/shell/key-bindings.<%= __method__ %>"
+
+# Old API
+_fzf_complete_f() {
+ _fzf_complete "+m --multi --prompt \"prompt-f> \"" "$@" < <(
+ echo foo
+ echo bar
+ )
+}
+
+# New API
+_fzf_complete_g() {
+ _fzf_complete +m --multi --prompt "prompt-g> " -- "$@" < <(
+ echo foo
+ echo bar
+ )
+}
+
+_fzf_complete_f_post() {
+ awk '{print "f" $0 $0}'
+}
+
+_fzf_complete_g_post() {
+ awk '{print "g" $0 $0}'
+}
+
+[ -n "$BASH" ] && complete -F _fzf_complete_f -o default -o bashdefault f
+[ -n "$BASH" ] && complete -F _fzf_complete_g -o default -o bashdefault g
+
+_comprun() {
+ local command=$1
+ shift
+
+ case "$command" in
+ f) fzf "$@" --preview 'echo preview-f-{}' ;;
+ g) fzf "$@" --preview 'echo preview-g-{}' ;;
+ *) fzf "$@" ;;
+ esac
+}
diff --git a/dot-oh-my-zsh/custom/plugins/fzf/uninstall b/dot-oh-my-zsh/custom/plugins/fzf/uninstall
new file mode 100755
index 00000000..4e587211
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/fzf/uninstall
@@ -0,0 +1,113 @@
+#!/usr/bin/env bash
+
+xdg=0
+prefix='~/.fzf'
+prefix_expand=~/.fzf
+fish_dir=${XDG_CONFIG_HOME:-$HOME/.config}/fish
+
+help() {
+ cat << EOF
+usage: $0 [OPTIONS]
+
+ --help Show this message
+ --xdg Remove files generated under \$XDG_CONFIG_HOME/fzf
+EOF
+}
+
+for opt in "$@"; do
+ case $opt in
+ --help)
+ help
+ exit 0
+ ;;
+ --xdg)
+ xdg=1
+ prefix='"${XDG_CONFIG_HOME:-$HOME/.config}"/fzf/fzf'
+ prefix_expand=${XDG_CONFIG_HOME:-$HOME/.config}/fzf/fzf
+ ;;
+ *)
+ echo "unknown option: $opt"
+ help
+ exit 1
+ ;;
+ esac
+done
+
+ask() {
+ while true; do
+ read -p "$1 ([y]/n) " -r
+ REPLY=${REPLY:-"y"}
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ return 0
+ elif [[ $REPLY =~ ^[Nn]$ ]]; then
+ return 1
+ fi
+ done
+}
+
+remove() {
+ echo "Remove $1"
+ rm -f "$1"
+}
+
+remove_line() {
+ src=$1
+ echo "Remove from $1:"
+
+ shift
+ line_no=1
+ match=0
+ while [ -n "$1" ]; do
+ line=$(sed -n "$line_no,\$p" "$src" | \grep -m1 -nF "$1")
+ if [ $? -ne 0 ]; then
+ shift
+ line_no=1
+ continue
+ fi
+ line_no=$(( $(sed 's/:.*//' <<< "$line") + line_no - 1 ))
+ content=$(sed 's/^[0-9]*://' <<< "$line")
+ match=1
+ echo " - Line #$line_no: $content"
+ [ "$content" = "$1" ] || ask " - Remove?"
+ if [ $? -eq 0 ]; then
+ temp=$(mktemp)
+ awk -v n=$line_no 'NR == n {next} {print}' "$src" > "$temp" &&
+ cat "$temp" > "$src" && rm -f "$temp" || break
+ echo " - Removed"
+ else
+ echo " - Skipped"
+ line_no=$(( line_no + 1 ))
+ fi
+ done
+ [ $match -eq 0 ] && echo " - Nothing found"
+ echo
+}
+
+for shell in bash zsh; do
+ shell_config=${prefix_expand}.${shell}
+ remove "${shell_config}"
+ remove_line ~/.${shell}rc \
+ "[ -f ${prefix}.${shell} ] && source ${prefix}.${shell}" \
+ "source ${prefix}.${shell}"
+done
+
+bind_file="${fish_dir}/functions/fish_user_key_bindings.fish"
+if [ -f "$bind_file" ]; then
+ remove_line "$bind_file" "fzf_key_bindings"
+fi
+
+if [ -d "${fish_dir}/functions" ]; then
+ remove "${fish_dir}/functions/fzf.fish"
+ remove "${fish_dir}/functions/fzf_key_bindings.fish"
+
+ if [ -z "$(ls -A "${fish_dir}/functions")" ]; then
+ rmdir "${fish_dir}/functions"
+ else
+ echo "Can't delete non-empty directory: \"${fish_dir}/functions\""
+ fi
+fi
+
+config_dir=$(dirname "$prefix_expand")
+if [[ "$xdg" = 1 ]] && [[ "$config_dir" = */fzf ]] && [[ -d "$config_dir" ]]; then
+ rmdir "$config_dir"
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/sudo/sudo.plugin.zsh b/dot-oh-my-zsh/custom/plugins/sudo/sudo.plugin.zsh
new file mode 100644
index 00000000..0ba8bed5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/sudo/sudo.plugin.zsh
@@ -0,0 +1,25 @@
+# ------------------------------------------------------------------------------
+# Description
+# -----------
+#
+# sudo will be inserted before the command
+#
+# ------------------------------------------------------------------------------
+# Authors
+# -------
+#
+# * Dongweiming <ciici123@gmail.com>
+#
+# ------------------------------------------------------------------------------
+
+sudo-command-line() {
+ [[ -z $BUFFER ]] && zle up-history
+ if [[ $BUFFER == sudo\ * ]]; then
+ LBUFFER="${LBUFFER#sudo }"
+ else
+ LBUFFER="sudo $LBUFFER"
+ fi
+}
+zle -N sudo-command-line
+# Defined shortcut keys: [Esc] [Esc]
+bindkey "\e\e" sudo-command-line
diff --git a/dot-oh-my-zsh/custom/plugins/web-search/web-search.plugin.zsh b/dot-oh-my-zsh/custom/plugins/web-search/web-search.plugin.zsh
new file mode 100644
index 00000000..ec176dd6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/web-search/web-search.plugin.zsh
@@ -0,0 +1,86 @@
+# web_search from terminal
+
+function web_search() {
+ emulate -L zsh
+
+ # define search engine URLS
+ typeset -A urls
+ urls=(
+ $ZSH_WEB_SEARCH_ENGINES
+ google "https://www.google.com/search?q="
+ bing "https://www.bing.com/search?q="
+ brave "https://search.brave.com/search?q="
+ yahoo "https://search.yahoo.com/search?p="
+ duckduckgo "https://www.duckduckgo.com/?q="
+ startpage "https://www.startpage.com/do/search?q="
+ yandex "https://yandex.ru/yandsearch?text="
+ github "https://github.com/search?q="
+ baidu "https://www.baidu.com/s?wd="
+ ecosia "https://www.ecosia.org/search?q="
+ goodreads "https://www.goodreads.com/search?q="
+ qwant "https://www.qwant.com/?q="
+ givero "https://www.givero.com/search?q="
+ stackoverflow "https://stackoverflow.com/search?q="
+ wolframalpha "https://www.wolframalpha.com/input/?i="
+ archive "https://web.archive.org/web/*/"
+ scholar "https://scholar.google.com/scholar?q="
+ ask "https://www.ask.com/web?q="
+ )
+
+ # check whether the search engine is supported
+ if [[ -z "$urls[$1]" ]]; then
+ echo "Search engine '$1' not supported."
+ return 1
+ fi
+
+ # search or go to main page depending on number of arguments passed
+ if [[ $# -gt 1 ]]; then
+ # build search url:
+ # join arguments passed with '+', then append to search engine URL
+ url="${urls[$1]}$(omz_urlencode ${@[2,-1]})"
+ else
+ # build main page url:
+ # split by '/', then rejoin protocol (1) and domain (2) parts with '//'
+ url="${(j://:)${(s:/:)urls[$1]}[1,2]}"
+ fi
+
+ open_command "$url"
+}
+
+
+alias bing='web_search bing'
+alias brs='web_search brave'
+alias google='web_search google'
+alias yahoo='web_search yahoo'
+alias ddg='web_search duckduckgo'
+alias sp='web_search startpage'
+alias yandex='web_search yandex'
+alias github='web_search github'
+alias baidu='web_search baidu'
+alias ecosia='web_search ecosia'
+alias goodreads='web_search goodreads'
+alias qwant='web_search qwant'
+alias givero='web_search givero'
+alias stackoverflow='web_search stackoverflow'
+alias wolframalpha='web_search wolframalpha'
+alias archive='web_search archive'
+alias scholar='web_search scholar'
+alias ask='web_search ask'
+
+#add your own !bang searches here
+alias wiki='web_search duckduckgo \!w'
+alias news='web_search duckduckgo \!n'
+alias youtube='web_search duckduckgo \!yt'
+alias map='web_search duckduckgo \!m'
+alias image='web_search duckduckgo \!i'
+alias ducky='web_search duckduckgo \!'
+
+# other search engine aliases
+if [[ ${#ZSH_WEB_SEARCH_ENGINES} -gt 0 ]]; then
+ typeset -A engines
+ engines=($ZSH_WEB_SEARCH_ENGINES)
+ for key in ${(k)engines}; do
+ alias "$key"="web_search $key"
+ done
+ unset engines key
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.clitest/complete-word.post.md b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.clitest/complete-word.post.md
new file mode 100644
index 00000000..5685a899
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.clitest/complete-word.post.md
@@ -0,0 +1,86 @@
+Setup:
+```zsh
+% zmodload zsh/param/private
+% autoload -Uz zmathfunc && zmathfunc
+% autoload -Uz $PWD/functions/widget/.autocomplete.complete-word.post
+% unset terminfo
+% typeset -gA compstate=() _lastcomp=() terminfo=()
+% zstyle ':autocomplete:*' add-space 'FOO' 'TAG' 'BAR'
+% zstyle ':autocomplete:(|shift-)tab:' widget-style complete-word
+% KEYS=$'\t' WIDGET=complete-word terminfo[kcbt]=BACKTAB
+% compstate[old_list]=keep compstate[nmatches]=0 _lastcomp[nmatches]=2
+%
+```
+
+If we have only 1 match, just insert it:
+```zsh
+% _lastcomp[nmatches]=1
+% .autocomplete.complete-word.post
+% print -r -- ${(q+)compstate[insert]} $+compstate[list] $+MENUSELECT
+1 0 0
+% _lastcomp[nmatches]=2
+%
+```
+
+If we have more than 1 match, but there's no old list, then show the list and don't insert:
+```zsh
+% compstate[old_list]= compstate[nmatches]=2
+% .autocomplete.complete-word.post
+% print -r -- ${(q+)compstate[insert]} $+compstate[list] $+MENUSELECT
+'' 1 0
+% compstate[old_list]=keep compstate[nmatches]=0
+%
+```
+
+`menu-*` widgets set `$compstate[insert]` to `menu:*`:
+```zsh
+% zstyle ':autocomplete:shift-tab:' widget-style reverse-menu-complete
+% KEYS=$terminfo[kcbt]
+% .autocomplete.complete-word.post
+% print -r -- ${(q+)compstate[insert]} $+compstate[list] $+MENUSELECT
+menu:0 0 0
+% zstyle ':autocomplete:shift-tab:' widget-style complete-word
+% KEYS=$'\t'
+%
+```
+
+Widgets default to `menu-select`, which sets `$MENUSELECT`, even without old list:
+```zsh
+% KEYS=OTHER compstate[old_list]= compstate[nmatches]=2
+% .autocomplete.complete-word.post
+% print -r -- ${(q+)compstate[insert]} $+compstate[list] $+MENUSELECT
+menu:1 0 1
+% KEYS=$'\t' compstate[old_list]=keep compstate[nmatches]=0
+%
+```
+
+`Shift-Tab` key sets `$compstate[insert]` to `*0`:
+```zsh
+% KEYS=$terminfo[kcbt]
+% .autocomplete.complete-word.post
+% print -r -- ${(q+)compstate[insert]} $+compstate[list] $+MENUSELECT
+0 0 0
+% KEYS=$'\t'
+%
+```
+
+If the list is showing and there's an `add-space` tag in the last completion, then add a space:
+```zsh
+# % functions -T .autocomplete.complete-word.post
+% _comp_tags='OTHER' _lastcomp[tags]='LOREM TAG IPSUM'
+% .autocomplete.complete-word.post
+% print -r -- ${(q+)compstate[insert]} $+compstate[list] $+MENUSELECT
+'1 ' 0 0
+% compstate[old_list]= _lastcomp[tags]=
+%
+```
+
+If the list is not showing and there's an `add-space` tag in the new completion, then add a space:
+```zsh
+% compstate[old_list]= _comp_tags='LOREM TAG IPSUM' _lastcomp[tags]='OTHER'
+% .autocomplete.complete-word.post
+% print -r -- ${(q+)compstate[insert]} $+compstate[list] $+MENUSELECT
+'1 ' 0 0
+% compstate[old_list]=keep _comp_tags= _lastcomp[tags]=
+%
+```
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/alias-expansion.png b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/alias-expansion.png
new file mode 100644
index 00000000..368c44ee
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/alias-expansion.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/file-search.gif b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/file-search.gif
new file mode 100644
index 00000000..fb4b8441
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/file-search.gif
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-lines.png b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-lines.png
new file mode 100644
index 00000000..d9e8572d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-lines.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-menu.png b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-menu.png
new file mode 100644
index 00000000..5b9eb220
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-menu.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-search.gif b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-search.gif
new file mode 100644
index 00000000..c240303e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-search.gif
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/multi-select.png b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/multi-select.png
new file mode 100644
index 00000000..b5775af6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/multi-select.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/recent-dirs.png b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/recent-dirs.png
new file mode 100644
index 00000000..5769108e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/recent-dirs.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/requoted.png b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/requoted.png
new file mode 100644
index 00000000..364f5c71
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/requoted.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/unambiguous.png b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/unambiguous.png
new file mode 100644
index 00000000..b02921f6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/unambiguous.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.vscode/settings.json b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.vscode/settings.json
new file mode 100644
index 00000000..1da35530
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "files.associations": {
+ "_*": "shellscript"
+ }
+} \ No newline at end of file
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.zshrc b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.zshrc
new file mode 100644
index 00000000..6a06f216
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.zshrc
@@ -0,0 +1,99 @@
+#!/bin/zsh
+
+# The code below sets all of Autocomplete's settings to their default values. To
+# change a setting, copy it into your `.zshrc` file and modify it there.
+
+
+zstyle ':autocomplete:*' default-context ''
+# '': Start each new command line with normal autocompletion.
+# history-incremental-search-backward: Start in live history search mode.
+
+zstyle ':autocomplete:*' min-delay 0.05 # seconds (float)
+# Wait this many seconds for typing to stop, before showing completions.
+
+zstyle ':autocomplete:*' min-input 0 # characters (int)
+# Wait until this many characters have been typed, before showing completions.
+
+zstyle ':autocomplete:*' ignored-input '' # extended glob pattern
+# '': Always show completions.
+# '..##': Don't show completions for the current word, if it consists of two
+# or more dots.
+
+zstyle ':autocomplete:*' list-lines 16 # int
+# If there are fewer than this many lines below the prompt, move the prompt up
+# to make room for showing this many lines of completions (approximately).
+
+zstyle ':autocomplete:history-search:*' list-lines 16 # int
+# Show this many history lines when pressing ↑.
+
+zstyle ':autocomplete:history-incremental-search-*:*' list-lines 16 # int
+# Show this many history lines when pressing ⌃R or ⌃S.
+
+zstyle ':autocomplete:*' insert-unambiguous no
+# no: Tab inserts the top completion.
+# yes: Tab first inserts a substring common to all listed completions, if any.
+
+zstyle ':autocomplete:*' fzf-completion no
+# no: Tab uses Zsh's completion system only.
+# yes: Tab first tries Fzf's completion, then falls back to Zsh's.
+# ⚠️ NOTE: This setting can NOT be changed at runtime and requires that you
+# have installed Fzf's shell extensions.
+
+# Add a space after these completions:
+zstyle ':autocomplete:*' add-space \
+ executables aliases functions builtins reserved-words commands
+
+
+##
+# Config in this section should come BEFORE sourcing Autocomplete and cannot be
+# changed at runtime.
+#
+
+# Autocomplete automatically selects a backend for its recent dirs completions.
+# So, normally you won't need to change this.
+# However, you can set it if you find that the wrong backend is being used.
+zstyle ':autocomplete:recent-dirs' backend cdr
+# cdr: Use Zsh's `cdr` function to show recent directories as completions.
+# no: Don't show recent directories.
+# zsh-z|zoxide|z.lua|z.sh|autojump|fasd: Use this instead (if installed).
+# ⚠️ NOTE: This setting can NOT be changed at runtime.
+
+zstyle ':autocomplete:*' widget-style complete-word
+# complete-word: (Shift-)Tab inserts the top (bottom) completion.
+# menu-complete: Press again to cycle to next (previous) completion.
+# menu-select: Same as `menu-complete`, but updates selection in menu.
+# ⚠️ NOTE: This setting can NOT be changed at runtime.
+
+
+source /path/to/zsh-autocomplete.plugin.zsh
+
+
+##
+# Config in this section should come AFTER sourcing Autocomplete.
+#
+
+# Up arrow:
+bindkey '\e[A' up-line-or-search
+bindkey '\eOA' up-line-or-search
+# up-line-or-search: Open history menu.
+# up-line-or-history: Cycle to previous history line.
+
+# Down arrow:
+bindkey '\e[B' down-line-or-select
+bindkey '\eOB' down-line-or-select
+# down-line-or-select: Open completion menu.
+# down-line-or-history: Cycle to next history line.
+
+# Control-Space:
+bindkey '\0' list-expand
+# list-expand: Reveal hidden completions.
+# set-mark-command: Activate text selection.
+
+# Uncomment the following lines to disable live history search:
+# zle -A {.,}history-incremental-search-forward
+# zle -A {.,}history-incremental-search-backward
+
+# Return key in completion menu & history menu:
+bindkey -M menuselect '\r' .accept-line
+# .accept-line: Accept command line.
+# accept-line: Accept selection and exit menu.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/LICENSE b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/LICENSE
new file mode 100644
index 00000000..58c46b87
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2020 Marlon Richert
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/README.md b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/README.md
new file mode 100644
index 00000000..03904d98
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/README.md
@@ -0,0 +1,150 @@
+# `zsh-autocomplete`
+`zsh-autocomplete` adds **real-time type-ahead autocompletion** to Zsh. Find as you type, then
+press <kbd>Tab</kbd> to insert the top completion, <kbd>Shift</kbd><kbd>Tab</kbd> to insert the
+bottom one, or <kbd>↓</kbd>/<kbd>PgDn</kbd> to select another completion.
+
+[![file-search](.img/file-search.gif)](https://asciinema.org/a/377611)
+
+> Enjoy using this software? [Become a sponsor!](https://github.com/sponsors/marlonrichert).
+
+## Other Features
+Besides live autocompletion, `zsh-autocomplete` comes with many other useful completion features.
+
+### Optimized completion config
+Zsh's completion system is powerful, but hard to configure. So, `zsh-autocomplete` [does it for
+you](scripts/.autocomplete.config), while providing a manageable list of [configuration
+settings](.zshrc) for changing the defaults.
+
+### Live history search
+Press <kbd>Ctrl</kbd><kbd>R</kbd> or <kbd>Ctrl</kbd><kbd>S</kbd> to do live, multi-line history
+search.
+
+[![history-search](.img/history-search.gif)](https://asciinema.org/a/379844)
+
+### History menu
+Press <kbd>↑</kbd> (or <kbd>Alt</kbd><kbd>↑</kbd> or <kbd>PgUp</kbd>) to open a menu with the last
+16 history items. If the command line is not empty, then the contents of the command line are used
+to perform a fuzzy history search.
+
+![history menu](.img/history-menu.png)
+
+### Multi-selection
+Press <kbd>Ctrl</kbd><kbd>Space</kbd> in the completion menu or the history menu to insert more
+than one item.
+
+![multi-select](.img/multi-select.png)
+
+### Recent dirs completion
+Works out of the box with zero configuration, but also supports `zsh-z`, `zoxide`, `z.lua`,
+`rupa/z.sh`, `autojump` and `fasd`.
+
+![recent dirs](.img/recent-dirs.png)
+
+## Key Bindings
+
+On the command line:
+| Key(s) | Action | <sub>[Widget](.zshrc)</sub> |
+| ------ | ------ | --- |
+| <kbd>Tab</kbd> | Insert top completion | <sub>`complete-word`</sub> |
+| <kbd>Shift</kbd><kbd>Tab</kbd> | Insert bottom completion | <sub>`complete-word`</sub> |
+| <kbd>Ctrl</kbd><kbd>Space</kbd> | Show additional completions | <sub>`list-expand`</sub> |
+| <kbd>↓</kbd> | Cursor down (if able) or completion menu | <sub>`down-line-or-select`</sub> |
+| <kbd>PgDn</kbd> / <kbd>Alt</kbd><kbd>↓</kbd> | Completion menu (always) | <sub>`menu-select`</sub> |
+| <kbd>↑</kbd> | Cursor up (if able) or [history menu](#history-menu) | <sub>`up-line-or-search`</sub> |
+| <kbd>PgUp</kbd> / <kbd>Alt</kbd><kbd>↑</kbd> | [History menu](#history-menu) (always) | <sub>`history-search`</sub> |
+| <kbd>Ctrl</kbd><kbd>R</kbd> | [Live history search](#live-history-search), newest to oldest | <sub>`history-incremental-search-backward`</sub> |
+| <kbd>Ctrl</kbd><kbd>S</kbd> | [Live history search](#live-history-search), oldest to newest | <sub>`history-incremental-search-forward`</sub> |
+
+In the completion menu:
+| Key(s) | Action |
+| ------ | ------ |
+| <kbd>↑</kbd> / <kbd>↓</kbd> / <kbd>←</kbd> / <kbd>→</kbd> | Change selection |
+| <kbd>Alt</kbd><kbd>↑</kbd> | Backward one group |
+| <kbd>Alt</kbd><kbd>↓</kbd> | Forward one group |
+| <kbd>PgUp</kbd> / <kbd>PgDn</kbd> | Page up/down |
+| <kbd>Ctrl</kbd><kbd>R</kbd> | Find text forward |
+| <kbd>Ctrl</kbd><kbd>S</kbd> | Find text backward |
+| <kbd>Tab</kbd> | Insert selection and exit menu |
+| <kbd>Ctrl</kbd><kbd>Space</kbd> | Insert selection, but stay in menu |
+| <kbd>Shift</kbd><kbd>Tab</kbd> | Insert bottom completion and exit menu |
+| <kbd>Ctrl</kbd><kbd>-</kbd><br><kbd>Ctrl</kbd><kbd>/</kbd> | Undo and exit menu |
+| <kbd>Enter</kbd> | Submit command line |
+| other keys | Zsh [default behavior](https://zsh.sourceforge.io/Doc/Release/Zsh-Modules.html#Menu-selection) |
+
+In the history menu:
+| Key(s) | Action |
+| --- | --- |
+| <kbd>↑</kbd> / <kbd>↓</kbd> | Change selection |
+| <kbd>Tab</kbd> | Insert selection and exit menu |
+| <kbd>Ctrl</kbd><kbd>Space</kbd> | Insert selection, but stay in menu |
+| <kbd>Ctrl</kbd><kbd>-</kbd><br><kbd>Ctrl</kbd><kbd>/</kbd> | Undo and exit menu |
+| <kbd>Enter</kbd> | Submit command line |
+| other keys | Zsh [default behavior](https://zsh.sourceforge.io/Doc/Release/Zsh-Modules.html#Menu-selection) |
+
+## Requirements
+Recommended:
+* Tested to work with [Zsh](http://zsh.sourceforge.net) 5.7 or newer.
+
+Minimum:
+* Should theoretically work with Zsh 5.4 or newer, but I'm unable to test that.
+
+## Installing & Updating
+If you use [Znap](https://github.com/marlonrichert/zsh-snap), simply add the following to your
+`.zshrc` file:
+```zsh
+znap source marlonrichert/zsh-autocomplete
+```
+Then restart your shell.
+
+To update, do
+```zsh
+% znap pull
+```
+
+For configuration options, see the included [`.zshrc` file](.zshrc).
+
+To uninstall, remove `znap source marlonrichert/zsh-autocomplete` from your `.zshrc` file, then run
+```zsh
+% znap uninstall
+```
+
+### Manual installation
+ 1. Clone the repo:
+ ```zsh
+ % cd ~/Git # ...or wherever you keep your Git repos/Zsh plugins
+ % git clone --depth 1 -- https://github.com/marlonrichert/zsh-autocomplete.git
+ ```
+ 1. Add at or near the top of your `.zshrc` file (_before_ any calls to `compdef`):
+ ```zsh
+ source ~/Git/zsh-autocomplete/zsh-autocomplete.plugin.zsh
+ ```
+ 1. Remove any calls to `compinit` from your `.zshrc` file.
+ 1. If you're using Ubuntu, add to your `.zshenv` file:
+ ```zsh
+ skip_global_compinit=1
+ ```
+Then restart your shell.
+
+To update, do:
+```zsh
+% git -C ~zsh-autocomplete pull
+```
+
+To uninstall, simply undo the installation steps above in reverse order:
+ 1. Restore the lines you deleted in step 3.
+ 1. Delete the line you added in step 2.
+ 1. Delete the repo you created in step 1.
+Finally, restart your shell.
+
+### Other Frameworks/Plugin Managers
+To install with another Zsh framework or plugin manager, please refer to your
+framework's/plugin manager's documentation for instructions.
+
+## Troubleshooting
+Try the steps in the [bug report template](.github/ISSUE_TEMPLATE/bug-report.md).
+
+## Author
+© 2020-2021 [Marlon Richert](https://github.com/marlonrichert)
+
+## License
+This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/.autocomplete.patch b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/.autocomplete.patch
new file mode 100644
index 00000000..dbff68ac
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/.autocomplete.patch
@@ -0,0 +1,6 @@
+#!/bin/zsh
+zmodload -F zsh/parameter p:functions
+
+unfunction $1 2> /dev/null
+builtin autoload +X -Uz $1
+functions[.autocomplete.$1]=$functions[$1]
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/.autocomplete.zle-flags b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/.autocomplete.zle-flags
new file mode 100644
index 00000000..3080ca90
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/.autocomplete.zle-flags
@@ -0,0 +1,32 @@
+#!/bin/zsh
+typeset -gH _autocomplete__last_widget=
+
+.autocomplete.zle-flags() {
+ emulate -L zsh
+ setopt $_autocomplete__func_opts[@]
+
+ # If no arg, assume same widget as last time.
+ [[ -v 1 && -n $1 ]] &&
+ typeset -gH _autocomplete__last_widget="$1"
+
+ # Return 0 to continue, 1 to abort.
+ case $_autocomplete__last_widget in
+ ( *kill-*~vi-* )
+ builtin zle -f kill
+ return 0
+ ;;
+ ( *yank*~vi-* | vi-*put-*after | bracketed-paste )
+ builtin zle -f yank
+ return 1
+ ;;
+ ( vi-*put-*before )
+ builtin zle -f yankbefore
+ return 1
+ ;;
+ ( * )
+ return 0
+ ;;
+ esac
+}
+
+.autocomplete.zle-flags "$@"
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.ancestor_dirs b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.ancestor_dirs
new file mode 100644
index 00000000..bac8cae6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.ancestor_dirs
@@ -0,0 +1,29 @@
+#autoload
+
+(( compstate[nmatches] )) &&
+ return 1
+
+[[ $_comp_tags != (|* )(|local-)directories(| *) ]] &&
+ return 1
+
+local displ= expl=
+_description -V ancestor-directories expl 'ancestor directory'
+
+local -Pa ancestors=()
+local -P parent=$PWD:h
+while (( $#parent > 1 )); do
+ ancestors+=( $parent )
+ parent=$parent:h
+done
+
+local -Pi ret=1
+local -P a=
+for a in ${(aO)ancestors[@]}; do
+ displ=( "$a" )
+ [[ -z $PREFIX$SUFFIX ]] &&
+ displ=( "$a:t" )
+ compadd "$expl[@]" -d displ -P "${${(D)a:h}%/}/" -fW "${${a:h}%/}/" - "$a:t" &&
+ ret=0
+done
+
+return ret
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.command b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.command
new file mode 100644
index 00000000..77f1d91d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.command
@@ -0,0 +1,7 @@
+#compdef -command-
+local -P ret=1
+_expand_alias "$@" &&
+ ret=0
+_autocd "$@" &&
+ ret=0
+return ret
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.compadd_opts_len b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.compadd_opts_len
new file mode 100644
index 00000000..a29c6508
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.compadd_opts_len
@@ -0,0 +1,10 @@
+#autoload
+
+local -Pi len=$(( ${@[(i)(-|--)]} - 1 ))
+(( len < $# )) &&
+ return len
+
+len=${@[(I)-*]}
+[[ $@[len] == -*[PSpsiIdJVXxrRWFMOAD] ]] &&
+ (( len++ ))
+return len
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.history_lines b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.history_lines
new file mode 100644
index 00000000..b808426e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.history_lines
@@ -0,0 +1,144 @@
+#autoload
+
+_autocomplete.history_lines() {
+ local -P tag=history-lines
+ _tags $tag
+ _tags ||
+ return 1
+ _requested $tag ||
+ return 1
+
+ local -PA events=()
+ local -Pi min_lines= max_lines=
+ builtin zstyle -s ":autocomplete:${curcontext}:" list-lines min_lines ||
+ min_lines=16
+ (( max_lines = min( min_lines, HISTNO - 1, LINES - BUFFERLINES ) ))
+
+ if [[ -z $BUFFER ]]; then
+ if [[ $curcontext == *-forward:* ]]; then
+ local -Pi inc=1 histno=1
+ else
+ local -Pi inc=-1 histno=$(( HISTNO - 1 ))
+ fi
+ if [[ -o histfindnodups ]]; then
+ while (( $#events[@] < max_lines && 0 < histno && histno < HISTNO )); do
+ # -v's arg is a literal string, so we need to quote all characters.
+ [[ -v history[$histno] && ! -v events[${(q)history[$histno]}] ]] &&
+ events[$history[$histno]]=$histno
+ (( histno += inc ))
+ done
+ events=( "${(@Oa)${(@kv)events}}" )
+ else
+ while (( $#events[@] < max_lines && 0 < histno && histno < HISTNO )); do
+ [[ -v history[$histno] ]] &&
+ events[$histno]="$history[$histno]"
+ (( histno += inc ))
+ done
+ fi
+ _comp_colors=( '(history-lines)=[[:space:]]#(#b)(<->) *=0=2' "$_comp_colors[@]" )
+ else
+ local -PaU queries=() err=( '(#ia'{0..$(( $#words[CURRENT] ))}')' )
+ local -P query lbuffer= rbuffer=
+ if [[ $WIDGET == (|*-)search(|-*) ]]; then
+ queries=( \*$^err${(j:*:)${(0)words[CURRENT]}}\* )
+ else
+ lbuffer="${(j.[[:blank:]]##.)${(@b)words[1,CURRENT-1]}}"
+ rbuffer="${(j.[[:blank:]]##.)${(@b)words[CURRENT+1,-1]}}"
+ [[ -n $lbuffer ]] &&
+ lbuffer="${lbuffer}[[:blank:]]##"
+ [[ -n $rbuffer ]] &&
+ rbuffer="[[:blank:]]##${rbuffer}"
+ lbuffer="$lbuffer${(b)QIPREFIX}"
+ rbuffer="${(b)QISUFFIX}$rbuffer"
+ queries=( $lbuffer\*\($^err${words[CURRENT]}\)\*$rbuffer )
+ fi
+ if [[ -o histfindnodups ]]; then
+ local -Pa numbers=()
+ for query in $queries[@]; do
+ numbers=( "${(@k)history[(R)$~query]}" )
+ (( $#numbers[@] > 1 )) &&
+ break
+ done
+ local -Pa lines=( "${(@v)history[(I)(${(~j:|:)numbers})]}" )
+ if [[ $curcontext != *-forward:* ]]; then
+ numbers=( "${(@Oa)numbers}" )
+ lines=( "${(@Oa)lines}" )
+ fi
+ events=( "${(@)lines:^numbers}" )
+ events=( "${(@Oa)${(@kv)events}}" )
+ else
+ for query in $queries[@]; do
+ events=( "${(@kv)history[(R)$~query]}" )
+ (( $#events[@] > 1 )) &&
+ break
+ done
+ fi
+ _comp_colors=(
+ "(history-lines)=[[:space:]]#(#b)(<->) *(${${query#$lbuffer\*}%\*$rbuffer})*=0=2=30;103"
+ "$_comp_colors[@]"
+ )
+ fi
+
+ (( $#events[@] )) ||
+ return
+
+ local -a displays=()
+ printf -v displays "%s:%s" "${(@kv)events}"
+ displays=( "$displays[@]" )
+
+ local -Pi diff=$(( $#displays[@] - max_lines ))
+ local -P suf=
+ if [[ $WIDGET == (|*-)search(|-*) ]]; then
+ displays=( ${(@n)displays} )
+ (( diff > 0 )) &&
+ shift "$diff" displays
+ suf=';'
+ else
+ if [[ $curcontext == *-forward:* ]]; then
+ displays=( ${(@n)displays} )
+ else
+ displays=( ${(@On)displays} )
+ fi
+ (( diff > 0 )) &&
+ shift -p "$diff" displays
+ suf=' '
+ fi
+
+ local -a matches=( "${displays[@]##[[:blank:]]#<->:}" )
+ [[ $WIDGET != (|*-)search(|-*) ]] &&
+ matches=( "${(@)${(@)matches[@]##$~lbuffer}%%$~rbuffer}" )
+
+ local -Pa match=() mbegin=() mend=()
+ displays=(
+ "${(@r:COLUMNS-1:)displays[@]/%(#b)(<->):(*)/${(l:$#HISTNO:)match[1]} ${(V)${(Z+c+)match[2]}}}"
+ )
+
+ local -a expl=()
+ local _comp_no_ignore=1
+ _description -2V "$tag" expl 'history line'
+ builtin compadd "$expl[@]" -S "$suf" -R _autocomplete.history_lines.suffix \
+ -QU -ld displays -a matches
+}
+# functions -T _autocomplete.history_lines
+
+_autocomplete.history_lines.suffix() {
+ case $WIDGET in
+ ( (|.|*-)(hist(|ory)|search|delete|kill)(|-*) )
+ ;;
+ ( (|.)(self-insert(|-*)|magic-space) )
+ case $KEYS[-1] in
+ ( [$ZLE_SPACE_SUFFIX_CHARS$ZLE_REMOVE_SUFFIX_CHARS] )
+ LBUFFER=$LBUFFER[1,-1-$1]
+ ;|
+ ( [$ZLE_SPACE_SUFFIX_CHARS] )
+ LBUFFER+=' '
+ ;;
+ esac
+ ;;
+ ( * )
+ LBUFFER=$LBUFFER[1,-1-$1]
+ ;;
+ esac
+}
+
+_autocomplete.history_lines "$@"
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.is_glob b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.is_glob
new file mode 100644
index 00000000..d2395253
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.is_glob
@@ -0,0 +1,12 @@
+#autoload
+zmodload -F zsh/parameter p:patchars
+
+local word=$PREFIX$SUFFIX
+if [[ $word == ${~${(q)word}} &&
+ $word == (*(${(~j:|:)patchars[@]:#\~}})*|?*(${(~j:|:)patchars})*) ]]; then
+ reply=( yes )
+ true
+else
+ reply=( no )
+ false
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.recent_paths b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.recent_paths
new file mode 100644
index 00000000..1ffde001
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.recent_paths
@@ -0,0 +1,56 @@
+#autoload
+zmodload -F zsh/parameter p:functions
+
+_autocomplete.recent_paths() {
+ (( compstate[nmatches] )) &&
+ return 1
+
+ local -PaU files=()
+ local -Pi ret=1
+ local -P tag=
+ for tag in directories files; do
+ if [[ -v functions[_autocomplete.recent_$tag] &&
+ $_comp_tags == (|* )(|(all|local)-)$tag(| *) ]] &&
+ _autocomplete.recent_$tag "$PREFIX$SUFFIX"; then
+ files=( "$reply[@]" )
+ _description -V recent-$tag expl 'recent directory'
+ .autocomplete.recent_paths.add $files[@] &&
+ ret=0
+ fi
+ done
+
+ return ret
+}
+
+.autocomplete.recent_paths.add() {
+ local -a displ=() matches=( "$@" )
+ builtin compadd "$expl[@]" -D matches -- "$@:t"
+ displ=( "${(@D)matches}" )
+ zformat -a displ '' $^displ':'
+
+ .autocomplete.recent_paths.trim
+
+ local -Pi ret=1
+
+ # Work around `setopt autonamedirs` by not assigning absolute paths to scalars.
+ while (( $#matches )); do
+ (( $#displ[1] > 1 )) &&
+ compadd "$expl[@]" -d displ -P "${${(D)matches[1]:h}%/}/" -fW "${${matches[1]:h}%/}/" \
+ -- "$matches[1]:t" &&
+ ret=0
+ shift -- displ matches
+ done
+
+ return ret
+}
+
+# Workaround to prevent the prompt from jumping
+.autocomplete.recent_paths.trim() {
+ local -P total="${(j:/ :)displ}/ "
+ while (( $#total > COLUMNS )); do
+ shift -p -- displ matches
+ total="${(j:/ :)displ}/ "
+ done
+}
+
+_autocomplete.recent_paths "$@"
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.requoted b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.requoted
new file mode 100644
index 00000000..e17933ec
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.requoted
@@ -0,0 +1,22 @@
+#autoload
+
+local -P tag=requoted
+_tags $tag
+_tags && _requested $tag ||
+ return 1
+
+(( compstate[nmatches] > 1 )) &&
+ return 1
+_autocomplete.is_glob &&
+ return 1
+[[ $_completer == expand ]] ||
+ return 1
+
+local -P match=${(Q)compstate[unambiguous]}
+
+[[ $match == ($words[CURRENT]|$compstate[unambiguous]) ]] &&
+ return 1
+
+local -a expl display=( "$match" )
+_description $tag expl 'human-readable'
+compadd "$expl[@]" -qS ' ' -QU -d display - ${(q+)match}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.unambiguous b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.unambiguous
new file mode 100644
index 00000000..f258a39c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/completion/_autocomplete.unambiguous
@@ -0,0 +1,35 @@
+#autoload
+# setopt localoptions verbose xtrace
+
+[[ -v _autocomplete__partial_list ]] &&
+ return 1
+
+(( compstate[nmatches] > 1 )) ||
+ return 1
+[[ $curcontext == history-*:* ||
+ $IPREFIX$PREFIX$SUFFIX$ISUFFIX == *${compstate[unambiguous]:#?}* ]] &&
+ return 1
+
+local -P tag=unambiguous
+_tags $tag
+_tags ||
+ return
+_requested $tag ||
+ return
+
+typeset -gH _autocomplete__unambiguous="$compstate[unambiguous]"
+
+if builtin zstyle -t :autocomplete:tab: insert-unambiguous; then
+ local -Pi nxt= prv=1
+ local -P subs= cols=
+ for nxt in ${(s.:.)compstate[unambiguous_positions]}; do
+ subs+='('${(b)compstate[unambiguous][prv,nxt]}')*'
+ cols+='=30;103' # black foreground, bright yellow background
+ (( prv = ++nxt ))
+ done
+ ZLS_COLORS="=(#bi)*$subs=$cols:$ZLS_COLORS"
+ return 1
+fi
+
+builtin compadd -J "$tag" \
+ -x $'%{\e[0;2m%}common substring:%b %F{0}%K{11}'"$compstate[unambiguous]%f%k"
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.complete-word.completion-widget b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.complete-word.completion-widget
new file mode 100644
index 00000000..9d14478b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.complete-word.completion-widget
@@ -0,0 +1,27 @@
+#!/bin/zsh
+zmodload -F zsh/terminfo p:terminfo
+
+local -P key_name=
+case $KEYS in
+ ( $'\t' ) key_name=tab ;;
+ ( $terminfo[kcbt] ) key_name=shift-tab ;;
+esac
+
+() {
+ local -a match=() mbegin=() mend=() # `zstyle` for some reason assigns these.
+ local +h curcontext=${curcontext:-${WIDGET}:::}
+ local +h -a comppostfuncs=( .autocomplete.complete-word.post "$comppostfuncs[@]" )
+
+ if [[ -z $compstate[old_list] ]] || [[ $WIDGET == *menu-* && -v _autocomplete__partial_list ]] ||
+ ( builtin zstyle -t ":autocomplete:${key_name}:" insert-unambiguous &&
+ [[ -n $_autocomplete__unambiguous ]] ); then
+ _main_complete
+ else
+ compstate[old_list]=keep
+ [[ $key_name == shift-tab && $_lastcomp[tags] == *all-matches ]] &&
+ compstate[insert]=all
+ _main_complete -
+ fi
+}
+[[ _lastcomp[nmatches] -gt 0 && -n $compstate[insert] ]] &&
+ unset curcontext
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.complete-word.post b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.complete-word.post
new file mode 100644
index 00000000..71fa9fc9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.complete-word.post
@@ -0,0 +1,68 @@
+#autoload
+local -a match=() mbegin=() mend=() # `zstyle` for some reason assigns these.
+
+unset MENUSELECT 'compstate[list]'
+compstate[insert]=
+
+local -P key_name=
+case $KEYS in
+ ( $'\t' ) key_name=tab ;;
+ ( $terminfo[kcbt] ) key_name=shift-tab ;;
+esac
+local widget_style=
+builtin zstyle -s :autocomplete:${key_name}: widget-style widget_style ||
+ widget_style=menu-select
+
+if [[ -n $_autocomplete__unambiguous ]] &&
+ builtin zstyle -t ":autocomplete:${key_name}:" insert-unambiguous; then
+ [[ $widget_style == (|*-)menu-* ]] &&
+ compstate[insert]='automenu-'
+ compstate[insert]+=unambiguous
+ unset _autocomplete__unambiguous
+ return
+fi
+
+local -Pi nmatches=0
+if [[ $compstate[old_list] == keep ]]; then
+ nmatches=$_lastcomp[nmatches]
+else
+ nmatches=$compstate[nmatches]
+fi
+
+if (( nmatches > 1 )); then
+ if [[ $widget_style == (|*-)menu-select ]]; then
+ typeset -gHi MENUSELECT=0
+ compstate[insert]='menu:'
+
+ # Determine which terminal line we're on (for async completion).
+ typeset -gHi _autocomplete__buffer_start_line=$((
+ max( min( _autocomplete__buffer_start_line, LINES - compstate[list_lines] ), BUFFERLINES )
+ ))
+
+ elif [[ $compstate[old_list] != keep && $_lastcomp[insert] != (|*-)unambiguous ]]; then
+ compstate[list]='list force'
+ return
+ elif [[ $widget_style == (|*-)menu-complete ]]; then
+ compstate[insert]='menu:'
+ fi
+fi
+
+if [[ $key_name == shift-tab ]]; then
+ compstate[insert]+='0'
+else
+ compstate[insert]+='1'
+fi
+
+if [[ $RBUFFER != [[:space:]]* ]]; then
+ local -a spacetags=()
+ builtin zstyle -a :autocomplete: add-space spacetags ||
+ spacetags=( executables aliases functions builtins reserved-words commands )
+ local -Pa comptags=()
+ if [[ $compstate[old_list] == keep ]]; then
+ comptags=( $=_lastcomp[tags] )
+ else
+ comptags=( $=_comp_tags )
+ fi
+ [[ -n ${comptags:*spacetags} ]] &&
+ compstate[insert]+=' '
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.down-line-or-select.zle-widget b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.down-line-or-select.zle-widget
new file mode 100644
index 00000000..a0c603b3
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.down-line-or-select.zle-widget
@@ -0,0 +1,7 @@
+#!/bin/zsh
+
+if [[ $RBUFFER == *$'\n'* ]]; then
+ builtin zle down-line
+else
+ builtin zle menu-select -w
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.history-search.completion-widget b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.history-search.completion-widget
new file mode 100644
index 00000000..509b82d9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.history-search.completion-widget
@@ -0,0 +1,19 @@
+#!/bin/zsh
+local 0=${(%):-%N}
+
+$0() {
+ typeset -gH curcontext=${WIDGET}:::
+
+ local +h -a comppostfuncs=( ${(%):-%N}.post "$comppostfuncs[@]" )
+ compstate[old_list]=
+ _main_complete _autocomplete.history_lines
+
+ unset curcontext
+ (( _lastcomp[nmatches] ))
+}
+
+$0.post() {
+ compstate[insert]='menu:0'
+}
+
+$0 "$@"
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.history-search.zle-widget b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.history-search.zle-widget
new file mode 100644
index 00000000..acf23b8e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.history-search.zle-widget
@@ -0,0 +1,47 @@
+#!/bin/zsh
+local 0=${(%):-%N}
+builtin zle -C ${0}.context list-choices ${0}.context
+
+${0}.context() {
+ # Inside a completion widget, the current quote level is removed. So, we should not include
+ # $QIPREFIX/$QISUFFIX in our pattern or it won't match.
+ lcontext=${LBUFFER%${(~j:*:)words[1,CURRENT-1]}*$IPREFIX$PREFIX}
+ lcontext+=${lcontext:+ }${(pj:\0:)${(@b)words}}
+ rcontext=${RBUFFER#$SUFFIX$ISUFFIX*${(~j:*:)words[CURRENT+1,-1]}}
+}
+
+${0}() {
+ local -P lbuffer="$LBUFFER" rbuffer="$RBUFFER"
+ local -P keymap_menuselect="$( builtin bindkey -M menuselect -L )"
+ {
+ builtin bindkey -M menuselect -s \
+ '^R' '^_^_^R' \
+ '^S' '^_^_^S'
+ builtin bindkey -M menuselect \
+ '\e[D' .backward-char \
+ '\eOD' .backward-char \
+ '\e[C' .forward-char \
+ '\eOC' .forward-char
+
+ setopt $_autocomplete__comp_opts[@] $_autocomplete__ctxt_opts[@]
+
+ local lcontext= rcontext=
+ builtin zle ${(%):-%N}.context
+ LBUFFER="$lcontext"
+ RBUFFER="$rcontext"
+
+ [[ -o sharehistory ]] &&
+ fc -RI # Get new history events from file.
+ builtin zle _history_search
+
+ } always {
+ builtin bindkey -M menuselect -r '^R' '^S' '\e'{\[,O}{D,C}
+ eval "$keymap_menuselect"
+ if [[ $BUFFER == $lcontext$rcontext ]] then
+ LBUFFER="$lbuffer"
+ RBUFFER="$rbuffer"
+ fi
+ }
+}
+
+$0 "$@"
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.list-expand.completion-widget b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.list-expand.completion-widget
new file mode 100644
index 00000000..f37c1642
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.list-expand.completion-widget
@@ -0,0 +1,29 @@
+#!/bin/zsh
+local 0=${(%):-%N}
+
+$0() {
+ local 0=${(%):-%N}
+ local +h curcontext=${curcontext:-${WIDGET}:::}
+
+ compstate[old_list]=
+ local +h -a comppostfuncs=( $0.post "$comppostfuncs[@]" )
+ _main_complete
+ (( _lastcomp[nmatches] ))
+}
+
+$0.post() {
+ # Determine which terminal line we're on (for async completion).
+ typeset -gHi _autocomplete__buffer_start_line=$((
+ max( min( _autocomplete__buffer_start_line, LINES - compstate[list_lines] ), BUFFERLINES )
+ ))
+
+ if (( compstate[list_lines] > LINES - BUFFERLINES )); then
+ compstate[insert]=menu
+ MENUSELECT=0
+ else
+ compstate[insert]=
+ unset MENUSELECT
+ fi
+}
+
+$0 "$@"
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.up-line-or-search.zle-widget b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.up-line-or-search.zle-widget
new file mode 100644
index 00000000..9bdc641d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/functions/widget/.autocomplete.up-line-or-search.zle-widget
@@ -0,0 +1,7 @@
+#!/bin/zsh
+
+if [[ $LBUFFER == *$'\n'* ]]; then
+ builtin zle up-line
+else
+ builtin zle history-search -w
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/run-tests.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/run-tests.zsh
new file mode 100755
index 00000000..8a18ca40
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/run-tests.zsh
@@ -0,0 +1,3 @@
+#!/bin/zsh -f
+print $VENDOR $OSTYPE =zsh $ZSH_VERSION $ZSH_PATCHLEVEL =clitest
+FPATH=$FPATH zsh -f =clitest --list-run --progress dot --prompt '%' -- ${0:h}/.clitest/*.md
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.__init__ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.__init__
new file mode 100644
index 00000000..fc2b578e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.__init__
@@ -0,0 +1,125 @@
+#!/bin/zsh
+zmodload -Fa zsh/files b:zf_mkdir b:zf_rm
+zmodload -F zsh/parameter p:functions
+zmodload -F zsh/system p:sysparams
+zmodload -F zsh/zleparameter p:widgets
+zmodload -Fa zsh/zutil b:zstyle
+builtin autoload +X -Uz add-zsh-hook zmathfunc
+zmathfunc
+
+typeset -gHa _autocomplete__func_opts=(
+ localoptions extendedglob clobber
+ NO_aliases localloops pipefail NO_shortloops NO_unset warncreateglobal
+)
+setopt $_autocomplete__func_opts[@]
+
+typeset -gHa _autocomplete__comp_opts=( localoptions NO_banghist NO_completeinword )
+typeset -gHa _autocomplete__ctxt_opts=( completealiases completeinword )
+
+.autocomplete.__init__.precmd() {
+ # Workaround for https://github.com/zdharma/zinit/issues/366
+ # NOTE: Needs to come before _everything_ else!
+ [[ -v functions[.zinit-shade-off] ]] &&
+ .zinit-shade-off "${___mode:-load}"
+ [[ -v functions[.zinit-tmp-subst-off] ]] &&
+ .zinit-tmp-subst-off "${___mode:-load}"
+
+ () {
+ emulate -L zsh
+ setopt $_autocomplete__func_opts[@]
+
+ add-zsh-hook -d precmd .autocomplete.__init__.precmd
+ unfunction .autocomplete.__init__.precmd
+
+ # Workaround for https://www.zsh.org/mla/workers/2021/msg01310.html
+ if builtin zstyle -L zle-hook types > /dev/null; then
+ local -P hook=
+ for hook in \
+ zle-{isearch-{exit,update},line-{pre-redraw,init,finish},history-line-set,keymap-select}
+ do
+ [[ -v widgets[$hook] &&
+ $widgets[$hook] == user:_zsh_highlight_widget_orig-s*-r<->-$hook ]] &&
+ builtin zle -N $hook azhw:$hook
+ done
+ fi
+ }
+
+ local -P mod=
+ for mod in compinit config widget key-binding recent-dirs async; do
+ mod=.autocomplete.$mod.precmd
+ if [[ -v functions[$mod] ]]; then
+ $mod
+ unfunction $mod
+ fi
+ done
+
+ true
+}
+
+local -P basedir=${${(%):-%x}:P:h:h}
+if ! [[ -n $basedir && -d $basedir ]]; then
+ print -u2 -- 'zsh-autocomplete: Failed to find base dir. Aborting.'
+ return 66
+fi
+hash -d zsh-autocomplete=$basedir
+typeset -gU FPATH fpath=( ~zsh-autocomplete/functions/completion $fpath[@] )
+
+local -Pa funcs=(
+ ~zsh-autocomplete/functions{,/widget}/.autocomplete.*~*.zwc(N-.:P)
+)
+if ! (( $#funcs )); then
+ print -u2 -- 'zsh-autocomplete: Failed to find functions. Aborting.'
+ return 66
+fi
+unfunction $funcs[@]:t 2> /dev/null
+builtin autoload -UWz $funcs[@]
+
+local -P xdg_data_home=${XDG_DATA_HOME:-$HOME/.local/share}
+
+local -P zsh_data_dir=$xdg_data_home/zsh
+[[ -d $zsh_data_dir ]] ||
+ zf_mkdir -pm 0700 $zsh_data_dir
+
+local -P logdir=$xdg_data_home/zsh-autocomplete/log
+[[ -d $logdir ]] ||
+ zf_mkdir -p -- $logdir
+local -Pa older_than_a_week=( $logdir/*(Nmd+7) )
+(( $#older_than_a_week[@] )) &&
+ zf_rm -f -- $older_than_a_week[@]
+local -P date=${(%):-%D{%F}}
+typeset -gH _autocomplete__log=$logdir/$date.log
+typeset -gH _autocomplete__log_async=$logdir/$date.async.log
+typeset -gH _autocomplete__log_pty=$logdir/$date.pty.log
+
+typeset -gH _autocomplete__prev=' ' _autocomplete__next=$'\n# %e. %N'
+typeset -gH _autocomplete__time=$' [%D{%T.%.}]\n'
+typeset -gH _autocomplete__ps4=\
+'${${_autocomplete__prev:#${(%)_autocomplete__next}}:+'\
+'${_autocomplete__prev::=${(%)_autocomplete__next}}${(%)_autocomplete__time}}'\
+$'%I%(?,\t, ->%?\t)%(1_,%_ ,)'
+
+local -P zsh_cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}/zsh
+[[ -d $zsh_cache_dir ]] ||
+ zf_mkdir -pm 0700 $zsh_cache_dir
+
+local -P mod=
+for mod in compinit config widget key-binding recent-dirs async; do
+ if builtin zstyle -T ":autocomplete:$mod" enabled; then
+ builtin autoload +X -Uz ~zsh-autocomplete/scripts/.autocomplete.$mod
+ {
+ .autocomplete.$mod "$@"
+ } always {
+ unfunction .autocomplete.$mod
+ }
+ fi
+done
+
+add-zsh-hook precmd .autocomplete.__init__.precmd
+
+# Ensure our precmd runs before zsh-autosuggestions'.
+[[ -v precmd_functions && $precmd_functions[(I)_zsh_autosuggest_start] != 0 ]] &&
+ typeset -gHaU precmd_functions=(
+ ${precmd_functions[@]:#_zsh_autosuggest_start} _zsh_autosuggest_start
+ )
+
+true
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.async b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.async
new file mode 100644
index 00000000..2965498c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.async
@@ -0,0 +1,603 @@
+#!/bin/zsh
+zmodload -F zsh/zpty b:zpty
+zmodload -F zsh/parameter p:funcstack p:functions p:parameters
+zmodload -F zsh/system b:sysopen p:sysparams
+zmodload -F zsh/zselect b:zselect
+zmodload -F zsh/terminfo b:echoti p:terminfo
+zmodload -F zsh/zutil b:zparseopts
+builtin autoload -RUz add-zle-hook-widget
+
+typeset -gHi _autocomplete__buffer_start_line=1
+typeset -g ZSH_AUTOSUGGEST_USE_ASYNC=yes
+local -Pa log_functions=()
+
+builtin zle -N history-incremental-search-backward .autocomplete.async.history-incremental-search
+builtin zle -N history-incremental-search-forward .autocomplete.async.history-incremental-search
+
+.autocomplete.async.precmd() {
+ local -PF delay=
+ builtin zstyle -s :autocomplete: min-delay delay
+ (( delay += 0.1 ))
+ typeset -gHF _autocomplete__async_avg_duration=$delay
+
+ # Start names with `.` to avoid getting wrapped by syntax highlighting.
+ builtin zle -N .autocomplete.async.pty.zle-widget
+ builtin zle -C .autocomplete.async.pty.completion-widget list-choices \
+ .autocomplete.async.pty.completion-widget
+ builtin zle -N .autocomplete.async.complete.fd-widget
+ builtin zle -C ._list_choices list-choices .autocomplete.async.list-choices.completion-widget
+
+ if [[ -v functions[_zsh_highlight_call_widget] ]]; then
+ _zsh_highlight_call_widget() {
+ .autocomplete.zle-flags $WIDGET
+ builtin zle "$@"
+ }
+ fi
+
+ if [[ -v functions[_zsh_autosuggest_highlight_apply] ]]; then
+ local -P action=
+ for action in clear modify fetch accept partial_accept execute enable disable toggle; do
+ # Set flags according to widget name.
+ eval "_zsh_autosuggest_widget_$action() {
+ .autocomplete.zle-flags \$WIDGET
+ _zsh_autosuggest_$action \"\$@\"
+ }"
+ done
+ _zsh_autosuggest_widget_suggest() {
+ .autocomplete.zle-flags # Maintain previously set flags.
+ _zsh_autosuggest_suggest "$@"
+ }
+ fi
+
+ .autocomplete.patch _message
+
+ add-zle-hook-widget line-init .autocomplete.async.read-cursor-position
+ add-zle-hook-widget line-init .autocomplete.async.reset-context
+ add-zle-hook-widget line-init .autocomplete.async.complete
+
+ add-zle-hook-widget line-pre-redraw .autocomplete.async.complete
+ add-zle-hook-widget line-finish .autocomplete.async.clear
+ add-zle-hook-widget isearch-update .autocomplete.async.isearch-update
+ add-zle-hook-widget isearch-exit .autocomplete.async.isearch-exit
+
+ add-zsh-hook zshexit .autocomplete.async.stop
+}
+
+.autocomplete.async.read-cursor-position() {
+ emulate -L zsh
+ # Cannot set strict shell options here, because other programs' async
+ # callbacks can interrupt the code and then get executed in the same context.
+ # See https://github.com/marlonrichert/zsh-autocomplete/issues/342
+
+ (( KEYS_QUEUED_COUNT || PENDING )) &&
+ return
+
+ # $MC_SID is set when we're in a subshell started by Midnight Commander.
+ # See https://github.com/marlonrichert/zsh-autocomplete/issues/269
+ if [[ -v MC_SID || ! ( -v terminfo[u6] && -v terminfo[u7] ) ]]; then
+ local -i max_lines=
+ builtin zstyle -s ":autocomplete:${curcontext}:" list-lines max_lines ||
+ max_lines=16
+ typeset -gHi _autocomplete__buffer_start_line=$(( min( max( LINES - max_lines, 1 ), LINES ) ))
+ return 0
+ fi
+
+ # Cursor position report (u6) always contains two %d markers.
+ local -Pa CPR=( "${(s:%d:)$( echoti u6 )}" )
+
+ # If there is a %i before the first %d, then decrement both %d values by 1.
+ local -Pi i=${${${(M)CPR[1]%'%i'}:+1}:-0}
+ CPR[1]=${CPR[1]%'%i'}
+
+ local REPLY=
+ local -P Y=
+ echoti u7 # Send cursor position request.
+
+ # Parse the cursor position report.
+ read -rsk $#CPR[1] # Discard the preamble.
+ while [[ $REPLY != $CPR[2] ]]; do
+ read -rsk
+ Y+=$REPLY
+ done
+ Y="${Y%$CPR[2]}" # Discard the separator.
+ Y=${(M)Y%%<->} # Keep trailing digits only (to work around input pollution).
+
+ # Flush the rest.
+ while [[ $REPLY != $CPR[3] ]]; do
+ read -rsk
+ done
+
+ typeset -gHi _autocomplete__buffer_start_line=$(( min( max( Y - i, 1 ), LINES ) ))
+}
+
+.autocomplete.async.history-incremental-search() {
+ if [[ $curcontext == $WIDGET* ]]; then
+ unset curcontext
+ else
+ typeset -gH curcontext=${WIDGET}:::
+ fi
+ [[ -o sharehistory ]] &&
+ fc -RI # Get new history events from file.
+ .autocomplete.async.start
+}
+
+.autocomplete.async.reset-context() {
+ local context
+ builtin zstyle -s :autocomplete: default-context context
+ typeset -gH curcontext=$context
+ return 0
+}
+
+.autocomplete.async.isearch-update() {
+ typeset -gHi _autocomplete__isearch=1
+}
+
+.autocomplete.async.isearch-exit() {
+ .autocomplete.zle-flags $LASTWIDGET
+ unset _autocomplete__isearch
+}
+
+.autocomplete.async.complete() {
+ .autocomplete.zle-flags $LASTWIDGET
+
+ (( KEYS_QUEUED_COUNT || PENDING )) &&
+ return
+
+ [[ -v functions[_zsh_highlight] ]] &&
+ _zsh_highlight
+ typeset -gH _autocomplete__highlight=( $region_highlight[@] )
+ [[ -v functions[_zsh_autosuggest_highlight_apply] ]] &&
+ _zsh_autosuggest_highlight_apply
+
+ [[ $LASTWIDGET == .autocomplete.async.complete.fd-widget ]] &&
+ return
+
+ .autocomplete.async.stop
+
+ if (( REGION_ACTIVE )) ||
+ [[ -v _autocomplete__isearch && $LASTWIDGET == *(incremental|isearch)* ]]; then
+ builtin zle -Rc
+ return 0
+ fi
+
+ [[ $LASTWIDGET ==
+ (_complete_help|list-expand|(|.)(describe-key-briefly|what-cursor-position|where-is)) ]] &&
+ return
+
+ [[ $_lastcomp[insert] == *unambiguous ]] &&
+ builtin zle .auto-suffix-retain # Make the cursor stay in the right place.
+
+ .autocomplete.async.start
+ return 0
+}
+
+.autocomplete.async.clear() {
+ builtin zle -Rc
+ unset _autocomplete__isearch
+ .autocomplete.async.stop
+ .autocomplete.async.reset-context
+ return 0
+}
+
+.autocomplete.async.stop() {
+ local fd=$_autocomplete__async_complete_fd
+ unset _autocomplete__async_complete_fd
+ unset _autocomplete__mesg _autocomplete__comp_mesg _autocomplete__words _autocomplete__current
+ if [[ $fd == <-> ]]; then
+ builtin zle -F $fd 2> /dev/null
+ exec {fd}<&-
+ fi
+}
+
+.autocomplete.async.start() {
+ local fd=
+ sysopen -r -o cloexec -u fd <(
+ typeset -F SECONDS=0
+ setopt promptsubst
+ PS4=$_autocomplete__ps4
+ .autocomplete.async.start.inner
+ )
+ builtin zle -Fw "$fd" .autocomplete.async.complete.fd-widget
+ typeset -gH _autocomplete__async_complete_fd=$fd
+
+ # There's a weird bug in Zsh < 5.8, where ^C stops working unless we force a fork.
+ # See https://github.com/zsh-users/zsh-autosuggestions/issues/364
+ command true
+}
+
+.autocomplete.async.start.inner() {
+ {
+ local -F min_delay=
+ builtin zstyle -s :autocomplete: min-delay min_delay ||
+ min_delay=0.05
+
+ # Directly using $(( [#10] 100 * max( 0, min_delay - SECONDS ) )) leads to 0
+ # in Zsh >= 5.9, as the result of the max call is converted to an integer.
+ # See https://github.com/marlonrichert/zsh-autocomplete/issues/441
+ local -i timeout=$(( 100 * max( 0, min_delay - SECONDS ) ))
+ zselect -t $timeout
+
+ local -P hooks=( chpwd periodic precmd preexec zshaddhistory zshexit )
+ builtin unset ${^hooks}_functions &> /dev/null
+ $hooks[@] () { : }
+
+ local -P hook=
+ for hook in \
+ zle-{isearch-{exit,update},line-{pre-redraw,init,finish},history-line-set,keymap-select}
+ do
+ builtin zle -N $hook .autocomplete.async.pty.no-op
+ done
+ {
+ local REPLY=
+ zpty AUTOCOMPLETE .autocomplete.async.pty
+ local -Pi fd=$REPLY
+
+ zpty -w AUTOCOMPLETE $'\t'
+
+ local header=
+ zpty -r AUTOCOMPLETE header $'*\C-B'
+
+ local -a reply=()
+ local text=
+
+ # Directly using $(( [#10] 100 * max( 0, 100 * _autocomplete__async_avg_duration - SECONDS ) ) ))
+ # leads to 0 in Zsh >= 5.9, as the result of the max call is converted to an integer.
+ # See https://github.com/marlonrichert/zsh-autocomplete/issues/441
+ local -i timeout=$(( 100 * max( 0, 100 * _autocomplete__async_avg_duration - SECONDS ) ))
+ zselect -rt $timeout "$fd" &&
+ zpty -r AUTOCOMPLETE text $'*\C-C'
+ } always {
+ zpty -d AUTOCOMPLETE
+ }
+ } always {
+ # Always produce output, so we always reach the callback, so we can close the fd and unset
+ # $_autocomplete__async_complete_fd (if necessary).
+ print -rNC1 -- "$SECONDS" "${text%$'\0\C-C'}"
+ }
+} 2>>| $_autocomplete__log_async
+log_functions+=( .autocomplete.async.start.inner )
+
+.autocomplete.async.pty() {
+ typeset -gH _autocomplete__lbuffer="$LBUFFER" _autocomplete__rbuffer="$RBUFFER"
+
+ builtin bindkey $'\t' .autocomplete.async.pty.zle-widget
+ local __tmp__=
+ builtin vared __tmp__
+} 2>>| $_autocomplete__log_pty
+log_functions+=( .autocomplete.async.pty )
+
+.autocomplete.async.pty.no-op() {
+ :
+}
+
+.autocomplete.async.pty.zle-widget() {
+ .autocomplete.async.pty.zle-widget.inner "$@"
+}
+
+.autocomplete.async.pty.zle-widget.inner() {
+ # The completion widget sometimes returns without calling its function. So, we need to print all
+ # our control characters here, to ensure we don't end up waiting endlessly to read them.
+ {
+ print -n -- '\C-B'
+ LBUFFER=$_autocomplete__lbuffer
+ RBUFFER=$_autocomplete__rbuffer
+
+ setopt $_autocomplete__comp_opts[@]
+ [[ -n $curcontext ]] &&
+ setopt $_autocomplete__ctxt_opts[@]
+ builtin zle .autocomplete.async.pty.completion-widget -w 2> /dev/null
+ } always {
+ print -rNC1 -- \
+ "$_autocomplete__list_lines" "$_autocomplete__mesg" "$_autocomplete__comp_mesg[@]" $'\C-C'
+ builtin kill $sysparams[pid]
+ }
+} 2>>| $_autocomplete__log_pty
+log_functions+=( .autocomplete.async.pty.zle-widget.inner )
+
+.autocomplete.async.pty.completion-widget() {
+ .autocomplete.async.pty.completion-widget.inner "$@"
+}
+
+.autocomplete.async.pty.completion-widget.inner() {
+ if ! .autocomplete.async.sufficient-input; then
+ typeset -gHi _autocomplete__list_lines=0
+ return
+ fi
+ if .autocomplete.async.same-state; then
+ typeset -gHi _autocomplete__list_lines=$_lastcomp[list_lines]
+ return
+ fi
+
+ unset _autocomplete__mesg _autocomplete__comp_mesg
+ {
+ local curcontext=${curcontext:-list-choices:::}
+ unset 'compstate[vared]'
+
+ _message() {
+ compadd() {
+ typeset -gHa _autocomplete__comp_mesg=( "$@" )
+ builtin compadd "$@"
+ }
+ zformat() {
+ builtin zformat "$@"
+ typeset -gHa _autocomplete__comp_mesg=( "$gopt[@]" -x "$format" )
+ }
+ .autocomplete._message "$@"
+ unfunction zformat
+ functions[compadd]="$functions[.autocomplete.compadd]"
+ }
+
+ local +h -a comppostfuncs=( .autocomplete.async.pty.message )
+ _main_complete
+ } always {
+ typeset -gHi _autocomplete__list_lines=$compstate[list_lines]
+ }
+} 2>>| $_autocomplete__log_pty
+log_functions+=( .autocomplete.async.pty.completion-widget.inner )
+
+.autocomplete.async.pty.message() {
+ typeset -gH _autocomplete__mesg=$mesg
+ return 0
+}
+
+.autocomplete.async.complete.fd-widget() {
+ setopt promptsubst
+ local +h PS4=$_autocomplete__ps4
+ .autocomplete.async.complete.fd-widget.inner "$@"
+}
+
+.autocomplete.async.complete.fd-widget.inner() {
+ local -i fd=$1
+ {
+ builtin zle -F $fd # Unhook ourselves immediately, so we don't get called more than once.
+
+ # Ensure our input will not be stopped.
+ unset _autocomplete__async_complete_fd
+
+ .autocomplete.zle-flags ||
+ return 0
+
+ local -a reply=()
+ IFS=$'\0' read -rAu $fd
+ shift -p reply
+ } always {
+ exec {fd}<&-
+ }
+
+ unset _autocomplete__mesg _autocomplete__comp_mesg
+
+ # If a widget can't be called, zle always returns true.
+ # Thus, we return false on purpose, so we can check if our widget got called.
+ setopt $_autocomplete__comp_opts[@]
+ [[ -n $curcontext ]] &&
+ setopt $_autocomplete__ctxt_opts[@]
+ if ! builtin zle ._list_choices -w "$reply[@]" 2>>| $_autocomplete__log; then
+ region_highlight=( "$_autocomplete__highlight[@]" )
+ [[ -v functions[_zsh_autosuggest_highlight_apply] ]] &&
+ _zsh_autosuggest_highlight_apply
+
+ # Refresh if and only if our widget got called. Otherwise, Zsh will crash (eventually).
+ builtin zle -R
+ else
+ .autocomplete.async.stop
+ fi
+ return 0
+} 2>>| $_autocomplete__log
+log_functions+=( .autocomplete.async.complete.fd-widget.inner )
+
+.autocomplete.async.sufficient-input() {
+ # Don't check the input if we're not doing normal autocompletion.
+ [[ -n $curcontext ]] &&
+ return
+
+ local min_input=
+ builtin zstyle -s :autocomplete:list-choices min-input min_input ||
+ min_input=0
+ local ignored=
+ builtin zstyle -s :autocomplete:list-choices ignored-input ignored
+ if (( ${#words[@]} == 1 && ${#words[CURRENT]} < min_input )) ||
+ [[ -n $words[CURRENT] && $words[CURRENT] == $~ignored ]]; then
+ compstate[list]=
+ false
+ else
+ true
+ fi
+}
+# functions -T .autocomplete.async.sufficient-input
+
+.autocomplete.async.same-state() {
+ [[ $_autocomplete__words == $words && $_autocomplete__current == $CURRENT ]]
+}
+
+.autocomplete.async.list-choices.completion-widget() {
+ unset _autocomplete__mesg _autocomplete__comp_mesg _autocomplete__words _autocomplete__current
+
+ if [[ $1 != <->.<-> || $2 != <-> ]]; then
+ compstate[list]=
+ return
+ fi
+
+ .autocomplete.async.sufficient-input ||
+ return 2
+
+ local -PF _seconds_=$1
+ local -Pi _list_lines_=$2
+ local -P _mesg_=$3
+ shift 3
+
+ local +h -a comppostfuncs=( .autocomplete.async.list-choices.post "$comppostfuncs[@]" )
+ if [[ -n $compstate[old_list] ]] && .autocomplete.async.same-state; then
+ compstate[old_list]=keep
+ elif [[ $_list_lines_ == 1 && -n $1 ]]; then
+ builtin compadd "$@"
+ elif [[ $_list_lines_ == 1 && -n $_mesg_ ]]; then
+ builtin compadd -x "$_mesg_"
+ else
+ typeset -gHF _autocomplete__async_avg_duration=$((
+ .1 * _seconds_ + .9 * _autocomplete__async_avg_duration
+ ))
+ if [[ -n $curcontext ]]; then
+ _main_complete
+ else
+ local curcontext=list-choices:::
+ .autocomplete.async.list-choices.main-complete
+ fi
+ fi
+
+ typeset -gH _autocomplete__mesg=$_mesg_
+ typeset -gHa _autocomplete__comp_mesg=( "$@" )
+ typeset -gHa _autocomplete__words=( "$words[@]" )
+ typeset -gHi _autocomplete__current=$CURRENT
+
+ return 2 # Don't return 1, to prevent beeping.
+} 2>>| $_autocomplete__log
+log_functions+=( .autocomplete.async.list-choices.completion-widget )
+
+.autocomplete.async.list-choices.post() {
+ [[ -v _autocomplete__partial_list ]] &&
+ builtin compadd -J -last- -x '%F{0}%K{14}(MORE)%f%k'
+ compstate[insert]=
+ unset MENUSELECT MENUMODE
+}
+
+.autocomplete.async.list-choices.main-complete() {
+ {
+ local -i min_lines=
+ builtin zstyle -s ":autocomplete:${curcontext}:" list-lines min_lines ||
+ min_lines=16
+ min_lines=$(( min( LINES - ( 1 + BUFFERLINES ), min_lines ) ))
+ local -Pi lines_below_buffer=$(( LINES - ( _autocomplete__buffer_start_line + BUFFERLINES ) ))
+ local -i _autocomplete__max_lines=$(( max( min_lines, lines_below_buffer ) ))
+ local -i _autocomplete__reserved_lines=0
+ () {
+ emulate -L zsh
+ setopt $_autocomplete__func_opts[@]
+ functions[compadd]=$functions[.autocomplete.async.compadd]
+ # functions -T compadd .autocomplete.compadd #_describe
+ } "$@"
+ _main_complete "$@"
+ } always {
+ unfunction compadd comptags 2> /dev/null
+ }
+}
+
+.autocomplete.async.compadd() {
+ local -A _opts_=()
+ local -a _Dopt_=() _dopt_=()
+ zparseopts -A _opts_ -E -- D:=_Dopt_ E: J: O: V: x: X: d:
+
+ if [[ ( -v _opts_[-x] && $# == 2 ) ]]; then
+ .autocomplete.compadd "$@"
+ return
+ elif [[ $funcstack[(I)_describe] -gt 0 && -z $_Dopt_ ]]; then
+ _autocomplete__reserved_lines=0
+ fi
+
+ local -P _displ_array_= _matches_array_=
+ local -Pi _ret_=1 _new_nmatches_=-1 _new_list_lines_=-1
+ local -Pi _avail_list_lines_=$((
+ max( _autocomplete__max_lines - 1 - ${${_opts_[(i)-[Xx]]}:+1} - compstate[list_lines], 0 )
+ ))
+
+ if [[ -n $_Dopt_ ]]; then
+ .autocomplete.compadd "$@"
+ _ret_=$?
+
+ (( funcstack[(I)_describe] )) ||
+ return _ret_
+
+ _displ_array_=$_opts_[-D]
+
+ (( ${${(PA)_displ_array_}[(I)*:*]} )) ||
+ return _ret_
+
+ _matches_array_=$_opts_[-O]
+
+ (( _avail_list_lines_ -= _autocomplete__reserved_lines ))
+ _new_nmatches_=${(PA)#_displ_array_}
+ _new_list_lines_=${#${(@u)${(PA)_displ_array_}[@]#*:}}
+ (( _autocomplete__reserved_lines += _new_list_lines_ ))
+ else
+ _autocomplete__reserved_lines=0
+
+ # (Note: Can't put comments inside expansions, without setting INTERACTIVE_COMMENTS.)
+ local -Pa _out_=()
+ _out_=( "${(0)"$(
+ .autocomplete.compadd "$@"
+ print -rNC1 -- "$compstate[list_lines]" "$compstate[nmatches]"
+ )"}" )
+ _new_list_lines_=$(( max( 0, $_out_[1] - $compstate[list_lines] ) ))
+ _new_nmatches_=$(( max( 0, $_out_[2] - $compstate[nmatches] ) ))
+ fi
+
+ if (( _new_list_lines_ <= _avail_list_lines_ )); then
+ if [[ -z $_Dopt_ ]]; then
+ .autocomplete.compadd "$@"
+ _ret_=$?
+ fi
+ return _ret_
+ fi
+
+ if [[ -z $_Dopt_ ]]; then
+ local -a _matches_=()
+ .autocomplete.compadd -O _matches_ "$@" # Collect all matching completions.
+ _matches_array_=_matches_
+ _new_nmatches_=$#_matches_[@]
+ fi
+
+ local -a _groupname_=()
+
+ # NOTE: This will overwrite the contents of $_opts_ !
+ zparseopts -A _opts_ -D -E - k U d:=_dopt_ l=_dopt_ J:=_groupname_ V:=_groupname_
+
+ set -- "$_groupname_[@]" "$@"
+ [[ -z $_Dopt_ ]] &&
+ _displ_array_=$_dopt_[-1]
+
+ local -Pi _nmatches_per_line_=$(( 1.0 * _new_nmatches_ / _new_list_lines_ ))
+ if [[ _nmatches_per_line_ -lt 1 && -z $_Dopt_ ]]; then
+ # If we need more than one line per match, then make each match fit on one line.
+ if [[ -z $_displ_array_ ]]; then
+ local -a displ=( ${(PA)_matches_array_} )
+ _dopt_=( -d displ )
+ _displ_array_=displ
+ fi
+ _dopt_=( -l "$_dopt_[@]" )
+
+ # WORKAROUND: Display strings that are exactly $COLUMNS wide are mistakenly
+ # counted as spanning two lines, causing the dreaded
+ # `zsh: do you wish to see all XX possibilities (YY lines)?`
+ set -A $_displ_array_ ${(@r:COLUMNS-1:)${(PA)_displ_array_}[@]//$'\n'/\n}
+
+ _nmatches_per_line_=1
+ fi
+
+ # Need to round this down _before_ subtracting or it will be effectively rounded up.
+ local -Pi _fit_=$(( max( _avail_list_lines_, 0 ) * _nmatches_per_line_ ))
+ local -Pi _trim_=$(( max( 0, _new_nmatches_ - _fit_ ) ))
+
+ if (( _trim_ )); then
+ [[ -n $_matches_array_ ]] &&
+ shift -p $(( min( _trim_, ${(PA)#_matches_array_} ) )) $_matches_array_
+ [[ -n $_displ_array_ ]] &&
+ shift -p $(( min( _trim_, ${(PA)#_displ_array_} ) )) $_displ_array_
+ typeset -gH _autocomplete__partial_list=$curtag
+
+ # If we have to trim off matches, that means we've run out of screen space.
+ # So, disable all further completion.
+ comptags() {
+ return 1
+ }
+ fi
+
+ if [[ -z $_Dopt_ ]]; then
+ _autocomplete.compadd_opts_len "$@"
+ .autocomplete.compadd $_dopt_ "$@[1,?]" -a -- $_matches_array_
+ _ret_=$?
+ fi
+
+ return _ret_
+} 2>>| $_autocomplete__log
+log_functions+=( .autocomplete.async.compadd )
+
+typeset -gHa _autocomplete__log_functions=( $log_functions[@] )
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.compinit b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.compinit
new file mode 100644
index 00000000..4ea5f5dc
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.compinit
@@ -0,0 +1,229 @@
+#!/bin/zsh
+zmodload -Fa zsh/files b:zf_rm
+zmodload -F zsh/parameter p:funcstack p:functions
+
+typeset -gHa _autocomplete__compdef=()
+compdef() {
+ typeset -gHa _autocomplete__compdef=( $_autocomplete__compdef[@] "${(j: :)${(@q+)@}}" )
+}
+
+[[ -v functions[_bash_complete] ]] ||
+ _bash_complete compgen complete () {
+ unfunction _bash_complete compgen complete
+ builtin autoload +X -Uz bashcompinit
+ bashcompinit
+ bashcompinit() { : }
+ ${(%):-%N} "$@"
+ }
+
+.autocomplete.compinit.precmd() {
+ emulate -L zsh
+ setopt $_autocomplete__func_opts[@]
+
+ [[ -v CDPATH && -z $CDPATH ]] &&
+ unset CDPATH cdpath
+
+ # Decrease Oh My Zsh start-up time. See below.
+ local -Pa omzdump=()
+ [[ -v ZSH_COMPDUMP && -r $ZSH_COMPDUMP ]] &&
+ omzdump=( ${(f)"$( < $ZSH_COMPDUMP )"} )
+
+ typeset -gU FPATH fpath=( ~zsh-autocomplete/functions/completion $fpath[@] )
+ typeset -gH \
+ _comp_dumpfile=${_comp_dumpfile:-${ZSH_COMPDUMP:-${XDG_CACHE_HOME:-$HOME/.cache}/zsh/compdump}}
+
+ if [[ -v _comps[-command-] && $_comps[-command-] != _autocomplete.command ]]; then
+ zf_rm -f $_comp_dumpfile
+ else
+ local -Pa compfuncfiles=( ~zsh-autocomplete/functions/completion/_autocomplete.*~*.zwc(N-.) )
+
+ if ! (( $#compfuncfiles )); then
+ print -u2 -- 'autocomplete: Failed to find completion function files. Aborting.'
+ return 66
+ fi
+
+ # Check if any of our function files are newer than the comp dump file.
+ local -P f=
+ for f in $compfuncfiles[@]; do
+ if [[ -v functions[$f:t] && $f -nt $_comp_dumpfile ]]; then
+ zf_rm -f $_comp_dumpfile
+ break
+ fi
+ done
+ fi
+
+ if ! [[ -v _comp_setup && -r $_comp_dumpfile ]]; then
+ unfunction compdef compinit 2> /dev/null
+ bindkey() { : }
+ {
+ builtin autoload +X -Uz compinit
+ compinit -d $_comp_dumpfile
+ } always {
+ unfunction bindkey
+ }
+
+ # Prevent Oh My Zsh from deleting comp dump file.
+ (( ${#omzdump[@]} > 0 )) &&
+ tee -a "$ZSH_COMPDUMP" &> /dev/null <<EOF
+$omzdump[-2]
+$omzdump[-1]
+EOF
+ fi
+
+ compinit() { : }
+
+ local -P args=
+ for args in "$_autocomplete__compdef[@]"; do
+ eval "compdef $args"
+ done
+ unset _autocomplete__compdef
+
+ (
+ local -a reply=()
+ local cache_dir=
+ if builtin zstyle -s ':completion:*' cache-path cache_dir; then
+ local -P src= bin=
+ for src in $cache_dir/*~**.zwc~**/.*(N-.); do
+ bin=$src.zwc
+ if [[ ! -e $bin || $bin -ot $src ]]; then
+ zcompile -Uz $src
+ fi
+ done
+ fi
+ ) &|
+
+ .autocomplete.patch _main_complete
+ _main_complete() {
+ local -i _autocomplete__reserved_lines=0
+ local -Pi ret=1
+ unset _autocomplete__partial_list _autocomplete__unambiguous
+
+ compstate[insert]=menu # To get the best output from `_expand` (and some other functions).
+ compstate[last_prompt]=yes # Completion doesn't stay on the same command line without this.
+ compstate[list]='list force packed rows' # `_setup` doesn't work well for this.
+ unset 'compstate[vared]'
+
+ [[ -v functions[compadd] ]] ||
+ functions[compadd]=$functions[.autocomplete.compadd]
+
+ local +h -a comppostfuncs=( _autocomplete._main_complete.post "$comppostfuncs[@]" )
+ .autocomplete._main_complete "$@"
+ }
+
+ # Add support for coloring file types to _expand.
+ # TODO: Might be added a future version of zsh.
+ .autocomplete.compadd() {
+ if [[ $_completer == expand* ]]; then
+ [[ $@[-1] == space && $#space[@] -eq 1 ]] &&
+ space=( ${(q+)${(Q)space}} )
+ builtin compadd -fW "${${${words[CURRENT]:#[~/]*}:+$PWD/}:-/}" "$@"
+ else
+ builtin compadd "$@"
+ fi
+ }
+
+ _autocomplete._main_complete.post() {
+ [[ $WIDGET != _complete_help ]] &&
+ unfunction compadd 2> /dev/null
+ _autocomplete.unambiguous
+ compstate[list_max]=0
+ MENUSCROLL=0
+ }
+
+ .autocomplete.patch _expand
+ _expand() {
+ if _autocomplete.is_glob; then
+ compstate[pattern_insert]= # Make compstate[insert]=unambiguous work.
+ compstate[pattern_match]=\* # Smartly append * to the pattern.
+
+ .autocomplete._expand "$@"
+ return
+ fi
+
+ .autocomplete._expand "$@"
+ }
+
+ .autocomplete.patch _complete
+ _complete() {
+ local -i nmatches=$compstate[nmatches]
+ .autocomplete._complete "$@" ||
+ _autocomplete.ancestor_dirs "$@" ||
+ _autocomplete.recent_paths "$@"
+
+ # Workaround the fact that some completion functions mistakenly don't
+ # return 0 when they have succeeded.
+ (( compstate[nmatches] > nmatches ))
+ }
+
+ .autocomplete.patch _approximate
+ _approximate() {
+ [[ -z $words[CURRENT] || -v compstate[quote] ]] &&
+ return 1
+ [[ -o banghist && $words[CURRENT] == [$histchars]* ]] &&
+ return 1
+ _autocomplete.is_glob &&
+ return 1
+
+ local -Pi ret=1
+ {
+ [[ -v functions[compadd] ]] &&
+ functions[.autocomplete.__tmp__]=$functions[compadd]
+
+ compadd() {
+ local -P ppre="$argv[(I)-p]"
+
+ [[ ${argv[(I)-[a-zA-Z]#U[a-zA-Z]#]} -eq 0 && "${#:-$PREFIX$SUFFIX}" -le _comp_correct ]] &&
+ return
+
+ if [[ "$PREFIX" = \~* && ( ppre -eq 0 || "$argv[ppre+1]" != \~* ) ]]; then
+ PREFIX="~(#a${_comp_correct})${PREFIX[2,-1]}"
+ else
+ PREFIX="(#a${_comp_correct})$PREFIX"
+ fi
+
+ builtin compadd "$@"
+ }
+
+ .autocomplete._approximate "$@"
+ ret=$?
+ _lastdescr=( ${_lastdescr[@]:#corrections} )
+ } always {
+ [[ -v functions[compadd] ]] &&
+ unfunction compadd
+ if [[ -v functions[.autocomplete.__tmp__] ]]; then
+ functions[compadd]=$functions[.autocomplete.__tmp__]
+ unfunction .autocomplete.__tmp__
+ fi
+ }
+ return ret
+ }
+
+ # Let parameter completion list each parameter's value.
+ # TODO: Might be added to a future version of zsh.
+ .autocomplete.patch _wanted
+ _wanted() {
+ if [[ $funcstack == *_parameters* ]] &&
+ builtin zstyle -T ":completion:${curcontext}:parameters" verbose; then
+ local -a params=( $@[(re)-,-1] )
+ shift -p $#params
+ shift params
+ _description "$@[1,3]"
+ builtin compadd "$expl[@]" "$@[5,-1]" -D params -a params
+ local -a displays=()
+
+ local sep=
+ builtin zstyle -s ":completion:${curcontext}:parameters" list-separator sep ||
+ sep=--
+
+ local -Pi MBEGIN= MEND=
+ local -P MATCH=
+ zformat -a displays " $sep " \
+ "${(@)params[@]:/(#m)*/${MATCH}:${${(kv)${(P)MATCH}}[1,COLUMNS]}}"
+ displays=( "${(@)displays[@]//(#m)[^[:print:]]##/${(q+)MATCH}}" )
+ displays=( "${(@)displays[@]:/(#m)*/$MATCH[1,COLUMNS]}" )
+ .autocomplete._wanted "$@" -d displays -a params
+ else
+ .autocomplete._wanted "$@"
+ fi
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.config b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.config
new file mode 100644
index 00000000..a79a9c92
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.config
@@ -0,0 +1,138 @@
+#!/bin/zsh
+zmodload -Fa zsh/zutil b:zstyle
+builtin autoload -RUz is-at-least
+typeset -g ZLE_REMOVE_SUFFIX_CHARS=$' /;\n\r\t'
+typeset -g ZLE_SPACE_SUFFIX_CHARS=$'|&<>-+'
+
+.autocomplete.config.precmd() {
+ typeset -gH _comp_setup="$_comp_setup"';
+ [[ $_comp_caller_options[globdots] == yes ]] && setopt globdots'
+
+ # Remove incompatible settings.
+ builtin zstyle -d ':completion:*:*:*:*:*' menu
+ builtin zstyle -d ':completion:*:default' list-prompt
+ unset LISTPROMPT
+}
+
+builtin zstyle ':completion:*' use-cache yes
+builtin zstyle -e ':completion:*' cache-path _autocomplete.config.cache-path
+_autocomplete.config.cache-path() {
+ reply=( "${XDG_CACHE_HOME:-$HOME/.cache}/zsh/compcache" )
+}
+
+builtin zstyle -e ':completion:*' completer _autocomplete.config.completer
+_autocomplete.config.completer() {
+ if [[ CURRENT -eq 1 && -z $PREFIX$SUFFIX && $compstate[context] == command ]]; then
+ reply=( _complete )
+ else
+ reply=( _expand _complete _approximate _complete:-loose _complete:-fuzzy _ignored )
+ fi
+}
+builtin zstyle ':completion:list-expand:*' completer \
+ _expand _complete:-fuzzy _ignored
+builtin zstyle ':completion:history-incremental-*search-*:*' completer \
+ _autocomplete.history_lines
+
+builtin zstyle ':completion:*:expand:*' tag-order '! original' -
+builtin zstyle -e ':completion:*:-command-:*' tag-order _autocomplete.config.tag-order.command
+_autocomplete.config.tag-order.command() {
+ if [[ $PREFIX == (|.|*/*) ]]; then
+ reply=( 'suffix-aliases (|*-)directories executables (|*-)files' - )
+ else
+ reply=( aliases suffix-aliases functions 'reserved-words builtins' )
+ if [[ -n $path[(r).] ]]; then
+ reply+=( '(|*-)directories executables (|*-)files' commands )
+ else
+ reply+=( commands '(|*-)directories executables (|*-)files' )
+ fi
+ fi
+}
+builtin zstyle ':completion:list-expand:*:-command-:*' tag-order '*'
+builtin zstyle ':completion:*:-tilde-:*' tag-order directory-stack named-directories
+builtin zstyle ':completion:*:(approximate|correct):*' tag-order '! original' -
+
+builtin zstyle ':completion:*:git-*:(|*-)argument-*:*' tag-order \
+ '! (|cached-)files *-remote remote-* (|*-)tags' \
+ '! *-remote remote-* tags'
+builtin zstyle ':completion:list-expand:*:git-*:(|*-)argument-*:*' tag-order '*'
+
+# Order of matchers matters: m should come before r, which should come before l.
+# Otherwise, the results are not as expected.
+builtin zstyle ':completion:*' matcher-list \
+ 'm:{[:lower:]-}={[:upper:]_} r:|[.]=**' \
+ '+l:|=*'
+builtin zstyle ':completion:*-loose:*' matcher-list \
+ 'm:{[:lower:]-}={[:upper:]_} r:|[.]=** l:?|=[-_\\ ] r:?||[-_]=*'
+builtin zstyle ':completion:*-fuzzy:*' matcher-list \
+ 'm:{[:lower:]-}={[:upper:]_} r:|?=**'
+
+builtin zstyle ':completion:*:options' matcher 'b:-=+'
+
+builtin zstyle ':completion:*' prefix-needed yes
+builtin zstyle ':completion:*:-command-:*' ignore-line current
+builtin zstyle ':completion:*:functions' ignored-patterns ''
+builtin zstyle ':completion:*:users' ignored-patterns '_*'
+builtin zstyle ':completion:*:widgets' ignored-patterns '.*' '*:*' '*orig-*'
+builtin zstyle ':completion:*' single-ignored ''
+
+builtin zstyle ':completion:*:expand:*' accept-exact continue
+builtin zstyle -e ':completion:*:expand:*' glob _autocomplete.is_glob
+builtin zstyle ':completion:*:expand:*' keep-prefix no # Needed for file type highlighting
+builtin zstyle ':completion:*:expand:*' add-space subst
+builtin zstyle -e ':completion:*:expand:*' substitute _autocomplete.config.expand.substitute
+_autocomplete.config.expand.substitute() {
+ local -P __word__=$PREFIX$SUFFIX
+ if [[ ${(Q)__word__} == *(\`*\`|\$\(*\))* ]]; then
+ reply=( false )
+ else
+ reply=( true )
+ fi
+}
+
+builtin zstyle ':completion:*:expand-alias:*' complete yes
+
+# Complete only the tail of a path.
+builtin zstyle ':completion:*' ignore-parents 'parent pwd directory'
+builtin zstyle ':completion:*:paths' expand suffix
+builtin zstyle ':completion:*:paths' list-suffixes yes
+builtin zstyle ':completion:*:paths' path-completion no
+builtin zstyle ':completion:*:paths' special-dirs no
+
+builtin zstyle ':completion:*' group-name ''
+builtin zstyle ':completion:*' group-order \
+ all-expansions expansions options \
+ aliases suffix-aliases functions reserved-words builtins commands \
+ local-directories directories executables
+
+builtin zstyle ':completion:*' complete-options yes
+
+builtin zstyle ':completion:*' file-patterns \
+ '*(-/):directories:directory %p(#q^-/):globbed-files'
+builtin zstyle -e ':completion:*:-command-:*' file-patterns \
+ _autocomplete.config.file-patterns.command
+_autocomplete.config.file-patterns.command() {
+ [[ $PREFIX != */* ]] &&
+ reply=( '*(-/):directories:directory ./*(-*^/):executables:"executable file"' )
+}
+builtin zstyle ':completion:*:(.|source):*' file-patterns \
+ '%p(#q-/):directories:directory %p~*.zwc(-.^*):globbed-files' '%p~*.zwc(-^/):globbed-files'
+
+builtin zstyle ':completion:*:descriptions' format $'%{\e[0;2m%}%d%{\e[0m%}'
+builtin zstyle -e ':completion:*:warnings' format _autocomplete.config.format
+_autocomplete.config.format() {
+ [[ $CURRENT == 1 && -z $PREFIX$SUFFIX ]] ||
+ reply=( $'%{\e[0;2m%}'"no matching %d completions"$'%{\e[0m%}' )
+}
+builtin zstyle ':completion:*:messages' format '%F{9}%d%f'
+builtin zstyle ':completion:*:history-lines' format ''
+
+builtin zstyle ':completion:*' auto-description '%d'
+builtin zstyle ':completion:*:parameters' extra-verbose yes
+builtin zstyle ':completion:*:default' select-prompt '%F{black}%K{14}line %l %p%f%k'
+
+builtin zstyle ':completion:*' insert-sections yes
+builtin zstyle ':completion:*' separate-sections yes
+
+# Needed for _gnu_generic to prevent descriptions from getting cropped.
+# TODO: Might be fixed in a future version of zsh.
+builtin zstyle ':completion:*' command '- COLUMNS=999'
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.key-binding b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.key-binding
new file mode 100644
index 00000000..d4cce583
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.key-binding
@@ -0,0 +1,130 @@
+#!/bin/zsh
+zmodload zsh/complist
+zmodload -F zsh/parameter p:funcstack p:functions
+zmodload -F zsh/terminfo p:terminfo
+
+.autocomplete.key-binding.precmd() {
+ emulate -L zsh
+ setopt $_autocomplete__func_opts[@]
+
+ local -a ignored=()
+ builtin zstyle -g ignored ':autocomplete:shift-tab:*' insert-unambiguous ||
+ builtin zstyle ':autocomplete:shift-tab:*' insert-unambiguous yes
+
+ local tab_style=
+ if ! builtin zstyle -s :autocomplete:tab: widget-style tab_style; then
+ tab_style='complete-word'
+ builtin zstyle ':autocomplete:tab:*' widget-style $tab_style
+ fi
+
+ if builtin zstyle -t :autocomplete:tab: fzf-completion &&
+ [[ -v functions[fzf-completion] ]]; then
+ typeset -gH fzf_default_completion=$tab_style
+ functions[.autocomplete.fzf-completion]=$functions[fzf-completion]
+ fzf-completion() {
+ zle() {
+ builtin zle "$@" ${${(M)funcstack[2]:#.autocomplete.fzf-completion}:+-w}
+ }
+ {
+ .autocomplete.fzf-completion "$@"
+ } always {
+ [[ -v functions[zle] ]] &&
+ unfunction zle
+ }
+ }
+ else
+ builtin bindkey -M emacs '\t' $tab_style
+ builtin bindkey -M viins '\t' $tab_style
+ fi
+
+ if [[ $tab_style == *menu-* ]]; then
+ builtin bindkey -M menuselect '\t' menu-complete
+ else
+ builtin bindkey -M menuselect '\t' accept-line
+ fi
+
+ if [[ -v terminfo[kcbt] && -n $terminfo[kcbt] ]]; then
+ local backtab_style=
+ if ! builtin zstyle -s :autocomplete:shift-tab: widget-style backtab_style; then
+ backtab_style=${tab_style:/menu-complete/reverse-menu-complete}
+ builtin zstyle ':autocomplete:shift-tab:*' widget-style $backtab_style
+ fi
+
+ builtin bindkey -M emacs $terminfo[kcbt] $backtab_style
+ builtin bindkey -M viins $terminfo[kcbt] $backtab_style
+ if [[ $backtab_style == *menu-* ]]; then
+ builtin bindkey -M menuselect $terminfo[kcbt] reverse-menu-complete
+ else
+ builtin bindkey -M menuselect -s $terminfo[kcbt] "\t^_$terminfo[kcbt]"
+ fi
+ fi
+}
+
+.autocomplete.key-binding.bind() {
+ local -P map=$1 widget=$2
+ shift 2
+ builtin bindkey -M "$map" "${@:^^widget}"
+}
+
+.autocomplete.key-binding.bound() {
+ [[ $( builtin bindkey -M "$1" "$2" ) == \"$2\"" $3" ]]
+}
+
+.autocomplete.key-binding.rebind() {
+ .autocomplete.key-binding.bound "$1" "$2" "$3" &&
+ builtin bindkey -M "$1" "$2" "$4"
+}
+
+.autocomplete.key-binding.unbind() {
+ .autocomplete.key-binding.bound "$1" "$2" "$3" &&
+ builtin bindkey -M "$1" -r "$2"
+}
+
+builtin bindkey -M emacs '^@' list-expand
+builtin bindkey -M vicmd '^@' list-expand
+builtin bindkey -M viins '^@' list-expand
+
+local -Pa prefix=( '\e'{\[,O} )
+local -Pa up=( ${^prefix}A ) down=( ${^prefix}B )
+local -Pa alt_up=( '\e'$^up '\e[1;3A' ) alt_down=( '\e'$^down '\e[1;3B' )
+
+.autocomplete.key-binding.bind emacs up-line-or-search $up[@]
+.autocomplete.key-binding.bind viins up-line-or-search $up[@]
+
+.autocomplete.key-binding.bind emacs history-search $alt_up[@]
+builtin bindkey -M emacs "$terminfo[kpp]" history-search
+builtin bindkey -M viins "$terminfo[kpp]" history-search
+.autocomplete.key-binding.bind vicmd history-search $up[@]
+
+.autocomplete.key-binding.bind emacs down-line-or-select $down[@]
+.autocomplete.key-binding.bind viins down-line-or-select $down[@]
+
+.autocomplete.key-binding.bind emacs menu-select $alt_down[@]
+builtin bindkey -M emacs "$terminfo[knp]" menu-select
+builtin bindkey -M viins "$terminfo[knp]" menu-select
+.autocomplete.key-binding.bind vicmd menu-select $down[@]
+
+.autocomplete.key-binding.rebind emacs '^D' delete-char-or-list delete-char
+
+.autocomplete.key-binding.unbind emacs '^X*' expand-word
+
+.autocomplete.key-binding.unbind emacs '\e^D' list-choices
+.autocomplete.key-binding.unbind vicmd '^D' list-choices
+.autocomplete.key-binding.unbind vicmd '=' list-choices
+.autocomplete.key-binding.unbind viins '^D' list-choices
+
+.autocomplete.key-binding.unbind emacs '^Xg' list-expand
+.autocomplete.key-binding.unbind emacs '^XG' list-expand
+.autocomplete.key-binding.unbind vicmd '^G' list-expand
+.autocomplete.key-binding.unbind viins '^G' list-expand
+
+.autocomplete.key-binding.bind menuselect vi-backward-blank-word $alt_up[@]
+.autocomplete.key-binding.bind menuselect vi-forward-blank-word $alt_down[@]
+builtin bindkey -M menuselect \
+ '\r' .accept-line \
+ '^@' accept-and-hold \
+ "$terminfo[kpp]" backward-word \
+ "$terminfo[knp]" forward-word \
+ '^_' .undo
+
+unfunction .autocomplete.key-binding.{{,re,un}bind,bound}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.recent-dirs b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.recent-dirs
new file mode 100644
index 00000000..9c5601b8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.recent-dirs
@@ -0,0 +1,92 @@
+#!/bin/zsh
+zmodload -Fa zsh/files b:zf_mv b:zf_mkdir
+zmodload -F zsh/parameter p:commands p:dirstack p:functions
+
+.autocomplete.recent-dirs.precmd() {
+ # NOTE: Cannot set localopts, because of `cdr`, below.
+
+ if [[ -v precmd_functions && $precmd_functions[(I)_zshz_precmd] != 0 ]] &&
+ builtin zstyle -T ':autocomplete:recent-dirs' backend 'zsh-z'; then
+ _autocomplete.recent_directories() {
+ reply=( ${(f)"$( zshz --complete -l $1 2> /dev/null )"} )
+ }
+
+ elif [[ -v chpwd_functions && $chpwd_functions[(I)__zoxide_hook] != 0 ]] &&
+ builtin zstyle -T ':autocomplete:recent-dirs' backend'zoxide'; then
+ _autocomplete.recent_directories() {
+ reply=( ${(f)"$( zoxide query --list $1 2> /dev/null )"} )
+ }
+
+ elif [[ -v chpwd_functions && $chpwd_functions[(I)_zlua_precmd] != 0 ]] &&
+ builtin zstyle -T ':autocomplete:recent-dirs' backend 'z.lua'; then
+ _autocomplete.recent_directories() {
+ reply=( ${${(f)"$( _zlua --complete $1 2> /dev/null )"}##<->[[:space:]]##} )
+ }
+
+ elif [[ -v precmd_functions && $precmd_functions[(I)_z_precmd] != 0 ]] &&
+ builtin zstyle -T ':autocomplete:recent-dirs' backend 'z.sh'; then
+ _autocomplete.recent_directories() {
+ reply=( ${${(fOa)"$( _z -l $1 2>&1 )"}##(common:|<->)[[:space:]]##} )
+ }
+
+ elif [[ -v chpwd_functions && $chpwd_functions[(I)autojump_chpwd] != 0 ]] &&
+ builtin zstyle -T ':autocomplete:recent-dirs' backend 'autojump'; then
+ _autocomplete.recent_directories() {
+ reply=( ${${(f)"$( autojump --complete $1 2> /dev/null )"}##${1}__<->__} )
+ }
+
+ elif [[ -v preexec_functions && $preexec_functions[(I)_fasd_preexec] != 0 ]] &&
+ builtin zstyle -T ':autocomplete:recent-dirs' backend 'fasd'; then
+ _autocomplete.recent_directories() {
+ reply=( ${(f)"$( fasd -dlR $1 2> /dev/null )"} )
+ }
+
+ elif builtin autoload -RUz chpwd_recent_filehandler &&
+ builtin zstyle -T ':autocomplete:recent-dirs' backend 'cdr'; then
+ setopt autopushd pushdignoredups
+
+ if ! builtin zstyle -s :chpwd: recent-dirs-file _; then
+ local -P old=${ZDOTDIR:-$HOME}/.chpwd-recent-dirs
+ local -P new=${XDG_DATA_HOME:-$HOME/.local/share}/zsh/chpwd-recent-dirs
+ builtin zstyle ':chpwd:*' recent-dirs-file $new
+ [[ -e $old && ! -e $new ]] &&
+ zf_mv "$old" "$new"
+ fi
+ builtin zstyle -s :chpwd: recent-dirs-max _ ||
+ builtin zstyle ':chpwd:*' recent-dirs-max 0
+
+ if ! (( $#dirstack[@] )); then
+ local -aU reply=()
+ chpwd_recent_filehandler
+ dirstack=( ${^reply[@]:#$PWD}(N-/) )
+ fi
+
+ _autocomplete.recent_directories.save() {
+ chpwd_recent_filehandler $PWD $dirstack[@]
+ }
+ add-zsh-hook chpwd _autocomplete.recent_directories.save
+
+ _autocomplete.recent_directories() {
+ reply=( ${^dirstack[@]:#$PWD(|/[^/]#)}(N) )
+
+ local -P ancestor=$PWD:h
+ while [[ $ancestor != / ]]; do
+ reply=( ${reply[@]:#$ancestor} )
+ ancestor=$ancestor:h
+ done
+
+ local exact=$reply[(r)*/$PREFIX$SUFFIX]
+ [[ -n $exact ]] &&
+ reply=( $exact ${reply[@]:#$exact} )
+
+ (( $#reply[@] ))
+ }
+ fi
+
+ if [[ -v preexec_functions && $preexec_functions[(I)_fasd_preexec] != 0 ]] &&
+ builtin zstyle -T ':autocomplete:' recent-files 'fasd'; then
+ _autocomplete.recent_files() {
+ reply=( $( fasd -flR $1 2> /dev/null ) )
+ }
+ fi
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.widget b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.widget
new file mode 100644
index 00000000..c646bc65
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/scripts/.autocomplete.widget
@@ -0,0 +1,31 @@
+#!/bin/zsh
+zmodload zsh/complist
+typeset -g ZSH_AUTOSUGGEST_MANUAL_REBIND=1
+typeset -g ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=.autosuggest-orig-
+
+.autocomplete.widget.precmd() {
+ emulate -L zsh
+ setopt $_autocomplete__func_opts[@]
+
+ local -P tab_style=
+ for tab_style in complete-word menu-complete menu-select; do
+ .autocomplete.widget.c "$tab_style" "$tab_style" complete-word
+ done
+ .autocomplete.widget.c reverse-menu-complete reverse-menu-complete complete-word
+
+ unfunction .autocomplete.widget.c .autocomplete.widget.z
+}
+
+.autocomplete.widget.c() {
+ builtin zle -C "$1" "$2" .autocomplete.$3.completion-widget
+}
+
+.autocomplete.widget.z() {
+ builtin zle -N "$1" .autocomplete.$2.zle-widget
+}
+
+.autocomplete.widget.c list-expand complete-word list-expand
+.autocomplete.widget.c _history_search menu-select history-search
+.autocomplete.widget.z history-search history-search
+.autocomplete.widget.z up-line-or-search up-line-or-search
+.autocomplete.widget.z down-line-or-select down-line-or-select
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/zsh-autocomplete.plugin.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/zsh-autocomplete.plugin.zsh
new file mode 100644
index 00000000..d69f4486
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/zsh-autocomplete.plugin.zsh
@@ -0,0 +1,19 @@
+#!/bin/zsh
+zmodload -F zsh/parameter p:funcfiletrace p:functions
+
+# Workaround for https://github.com/zdharma/zinit/issues/366
+# NOTE: Needs to come before _everything_ else!
+[[ -v functions[.zinit-shade-off] ]] &&
+ .zinit-shade-off "${___mode:-load}"
+[[ -v functions[.zinit-tmp-subst-off] ]] &&
+ .zinit-tmp-subst-off "${___mode:-load}"
+
+zmodload zsh/param/private
+setopt NO_flowcontrol NO_listbeep NO_singlelinezle
+typeset -gHa _autocomplete__funcfiletrace=( $funcfiletrace[2,-2] )
+builtin autoload +X -Uz ${${(%):-%x}:P:h}/scripts/.autocomplete.__init__
+{
+ .autocomplete.__init__ "$@"
+} always {
+ unfunction .autocomplete.__init__
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.circleci/config.yml b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.circleci/config.yml
new file mode 100644
index 00000000..d95fa98b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.circleci/config.yml
@@ -0,0 +1,15 @@
+version: 2
+jobs:
+ build:
+ parallelism: 4
+ shell: /bin/bash --login
+ docker:
+ - image: ericfreese/zsh-autosuggestions-test:latest
+ steps:
+ - checkout
+ - run:
+ name: Running tests
+ command: |
+ for v in $(grep "^[^#]" ZSH_VERSIONS | awk "(NR + $CIRCLE_NODE_INDEX) % $CIRCLE_NODE_TOTAL == 0"); do
+ TEST_ZSH_BIN=zsh-$v make test || exit 1
+ done
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.editorconfig b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.editorconfig
new file mode 100644
index 00000000..ddabb17b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.editorconfig
@@ -0,0 +1,18 @@
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = tab
+indent_size = 4
+
+[*.md]
+indent_style = space
+
+[*.rb]
+indent_style = space
+indent_size = 2
+
+[*.yml]
+indent_style = space
+indent_size = 2
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.rspec b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.rspec
new file mode 100644
index 00000000..43ae2036
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.rspec
@@ -0,0 +1,3 @@
+--color
+--require spec_helper
+--format documentation
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.rubocop.yml b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.rubocop.yml
new file mode 100644
index 00000000..97facac8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.rubocop.yml
@@ -0,0 +1,30 @@
+# Rails:
+# Enabled: true
+
+AllCops:
+ TargetRubyVersion: 2.3
+ Include:
+ - '**/Rakefile'
+ - '**/config.ru'
+ - '**/Gemfile'
+
+Metrics/LineLength:
+ Max: 120
+
+Style/Documentation:
+ Enabled: false
+
+Style/DotPosition:
+ EnforcedStyle: trailing
+
+Style/FrozenStringLiteralComment:
+ Enabled: false
+
+Style/Lambda:
+ Enabled: false
+
+Style/MultilineMethodCallIndentation:
+ EnforcedStyle: indented
+
+Style/TrailingUnderscoreVariable:
+ Enabled: false
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.ruby-version b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.ruby-version
new file mode 100644
index 00000000..aedc15bb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/.ruby-version
@@ -0,0 +1 @@
+2.5.3
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/CHANGELOG.md b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/CHANGELOG.md
new file mode 100644
index 00000000..15d65a98
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/CHANGELOG.md
@@ -0,0 +1,117 @@
+# Changelog
+
+## v0.7.0
+- Enable asynchronous mode by default (#498)
+- No longer wrap user widgets starting with `autosuggest-` prefix (#496)
+- Fix a bug wrapping widgets that modify the buffer (#541)
+
+
+## v0.6.4
+- Fix `vi-forward-char` triggering a bell when using it to accept a suggestion (#488)
+- New configuration option to skip completion suggestions when buffer matches a pattern (#487)
+- New configuration option to ignore history entries matching a pattern (#456)
+
+## v0.6.3
+- Fixed bug moving cursor to end of buffer after accepting suggestion (#453)
+
+## v0.6.2
+- Fixed bug deleting the last character in the buffer in vi mode (#450)
+- Degrade gracefully when user doesn't have `zsh/system` module installed (#447)
+
+## v0.6.1
+- Fixed bug occurring when `_complete` had been aliased (#443)
+
+## v0.6.0
+- Added `completion` suggestion strategy powered by completion system (#111)
+- Allow setting `ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE` to an empty string (#422)
+- Don't fetch suggestions after copy-earlier-word (#439)
+- Allow users to unignore zle-\* widgets (e.g. zle-line-init) (#432)
+
+
+## v0.5.2
+- Allow disabling automatic widget re-binding for better performance (#418)
+- Fix async suggestions when `SH_WORD_SPLIT` is set
+- Refactor async mode to use process substitution instead of zpty (#417)
+
+## v0.5.1
+- Speed up widget rebinding (#413)
+- Clean up global variable creations (#403)
+- Respect user's set options when running original widget (#402)
+
+## v0.5.0
+- Don't overwrite config with default values (#335)
+- Support fallback strategies by supplying array to suggestion config var
+- Rename "default" suggestion strategy to "history" to name it based on what it actually does
+- Reset opts in some functions affected by `GLOB_SUBST` (#334)
+- Support widgets starting with dashes (ex: `-a-widget`) (#337)
+- Skip async tests in zsh versions less than 5.0.8 because of reliability issues
+- Fix handling of newline + carriage return in async pty (#333)
+
+
+## v0.4.3
+- Avoid bell when accepting suggestions with `autosuggest-accept` (#228)
+- Don't fetch suggestions after [up,down]-line-or-beginning-search (#227, #241)
+- We are now running CI against new 5.5.1 version
+- Fix partial-accept in vi mode (#188)
+- Fix suggestion disappearing on fast movement after switching to `vicmd` mode (#290)
+- Fix issue rotating through kill ring with `yank-pop` (#301)
+- Fix issue creating new pty for async mode when previous pty is not properly cleaned up (#249)
+
+## v0.4.2
+- Fix bug in zsh versions older than 5.0.8 (#296)
+- Officially support back to zsh v4.3.11
+
+## v0.4.1
+- Switch to [[ and (( conditionals instead of [ (#257)
+- Avoid warnnestedvar warnings with `typeset -g` (#275)
+- Replace tabs with spaces in yaml (#268)
+- Clean up and fix escaping of special characters (#267)
+- Add `emacs-forward-word` to default list of partial accept widgets (#246)
+
+## v0.4.0
+- High-level integration tests using RSpec and tmux
+- Add continuous integration with Circle CI
+- Experimental support for asynchronous suggestions (#170)
+- Fix problems with multi-line suggestions (#225)
+- Optimize case where manually typing in suggestion
+- Avoid wrapping any zle-\* widgets (#206)
+- Remove support for deprecated options from v0.0.x
+- Handle history entries that begin with dashes
+- Gracefully handle being sourced multiple times (#126)
+- Add enable/disable/toggle widgets to disable/enable suggestions (#219)
+
+
+## v0.3.3
+- Switch from $history array to fc builtin for better performance with large HISTFILEs (#164)
+- Fix tilde handling when extended_glob is set (#168)
+- Add config option for maximum buffer length to fetch suggestions for (#178)
+- Add config option for list of widgets to ignore (#184)
+- Don't fetch a new suggestion unless a modification widget actually modifies the buffer (#183)
+
+## v0.3.2
+- Test runner now supports running specific tests and choosing zsh binary
+- Return code from original widget is now correctly passed through (#135)
+- Add `vi-add-eol` to list of accept widgets (#143)
+- Escapes widget names within evals to fix problems with irregular widget names (#152)
+- Plugin now clears suggestion while within a completion menu (#149)
+- .plugin file no longer relies on symbolic link support, fixing issues on Windows (#156)
+
+## v0.3.1
+
+- Fixes issue with `vi-next-char` not accepting suggestion (#137).
+- Fixes global variable warning when WARN_CREATE_GLOBAL option enabled (#133).
+- Split out a separate test file for each widget.
+
+## v0.3.0
+
+- Adds `autosuggest-execute` widget (PR #124).
+- Adds concept of suggestion "strategies" for different ways of fetching suggestions.
+- Adds "match_prev_cmd" strategy (PR #131).
+- Uses git submodules for testing dependencies.
+- Lots of test cleanup.
+- Various bug fixes for zsh 5.0.x and `sh_word_split` option.
+
+
+## v0.2.17
+
+Start of changelog.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/DESCRIPTION b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/DESCRIPTION
new file mode 100644
index 00000000..b69200fc
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/DESCRIPTION
@@ -0,0 +1 @@
+Fish-like fast/unobtrusive autosuggestions for zsh.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Dockerfile b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Dockerfile
new file mode 100644
index 00000000..0d51407c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Dockerfile
@@ -0,0 +1,20 @@
+FROM ruby:2.5.3-alpine
+
+RUN apk add --no-cache autoconf
+RUN apk add --no-cache libtool
+RUN apk add --no-cache libcap-dev
+RUN apk add --no-cache pcre-dev
+RUN apk add --no-cache curl
+RUN apk add --no-cache build-base
+RUN apk add --no-cache ncurses-dev
+RUN apk add --no-cache tmux
+
+WORKDIR /zsh-autosuggestions
+
+ADD ZSH_VERSIONS /zsh-autosuggestions/ZSH_VERSIONS
+ADD install_test_zsh.sh /zsh-autosuggestions/install_test_zsh.sh
+RUN ./install_test_zsh.sh
+
+ADD Gemfile /zsh-autosuggestions/Gemfile
+ADD Gemfile.lock /zsh-autosuggestions/Gemfile.lock
+RUN bundle install
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Gemfile b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Gemfile
new file mode 100644
index 00000000..8b5deecf
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Gemfile
@@ -0,0 +1,5 @@
+source 'https://rubygems.org'
+
+gem 'rspec'
+gem 'rspec-wait'
+gem 'pry-byebug'
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Gemfile.lock b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Gemfile.lock
new file mode 100644
index 00000000..63ee778a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Gemfile.lock
@@ -0,0 +1,41 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ byebug (9.0.5)
+ coderay (1.1.1)
+ diff-lcs (1.3)
+ method_source (0.8.2)
+ pry (0.10.4)
+ coderay (~> 1.1.0)
+ method_source (~> 0.8.1)
+ slop (~> 3.4)
+ pry-byebug (3.4.0)
+ byebug (~> 9.0)
+ pry (~> 0.10)
+ rspec (3.5.0)
+ rspec-core (~> 3.5.0)
+ rspec-expectations (~> 3.5.0)
+ rspec-mocks (~> 3.5.0)
+ rspec-core (3.5.4)
+ rspec-support (~> 3.5.0)
+ rspec-expectations (3.5.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.5.0)
+ rspec-mocks (3.5.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.5.0)
+ rspec-support (3.5.0)
+ rspec-wait (0.0.9)
+ rspec (>= 3, < 4)
+ slop (3.6.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ pry-byebug
+ rspec
+ rspec-wait
+
+BUNDLED WITH
+ 1.13.6
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/INSTALL.md b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/INSTALL.md
new file mode 100644
index 00000000..196524fe
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/INSTALL.md
@@ -0,0 +1,64 @@
+# Installation
+
+* [Packages](#packages)
+* [Antigen](#antigen)
+* [Oh My Zsh](#oh-my-zsh)
+* [Manual](#manual-git-clone)
+
+## Packages
+
+| System | Package |
+| ------------- | ------------- |
+| Debian / Ubuntu | [zsh-autosuggestions OBS repository](https://software.opensuse.org/download.html?project=shells%3Azsh-users%3Azsh-autosuggestions&package=zsh-autosuggestions) |
+| Fedora / CentOS / RHEL / Scientific Linux | [zsh-autosuggestions OBS repository](https://software.opensuse.org/download.html?project=shells%3Azsh-users%3Azsh-autosuggestions&package=zsh-autosuggestions) |
+| OpenSUSE / SLE | [zsh-autosuggestions OBS repository](https://software.opensuse.org/download.html?project=shells%3Azsh-users%3Azsh-autosuggestions&package=zsh-autosuggestions) |
+| Arch Linux / Manjaro / Antergos / Hyperbola | [zsh-autosuggestions](https://www.archlinux.org/packages/zsh-autosuggestions), [zsh-autosuggestions-git](https://aur.archlinux.org/packages/zsh-autosuggestions-git) |
+| NixOS | [zsh-autosuggestions](https://github.com/NixOS/nixpkgs/blob/master/pkgs/shells/zsh/zsh-autosuggestions/default.nix) |
+| Void Linux | [zsh-autosuggestions](https://github.com/void-linux/void-packages/blob/master/srcpkgs/zsh-autosuggestions/template) |
+| Mac OS | [homebrew](https://github.com/Homebrew/homebrew-core/blob/master/Formula/zsh-autosuggestions.rb) |
+| NetBSD | [pkgsrc](http://ftp.netbsd.org/pub/pkgsrc/current/pkgsrc/shells/zsh-autosuggestions/README.html) |
+
+## Antigen
+
+1. Add the following to your `.zshrc`:
+
+ ```sh
+ antigen bundle zsh-users/zsh-autosuggestions
+ ```
+
+2. Start a new terminal session.
+
+## Oh My Zsh
+
+1. Clone this repository into `$ZSH_CUSTOM/plugins` (by default `~/.oh-my-zsh/custom/plugins`)
+
+ ```sh
+ git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
+ ```
+
+2. Add the plugin to the list of plugins for Oh My Zsh to load (inside `~/.zshrc`):
+
+ ```sh
+ plugins=(
+ # other plugins...
+ zsh-autosuggestions
+ )
+ ```
+
+3. Start a new terminal session.
+
+## Manual (Git Clone)
+
+1. Clone this repository somewhere on your machine. This guide will assume `~/.zsh/zsh-autosuggestions`.
+
+ ```sh
+ git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
+ ```
+
+2. Add the following to your `.zshrc`:
+
+ ```sh
+ source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
+ ```
+
+3. Start a new terminal session.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/LICENSE b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/LICENSE
new file mode 100644
index 00000000..7ea78cc6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2013 Thiago de Arruda
+Copyright (c) 2016-2021 Eric Freese
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Makefile b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Makefile
new file mode 100644
index 00000000..f6d13a77
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/Makefile
@@ -0,0 +1,35 @@
+SRC_DIR := ./src
+
+SRC_FILES := \
+ $(SRC_DIR)/config.zsh \
+ $(SRC_DIR)/util.zsh \
+ $(SRC_DIR)/bind.zsh \
+ $(SRC_DIR)/highlight.zsh \
+ $(SRC_DIR)/widgets.zsh \
+ $(SRC_DIR)/strategies/*.zsh \
+ $(SRC_DIR)/fetch.zsh \
+ $(SRC_DIR)/async.zsh \
+ $(SRC_DIR)/start.zsh
+
+HEADER_FILES := \
+ DESCRIPTION \
+ URL \
+ VERSION \
+ LICENSE
+
+PLUGIN_TARGET := zsh-autosuggestions.zsh
+
+all: $(PLUGIN_TARGET)
+
+$(PLUGIN_TARGET): $(HEADER_FILES) $(SRC_FILES)
+ cat $(HEADER_FILES) | sed -e 's/^/# /g' > $@
+ cat $(SRC_FILES) >> $@
+
+.PHONY: clean
+clean:
+ rm $(PLUGIN_TARGET)
+
+.PHONY: test
+test: all
+ @test -n "$$TEST_ZSH_BIN" && echo "Testing zsh binary: $(TEST_ZSH_BIN)" || true
+ bundle exec rspec $(TESTS)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/README.md b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/README.md
new file mode 100644
index 00000000..3cfd2e82
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/README.md
@@ -0,0 +1,191 @@
+# zsh-autosuggestions
+
+_[Fish](http://fishshell.com/)-like fast/unobtrusive autosuggestions for zsh._
+
+It suggests commands as you type based on history and completions.
+
+Requirements: Zsh v4.3.11 or later
+
+[![CircleCI](https://img.shields.io/circleci/build/github/zsh-users/zsh-autosuggestions.svg)](https://circleci.com/gh/zsh-users/zsh-autosuggestions)
+[![Chat on Gitter](https://img.shields.io/gitter/room/zsh-users/zsh-autosuggestions.svg)](https://gitter.im/zsh-users/zsh-autosuggestions)
+
+<a href="https://asciinema.org/a/37390" target="_blank"><img src="https://asciinema.org/a/37390.png" width="400" /></a>
+
+
+## Installation
+
+See [INSTALL.md](INSTALL.md).
+
+
+## Usage
+
+As you type commands, you will see a completion offered after the cursor in a muted gray color. This color can be changed by setting the `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` variable. See [configuration](#configuration).
+
+If you press the <kbd>→</kbd> key (`forward-char` widget) or <kbd>End</kbd> (`end-of-line` widget) with the cursor at the end of the buffer, it will accept the suggestion, replacing the contents of the command line buffer with the suggestion.
+
+If you invoke the `forward-word` widget, it will partially accept the suggestion up to the point that the cursor moves to.
+
+
+## Configuration
+
+You may want to override the default global config variables. Default values of these variables can be found [here](src/config.zsh).
+
+**Note:** If you are using Oh My Zsh, you can put this configuration in a file in the `$ZSH_CUSTOM` directory. See their comments on [overriding internals](https://github.com/robbyrussell/oh-my-zsh/wiki/Customization#overriding-internals).
+
+
+### Suggestion Highlight Style
+
+Set `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` to configure the style that the suggestion is shown with. The default is `fg=8`, which will set the foreground color to color 8 from the [256-color palette](https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg). If your terminal only supports 8 colors, you will need to use a number between 0 and 7.
+
+Background color can also be set, and the suggestion can be styled bold, underlined, or standout. For example, this would show suggestions with bold, underlined, pink text on a cyan background:
+
+```sh
+ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#ff00ff,bg=cyan,bold,underline"
+```
+
+For more info, read the Character Highlighting section of the zsh manual: `man zshzle` or [online](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting).
+
+**Note:** Some iTerm2 users have reported [not being able to see the suggestions](https://github.com/zsh-users/zsh-autosuggestions/issues/416#issuecomment-486516333). If this affects you, the problem is likely caused by incorrect color settings. In order to correct this, go into iTerm2's setting, navigate to profile > colors and make sure that the colors for Basic Colors > Background and ANSI Colors > Bright Black are **different**.
+
+
+### Suggestion Strategy
+
+`ZSH_AUTOSUGGEST_STRATEGY` is an array that specifies how suggestions should be generated. The strategies in the array are tried successively until a suggestion is found. There are currently three built-in strategies to choose from:
+
+- `history`: Chooses the most recent match from history.
+- `completion`: Chooses a suggestion based on what tab-completion would suggest. (requires `zpty` module)
+- `match_prev_cmd`: Like `history`, but chooses the most recent match whose preceding history item matches the most recently executed command ([more info](src/strategies/match_prev_cmd.zsh)). Note that this strategy won't work as expected with ZSH options that don't preserve the history order such as `HIST_IGNORE_ALL_DUPS` or `HIST_EXPIRE_DUPS_FIRST`.
+
+For example, setting `ZSH_AUTOSUGGEST_STRATEGY=(history completion)` will first try to find a suggestion from your history, but, if it can't find a match, will find a suggestion from the completion engine.
+
+
+### Widget Mapping
+
+This plugin works by triggering custom behavior when certain [zle widgets](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets) are invoked. You can add and remove widgets from these arrays to change the behavior of this plugin:
+
+- `ZSH_AUTOSUGGEST_CLEAR_WIDGETS`: Widgets in this array will clear the suggestion when invoked.
+- `ZSH_AUTOSUGGEST_ACCEPT_WIDGETS`: Widgets in this array will accept the suggestion when invoked.
+- `ZSH_AUTOSUGGEST_EXECUTE_WIDGETS`: Widgets in this array will execute the suggestion when invoked.
+- `ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS`: Widgets in this array will partially accept the suggestion when invoked.
+- `ZSH_AUTOSUGGEST_IGNORE_WIDGETS`: Widgets in this array will not trigger any custom behavior.
+
+Widgets that modify the buffer and are not found in any of these arrays will fetch a new suggestion after they are invoked.
+
+**Note:** A widget shouldn't belong to more than one of the above arrays.
+
+
+### Disabling suggestion for large buffers
+
+Set `ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE` to an integer value to disable autosuggestion for large buffers. The default is unset, which means that autosuggestion will be tried for any buffer size. Recommended value is 20.
+This can be useful when pasting large amount of text in the terminal, to avoid triggering autosuggestion for strings that are too long.
+
+### Asynchronous Mode
+
+Suggestions are fetched asynchronously by default in zsh versions 5.0.8 and greater. To disable asynchronous suggestions and fetch them synchronously instead, `unset ZSH_AUTOSUGGEST_USE_ASYNC` after sourcing the plugin.
+
+Alternatively, if you are using a version of zsh older than 5.0.8 and want to enable asynchronous mode, set the `ZSH_AUTOSUGGEST_USE_ASYNC` variable after sourcing the plugin (it can be set to anything). Note that there is [a bug](https://github.com/zsh-users/zsh-autosuggestions/issues/364#issuecomment-481423232) in versions of zsh older than 5.0.8 where <kbd>ctrl</kbd> + <kbd>c</kbd> will fail to reset the prompt immediately after fetching a suggestion asynchronously.
+
+### Disabling automatic widget re-binding
+
+Set `ZSH_AUTOSUGGEST_MANUAL_REBIND` (it can be set to anything) to disable automatic widget re-binding on each precmd. This can be a big boost to performance, but you'll need to handle re-binding yourself if any of the widget lists change or if you or another plugin wrap any of the autosuggest widgets. To re-bind widgets, run `_zsh_autosuggest_bind_widgets`.
+
+### Ignoring history suggestions that match a pattern
+
+Set `ZSH_AUTOSUGGEST_HISTORY_IGNORE` to a [glob pattern](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Operators) to prevent offering suggestions for history entries that match the pattern. For example, set it to `"cd *"` to never suggest any `cd` commands from history. Or set to `"?(#c50,)"` to never suggest anything 50 characters or longer.
+
+**Note:** This only affects the `history` and `match_prev_cmd` suggestion strategies.
+
+### Skipping completion suggestions for certain cases
+
+Set `ZSH_AUTOSUGGEST_COMPLETION_IGNORE` to a [glob pattern](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Operators) to prevent offering completion suggestions when the buffer matches that pattern. For example, set it to `"git *"` to disable completion suggestions for git subcommands.
+
+**Note:** This only affects the `completion` suggestion strategy.
+
+
+### Key Bindings
+
+This plugin provides a few widgets that you can use with `bindkey`:
+
+1. `autosuggest-accept`: Accepts the current suggestion.
+2. `autosuggest-execute`: Accepts and executes the current suggestion.
+3. `autosuggest-clear`: Clears the current suggestion.
+4. `autosuggest-fetch`: Fetches a suggestion (works even when suggestions are disabled).
+5. `autosuggest-disable`: Disables suggestions.
+6. `autosuggest-enable`: Re-enables suggestions.
+7. `autosuggest-toggle`: Toggles between enabled/disabled suggestions.
+
+For example, this would bind <kbd>ctrl</kbd> + <kbd>space</kbd> to accept the current suggestion.
+
+```sh
+bindkey '^ ' autosuggest-accept
+```
+
+
+## Troubleshooting
+
+If you have a problem, please search through [the list of issues on GitHub](https://github.com/zsh-users/zsh-autosuggestions/issues?q=) to see if someone else has already reported it.
+
+### Reporting an Issue
+
+Before reporting an issue, please try temporarily disabling sections of your configuration and other plugins that may be conflicting with this plugin to isolate the problem.
+
+When reporting an issue, please include:
+
+- The smallest, simplest `.zshrc` configuration that will reproduce the problem. See [this comment](https://github.com/zsh-users/zsh-autosuggestions/issues/102#issuecomment-180944764) for a good example of what this means.
+- The version of zsh you're using (`zsh --version`)
+- Which operating system you're running
+
+
+## Uninstallation
+
+1. Remove the code referencing this plugin from `~/.zshrc`.
+
+2. Remove the git repository from your hard drive
+
+ ```sh
+ rm -rf ~/.zsh/zsh-autosuggestions # Or wherever you installed
+ ```
+
+
+## Development
+
+### Build Process
+
+Edit the source files in `src/`. Run `make` to build `zsh-autosuggestions.zsh` from those source files.
+
+
+### Pull Requests
+
+Pull requests are welcome! If you send a pull request, please:
+
+- Request to merge into the `develop` branch (*NOT* `master`)
+- Match the existing coding conventions.
+- Include helpful comments to keep the barrier-to-entry low for people new to the project.
+- Write tests that cover your code as much as possible.
+
+
+### Testing
+
+Tests are written in ruby using the [`rspec`](http://rspec.info/) framework. They use [`tmux`](https://tmux.github.io/) to drive a pseudoterminal, sending simulated keystrokes and making assertions on the terminal content.
+
+Test files live in `spec/`. To run the tests, run `make test`. To run a specific test, run `TESTS=spec/some_spec.rb make test`. You can also specify a `zsh` binary to use by setting the `TEST_ZSH_BIN` environment variable (ex: `TEST_ZSH_BIN=/bin/zsh make test`).
+
+A docker image for testing is available [on docker hub](https://hub.docker.com/r/ericfreese/zsh-autosuggestions-test). It comes with ruby, the bundler dependencies, and all supported versions of zsh installed.
+
+Pull the docker image with:
+
+```sh
+docker pull ericfreese/zsh-autosuggestions-test
+```
+
+To run the tests for a specific version of zsh (where `<version>` below is substituted with the contents of a line from the [`ZSH_VERSIONS`](ZSH_VERSIONS) file):
+
+```sh
+docker run -it -e TEST_ZSH_BIN=zsh-<version> -v $PWD:/zsh-autosuggestions zsh-autosuggestions-test make test
+```
+
+
+## License
+
+This project is licensed under [MIT license](http://opensource.org/licenses/MIT).
+For the full text of the license, see the [LICENSE](LICENSE) file.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/URL b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/URL
new file mode 100644
index 00000000..4e2bd941
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/URL
@@ -0,0 +1 @@
+https://github.com/zsh-users/zsh-autosuggestions
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/VERSION b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/VERSION
new file mode 100644
index 00000000..8b20e485
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/VERSION
@@ -0,0 +1 @@
+v0.7.0
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/ZSH_VERSIONS b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/ZSH_VERSIONS
new file mode 100644
index 00000000..18ed7a62
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/ZSH_VERSIONS
@@ -0,0 +1,17 @@
+# Zsh releases to run tests against
+# See https://github.com/zsh-users/zsh/releases
+#
+# When modifying this file, rebuild and push docker image:
+# $ docker build -t ericfreese/zsh-autosuggestions-test .
+# $ docker push ericfreese/zsh-autosuggestions-test
+4.3.11
+5.0.2
+5.0.8
+5.1.1
+5.2
+5.3.1
+5.4.2
+5.5.1
+5.6.2
+5.7.1
+5.8
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/install_test_zsh.sh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/install_test_zsh.sh
new file mode 100755
index 00000000..40dc4c56
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/install_test_zsh.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+set -ex
+
+for v in $(grep "^[^#]" ZSH_VERSIONS); do
+ mkdir zsh-$v
+ cd zsh-$v
+
+ curl -L https://api.github.com/repos/zsh-users/zsh/tarball/zsh-$v | tar xz --strip=1
+
+ ./Util/preconfig
+ ./configure --enable-pcre \
+ --enable-cap \
+ --enable-multibyte \
+ --with-term-lib='ncursesw tinfo' \
+ --with-tcsetpgrp \
+ --program-suffix="-$v"
+
+ make install.bin
+ make install.modules
+ make install.fns
+
+ cd ..
+
+ rm -rf zsh-$v
+done
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/async_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/async_spec.rb
new file mode 100644
index 00000000..0af72329
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/async_spec.rb
@@ -0,0 +1,70 @@
+context 'with asynchronous suggestions enabled' do
+ let(:options) { ["ZSH_AUTOSUGGEST_USE_ASYNC="] }
+
+ describe '`up-line-or-beginning-search`' do
+ let(:before_sourcing) do
+ -> do
+ session.
+ run_command('autoload -U up-line-or-beginning-search').
+ run_command('zle -N up-line-or-beginning-search').
+ send_string('bindkey "').
+ send_keys('C-v').send_keys('up').
+ send_string('" up-line-or-beginning-search').
+ send_keys('enter')
+ end
+ end
+
+ it 'should show previous history entries' do
+ with_history(
+ 'echo foo',
+ 'echo bar',
+ 'echo baz'
+ ) do
+ session.clear_screen
+ 3.times { session.send_keys('up') }
+ wait_for { session.content }.to eq("echo foo")
+ end
+ end
+ end
+
+ describe '`copy-earlier-word`' do
+ let(:before_sourcing) do
+ -> do
+ session.
+ run_command('autoload -Uz copy-earlier-word').
+ run_command('zle -N copy-earlier-word').
+ run_command('bindkey "^N" copy-earlier-word')
+ end
+ end
+
+ it 'should cycle through previous words in the buffer' do
+ session.clear_screen
+ session.send_string('foo bar baz')
+ sleep 0.5
+ session.send_keys('C-n')
+ wait_for { session.content }.to eq('foo bar bazbaz')
+ session.send_keys('C-n')
+ wait_for { session.content }.to eq('foo bar bazbar')
+ session.send_keys('C-n')
+ wait_for { session.content }.to eq('foo bar bazfoo')
+ end
+ end
+
+ describe 'pressing ^C after fetching a suggestion' do
+ before do
+ skip 'Workaround does not work below v5.0.8' if session.zsh_version < Gem::Version.new('5.0.8')
+ end
+
+ it 'terminates the prompt and begins a new one' do
+ session.send_keys('e')
+ sleep 0.5
+ session.send_keys('C-c')
+ sleep 0.5
+ session.send_keys('echo')
+
+ wait_for { session.content }.to eq("e\necho")
+ end
+ end
+end
+
+
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/auto_cd_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/auto_cd_spec.rb
new file mode 100644
index 00000000..94bd24b0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/auto_cd_spec.rb
@@ -0,0 +1,14 @@
+describe 'with `AUTO_CD` option set' do
+ let(:after_sourcing) do
+ -> {
+ session.run_command('setopt AUTO_CD')
+ session.run_command('autoload compinit && compinit')
+ }
+ end
+
+ it 'directory names are still completed' do
+ session.send_string('sr')
+ session.send_keys('C-i')
+ wait_for { session.content }.to eq('src/')
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/bracketed_paste_magic_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/bracketed_paste_magic_spec.rb
new file mode 100644
index 00000000..41ff2676
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/bracketed_paste_magic_spec.rb
@@ -0,0 +1,43 @@
+describe 'pasting using bracketed-paste-magic' do
+ let(:before_sourcing) do
+ -> do
+ session.
+ run_command('autoload -Uz bracketed-paste-magic').
+ run_command('zle -N bracketed-paste bracketed-paste-magic')
+ end
+ end
+
+ context 'with suggestions disabled while pasting' do
+ before do
+ session.
+ run_command('bpm_init() { zle autosuggest-disable }').
+ run_command('bpm_finish() { zle autosuggest-enable }').
+ run_command('zstyle :bracketed-paste-magic paste-init bpm_init').
+ run_command('zstyle :bracketed-paste-magic paste-finish bpm_finish')
+ end
+
+ it 'does not show an incorrect suggestion' do
+ with_history('echo hello') do
+ session.paste_string("echo #{'a' * 60}")
+ sleep 1
+ expect(session.content).to eq("echo #{'a' * 60}")
+ end
+ end
+ end
+
+ context 'with `bracketed-paste` added to the list of widgets that clear the suggestion' do
+ let(:options) { ['ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste)'] }
+
+ it 'does not retain an old suggestion' do
+ with_history ('echo foo') do
+ session.send_string('echo ')
+ wait_for { session.content }.to eq('echo foo')
+ session.paste_string('bar')
+ wait_for { session.content }.to eq('echo bar')
+ session.send_keys('C-a') # Any cursor movement works
+ sleep 1
+ expect(session.content).to eq('echo bar')
+ end
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/client_zpty_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/client_zpty_spec.rb
new file mode 100644
index 00000000..b8abb375
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/client_zpty_spec.rb
@@ -0,0 +1,14 @@
+describe 'a running zpty command' do
+ let(:before_sourcing) { -> { session.run_command('zmodload zsh/zpty && zpty -b kitty cat') } }
+
+ context 'when using `completion` strategy' do
+ let(:options) { ["ZSH_AUTOSUGGEST_STRATEGY=completion"] }
+
+ it 'is not affected' do
+ session.send_keys('a').send_keys('C-h')
+ session.run_command('zpty -t kitty; echo $?')
+
+ wait_for { session.content }.to end_with("\n0")
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/glob_subst_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/glob_subst_spec.rb
new file mode 100644
index 00000000..c3dd671c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/glob_subst_spec.rb
@@ -0,0 +1,12 @@
+describe 'with `GLOB_SUBST` option set' do
+ let(:after_sourcing) do
+ -> {
+ session.run_command('setopt GLOB_SUBST')
+ }
+ end
+
+ it 'error messages are not printed' do
+ session.send_string('[[')
+ wait_for { session.content }.to eq('[[')
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/rebound_bracket_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/rebound_bracket_spec.rb
new file mode 100644
index 00000000..8b420f06
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/rebound_bracket_spec.rb
@@ -0,0 +1,13 @@
+describe 'rebinding [' do
+ context 'initialized before sourcing the plugin' do
+ before do
+ session.run_command("function [ { $commands[\\[] \"$@\" }")
+ session.clear_screen
+ end
+
+ it 'executes the custom behavior and the built-in behavior' do
+ session.send_string('asdf')
+ wait_for { session.content }.to eq('asdf')
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/vi_mode_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/vi_mode_spec.rb
new file mode 100644
index 00000000..0a295c23
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/vi_mode_spec.rb
@@ -0,0 +1,80 @@
+describe 'when using vi mode' do
+ let(:before_sourcing) do
+ -> do
+ session.run_command('bindkey -v')
+ end
+ end
+
+ describe 'moving the cursor after exiting insert mode' do
+ it 'should not clear the current suggestion' do
+ with_history('foobar foo') do
+ session.
+ send_string('foo').
+ send_keys('escape').
+ send_keys('h')
+
+ wait_for { session.content }.to eq('foobar foo')
+ end
+ end
+ end
+
+ describe '`vi-forward-word-end`' do
+ it 'should accept through the end of the current word' do
+ with_history('foobar foo') do
+ session.
+ send_string('foo').
+ send_keys('escape').
+ send_keys('e'). # vi-forward-word-end
+ send_keys('a'). # vi-add-next
+ send_string('baz')
+
+ wait_for { session.content }.to eq('foobarbaz')
+ end
+ end
+ end
+
+ describe '`vi-forward-word`' do
+ it 'should accept through the first character of the next word' do
+ with_history('foobar foo') do
+ session.
+ send_string('foo').
+ send_keys('escape').
+ send_keys('w'). # vi-forward-word
+ send_keys('a'). # vi-add-next
+ send_string('az')
+
+ wait_for { session.content }.to eq('foobar faz')
+ end
+ end
+ end
+
+ describe '`vi-find-next-char`' do
+ it 'should accept through the next occurrence of the character' do
+ with_history('foobar foo') do
+ session.
+ send_string('foo').
+ send_keys('escape').
+ send_keys('f'). # vi-find-next-char
+ send_keys('o').
+ send_keys('a'). # vi-add-next
+ send_string('b')
+
+ wait_for { session.content }.to eq('foobar fob')
+ end
+ end
+ end
+
+ describe '`vi-delete`' do
+ it 'should be able to remove the last character in the buffer' do
+ skip 'deleting last char did not work below zsh version 5.0.8' if session.zsh_version < Gem::Version.new('5.0.8')
+
+ session.
+ send_string('echo foo').
+ send_keys('escape').
+ send_keys('d').
+ send_keys('l')
+
+ wait_for { session.content }.to eq('echo fo')
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/wrapped_widget_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/wrapped_widget_spec.rb
new file mode 100644
index 00000000..61dfc2dc
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/wrapped_widget_spec.rb
@@ -0,0 +1,39 @@
+describe 'a wrapped widget' do
+ let(:widget) { 'backward-delete-char' }
+
+ context 'initialized before sourcing the plugin' do
+ let(:before_sourcing) do
+ -> do
+ session.
+ run_command("_orig_#{widget}() { zle .#{widget} }").
+ run_command("zle -N orig-#{widget} _orig_#{widget}").
+ run_command("#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }").
+ run_command("zle -N #{widget} #{widget}-magic")
+ end
+ end
+
+ it 'executes the custom behavior and the built-in behavior' do
+ with_history('foobar', 'foodar') do
+ session.send_string('food').send_keys('C-h')
+ wait_for { session.content }.to eq('foobar')
+ end
+ end
+ end
+
+ context 'initialized after sourcing the plugin' do
+ before do
+ session.
+ run_command("zle -N orig-#{widget} ${widgets[#{widget}]#*:}").
+ run_command("#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }").
+ run_command("zle -N #{widget} #{widget}-magic").
+ clear_screen
+ end
+
+ it 'executes the custom behavior and the built-in behavior' do
+ with_history('foobar', 'foodar') do
+ session.send_string('food').send_keys('C-h')
+ wait_for { session.content }.to eq('foobar')
+ end
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/zle_input_stack_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/zle_input_stack_spec.rb
new file mode 100644
index 00000000..12cfbc7b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/integrations/zle_input_stack_spec.rb
@@ -0,0 +1,24 @@
+describe 'using `zle -U`' do
+ let(:before_sourcing) do
+ -> do
+ session.
+ run_command('_zsh_autosuggest_strategy_test() { sleep 1; _zsh_autosuggest_strategy_history "$1" }').
+ run_command('foo() { zle -U - "echo hello" }; zle -N foo; bindkey ^B foo')
+ end
+ end
+
+ let(:options) { ['unset ZSH_AUTOSUGGEST_USE_ASYNC', 'ZSH_AUTOSUGGEST_STRATEGY=test'] }
+
+ # TODO: This is only possible with the $KEYS_QUEUED_COUNT widget parameter, coming soon...
+ xit 'does not fetch a suggestion for every inserted character' do
+ session.send_keys('C-b')
+ wait_for { session.content }.to eq('echo hello')
+ end
+
+ it 'shows a suggestion when the widget completes' do
+ with_history('echo hello world') do
+ session.send_keys('C-b')
+ wait_for { session.content(esc_seqs: true) }.to match(/\Aecho hello\e\[[0-9]+m world/)
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/kill_ring_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/kill_ring_spec.rb
new file mode 100644
index 00000000..4d0178f9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/kill_ring_spec.rb
@@ -0,0 +1,23 @@
+context 'with some items in the kill ring' do
+ before do
+ session.
+ send_string('echo foo').
+ send_keys('C-u').
+ send_string('echo bar').
+ send_keys('C-u')
+ end
+
+ describe '`yank-pop`' do
+ it 'should cycle through all items in the kill ring' do
+ session.send_keys('C-y')
+ wait_for { session.content }.to eq('echo bar')
+
+ session.send_keys('escape').send_keys('y')
+ wait_for { session.content }.to eq('echo foo')
+
+ session.send_keys('escape').send_keys('y')
+ wait_for { session.content }.to eq('echo bar')
+ end
+ end
+end
+
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/line_init_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/line_init_spec.rb
new file mode 100644
index 00000000..826277fc
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/line_init_spec.rb
@@ -0,0 +1,17 @@
+context 'with zle-line-init unignored' do
+ let(:after_sourcing) do
+ -> do
+ session.
+ run_command('setopt extendedglob').
+ run_command('ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(${(@)ZSH_AUTOSUGGEST_IGNORE_WIDGETS:#zle-\*} zle-\^line-init)').
+ run_command('zle-line-init() { BUFFER="echo" }')
+ end
+ end
+
+ it 'should fetch a suggestion on each line initialization' do
+ with_history('echo foo') do
+ session.run_command('zle -N zle-line-init')
+ wait_for { session.content }.to end_with('echo foo')
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/multi_line_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/multi_line_spec.rb
new file mode 100644
index 00000000..364780a2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/multi_line_spec.rb
@@ -0,0 +1,8 @@
+describe 'a multi-line suggestion' do
+ it 'should be displayed on multiple lines' do
+ with_history("echo \"\n\"") do
+ session.send_keys('e')
+ wait_for { session.content }.to eq("echo \"\n\"")
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/buffer_max_size_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/buffer_max_size_spec.rb
new file mode 100644
index 00000000..29ca8bc4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/buffer_max_size_spec.rb
@@ -0,0 +1,30 @@
+describe 'a suggestion' do
+ let(:term_opts) { { width: 200 } }
+ let(:long_command) { "echo #{'a' * 100}" }
+
+ around do |example|
+ with_history(long_command) { example.run }
+ end
+
+ it 'is provided for any buffer length' do
+ session.send_string(long_command[0...-1])
+ wait_for { session.content }.to eq(long_command)
+ end
+
+ context 'when ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE is specified' do
+ let(:buffer_max_size) { 10 }
+ let(:options) { ["ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=#{buffer_max_size}"] }
+
+ it 'is provided when the buffer is shorter than the specified length' do
+ session.send_string(long_command[0...(buffer_max_size - 1)])
+ wait_for { session.content }.to eq(long_command)
+ end
+
+ it 'is provided when the buffer is equal to the specified length' do
+ session.send_string(long_command[0...(buffer_max_size)])
+ wait_for { session.content }.to eq(long_command)
+ end
+
+ it 'is not provided when the buffer is longer than the specified length'
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/highlight_style_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/highlight_style_spec.rb
new file mode 100644
index 00000000..a7e39b34
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/highlight_style_spec.rb
@@ -0,0 +1,7 @@
+describe 'a displayed suggestion' do
+ it 'is shown in the default style'
+
+ describe 'when ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE is set to a zle_highlight string' do
+ it 'is shown in the specified style'
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/original_widget_prefix_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/original_widget_prefix_spec.rb
new file mode 100644
index 00000000..a4b6e983
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/original_widget_prefix_spec.rb
@@ -0,0 +1,7 @@
+describe 'an original zle widget' do
+ context 'is accessible with the default prefix'
+
+ context 'when ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX is set' do
+ it 'is accessible with the specified prefix'
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/strategy_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/strategy_spec.rb
new file mode 100644
index 00000000..58562d0c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/strategy_spec.rb
@@ -0,0 +1,55 @@
+describe 'a suggestion for a given prefix' do
+ let(:history_strategy) { '_zsh_autosuggest_strategy_history() { suggestion="history" }' }
+ let(:foobar_strategy) { '_zsh_autosuggest_strategy_foobar() { [[ "foobar baz" = $1* ]] && suggestion="foobar baz" }' }
+ let(:foobaz_strategy) { '_zsh_autosuggest_strategy_foobaz() { [[ "foobaz bar" = $1* ]] && suggestion="foobaz bar" }' }
+
+ let(:after_sourcing) do
+ -> do
+ session.run_command(history_strategy)
+ end
+ end
+
+ it 'by default is determined by calling the `history` strategy function' do
+ session.send_string('h')
+ wait_for { session.content }.to eq('history')
+ end
+
+ context 'when ZSH_AUTOSUGGEST_STRATEGY is set to an array' do
+ let(:after_sourcing) do
+ -> do
+ session.
+ run_command(foobar_strategy).
+ run_command(foobaz_strategy).
+ run_command('ZSH_AUTOSUGGEST_STRATEGY=(foobar foobaz)')
+ end
+ end
+
+ it 'is determined by the first strategy function to return a suggestion' do
+ session.send_string('foo')
+ wait_for { session.content }.to eq('foobar baz')
+
+ session.send_string('baz')
+ wait_for { session.content }.to eq('foobaz bar')
+ end
+ end
+
+ context 'when ZSH_AUTOSUGGEST_STRATEGY is set to a string' do
+ let(:after_sourcing) do
+ -> do
+ session.
+ run_command(foobar_strategy).
+ run_command(foobaz_strategy).
+ run_command('ZSH_AUTOSUGGEST_STRATEGY="foobar foobaz"')
+ end
+ end
+
+ it 'is determined by the first strategy function to return a suggestion' do
+ session.send_string('foo')
+ wait_for { session.content }.to eq('foobar baz')
+
+ session.send_string('baz')
+ wait_for { session.content }.to eq('foobaz bar')
+ end
+ end
+end
+
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/widget_lists_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/widget_lists_spec.rb
new file mode 100644
index 00000000..421b84e4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/options/widget_lists_spec.rb
@@ -0,0 +1,121 @@
+describe 'a zle widget' do
+ let(:widget) { 'my-widget' }
+ let(:before_sourcing) { -> { session.run_command("#{widget}() {}; zle -N #{widget}; bindkey ^B #{widget}") } }
+
+ context 'when added to ZSH_AUTOSUGGEST_ACCEPT_WIDGETS' do
+ let(:options) { ["ZSH_AUTOSUGGEST_ACCEPT_WIDGETS+=(#{widget})"] }
+
+ it 'accepts the suggestion and moves the cursor to the end of the buffer when invoked' do
+ with_history('echo hello') do
+ session.send_string('e')
+ wait_for { session.content }.to eq('echo hello')
+ session.send_keys('C-b')
+ wait_for { session.content(esc_seqs: true) }.to eq('echo hello')
+ wait_for { session.cursor }.to eq([10, 0])
+ end
+ end
+ end
+
+ context 'when added to ZSH_AUTOSUGGEST_CLEAR_WIDGETS' do
+ let(:options) { ["ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(#{widget})"] }
+
+ it 'clears the suggestion when invoked' do
+ with_history('echo hello') do
+ session.send_string('e')
+ wait_for { session.content }.to eq('echo hello')
+ session.send_keys('C-b')
+ wait_for { session.content }.to eq('e')
+ end
+ end
+ end
+
+ context 'when added to ZSH_AUTOSUGGEST_EXECUTE_WIDGETS' do
+ let(:options) { ["ZSH_AUTOSUGGEST_EXECUTE_WIDGETS+=(#{widget})"] }
+
+ it 'executes the suggestion when invoked' do
+ with_history('echo hello') do
+ session.send_string('e')
+ wait_for { session.content }.to eq('echo hello')
+ session.send_keys('C-b')
+ wait_for { session.content }.to end_with("\nhello")
+ end
+ end
+ end
+
+ context 'when added to ZSH_AUTOSUGGEST_IGNORE_WIDGETS' do
+ let(:options) { ["ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(#{widget})"] }
+
+ it 'should not be wrapped with an autosuggest widget' do
+ session.run_command("echo $widgets[#{widget}]")
+ wait_for { session.content }.to end_with("\nuser:#{widget}")
+ end
+ end
+
+ context 'that moves the cursor forward' do
+ before { session.run_command("#{widget}() { zle forward-char }") }
+
+ context 'when added to ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS' do
+ let(:options) { ["ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(#{widget})"] }
+
+ it 'accepts the suggestion as far as the cursor is moved when invoked' do
+ with_history('echo hello') do
+ session.send_string('e')
+ wait_for { session.content }.to start_with('echo hello')
+ session.send_keys('C-b')
+ wait_for { session.content(esc_seqs: true) }.to match(/\Aec\e\[[0-9]+mho hello/)
+ end
+ end
+ end
+ end
+
+ context 'that modifies the buffer' do
+ before { session.run_command("#{widget}() { BUFFER=\"foo\" }") }
+
+ context 'when not added to any of the widget lists' do
+ it 'modifies the buffer and fetches a new suggestion' do
+ with_history('foobar') do
+ session.send_keys('C-b')
+ wait_for { session.content }.to eq('foobar')
+ end
+ end
+ end
+ end
+end
+
+describe 'a modification to the widget lists' do
+ let(:widget) { 'my-widget' }
+ let(:before_sourcing) { -> { session.run_command("#{widget}() {}; zle -N #{widget}; bindkey ^B #{widget}") } }
+ before { session.run_command("ZSH_AUTOSUGGEST_ACCEPT_WIDGETS+=(#{widget})") }
+
+ it 'takes effect on the next cmd line' do
+ with_history('echo hello') do
+ session.send_string('e')
+ wait_for { session.content }.to eq('echo hello')
+ session.send_keys('C-b')
+ wait_for { session.content(esc_seqs: true) }.to eq('echo hello')
+ end
+ end
+
+ context 'when manual rebind is enabled' do
+ let(:options) { ["ZSH_AUTOSUGGEST_MANUAL_REBIND=true"] }
+
+ it 'does not take effect until bind command is re-run' do
+ with_history('echo hello') do
+ session.send_string('e')
+ wait_for { session.content }.to eq('echo hello')
+ session.send_keys('C-b')
+ sleep 1
+ expect(session.content(esc_seqs: true)).not_to eq('echo hello')
+
+ session.send_keys('C-c')
+ session.run_command('_zsh_autosuggest_bind_widgets').clear_screen
+ wait_for { session.content }.to eq('')
+
+ session.send_string('e')
+ wait_for { session.content }.to eq('echo hello')
+ session.send_keys('C-b')
+ wait_for { session.content(esc_seqs: true) }.to eq('echo hello')
+ end
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/spec_helper.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/spec_helper.rb
new file mode 100644
index 00000000..dc1abb0a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/spec_helper.rb
@@ -0,0 +1,54 @@
+require 'pry'
+require 'rspec/wait'
+require 'terminal_session'
+require 'tempfile'
+
+RSpec.shared_context 'terminal session' do
+ let(:term_opts) { {} }
+ let(:session) { TerminalSession.new(term_opts) }
+ let(:before_sourcing) { -> {} }
+ let(:after_sourcing) { -> {} }
+ let(:options) { [] }
+
+ around do |example|
+ before_sourcing.call
+ session.run_command(['source zsh-autosuggestions.zsh', *options].join('; '))
+ after_sourcing.call
+ session.clear_screen
+
+ example.run
+
+ session.destroy
+ end
+
+ def with_history(*commands, &block)
+ Tempfile.create do |f|
+ f.write(commands.map{|c| c.gsub("\n", "\\\n")}.join("\n"))
+ f.flush
+
+ session.run_command('fc -p')
+ session.run_command("fc -R #{f.path}")
+
+ session.clear_screen
+
+ yield block
+
+ session.send_keys('C-c')
+ session.run_command('fc -P')
+ end
+ end
+end
+
+RSpec.configure do |config|
+ config.expect_with :rspec do |expectations|
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+ end
+
+ config.mock_with :rspec do |mocks|
+ mocks.verify_partial_doubles = true
+ end
+
+ config.wait_timeout = 2
+
+ config.include_context 'terminal session'
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/completion_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/completion_spec.rb
new file mode 100644
index 00000000..92794d6a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/completion_spec.rb
@@ -0,0 +1,72 @@
+describe 'the `completion` suggestion strategy' do
+ let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=completion'] }
+ let(:before_sourcing) do
+ -> do
+ session.
+ run_command('autoload compinit && compinit').
+ run_command('_foo() { compadd bar; compadd bat }').
+ run_command('_num() { compadd two; compadd three }').
+ run_command('compdef _foo baz').
+ run_command('compdef _num one')
+ end
+ end
+
+ it 'suggests the first completion result' do
+ session.send_string('baz ')
+ wait_for { session.content }.to eq('baz bar')
+ end
+
+ it 'does not add extra carriage returns when prefix has a line feed' do
+ skip '`stty` does not work inside zpty below zsh version 5.0.3' if session.zsh_version < Gem::Version.new('5.0.3')
+ session.send_string('baz \\').send_keys('C-v', 'C-j')
+ wait_for { session.content }.to eq("baz \\\nbar")
+ end
+
+ context 'when `_complete` is aliased' do
+ let(:before_sourcing) do
+ -> do
+ session.
+ run_command('autoload compinit && compinit').
+ run_command('_foo() { compadd bar; compadd bat }').
+ run_command('compdef _foo baz').
+ run_command('alias _complete=_complete')
+ end
+ end
+
+ it 'suggests the first completion result' do
+ session.send_string('baz ')
+ wait_for { session.content }.to eq('baz bar')
+ end
+ end
+
+ context 'when ZSH_AUTOSUGGEST_COMPLETION_IGNORE is set to a pattern' do
+ let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=completion', 'ZSH_AUTOSUGGEST_COMPLETION_IGNORE="one *"'] }
+
+ it 'makes suggestions when the buffer does not match the pattern' do
+ session.send_string('baz ')
+ wait_for { session.content }.to eq('baz bar')
+ end
+
+ it 'does not make suggestions when the buffer matches the pattern' do
+ session.send_string('one t')
+ sleep 1
+ expect(session.content).to eq('one t')
+ end
+ end
+
+ context 'when async mode is enabled' do
+ let(:options) { ['ZSH_AUTOSUGGEST_USE_ASYNC=true', 'ZSH_AUTOSUGGEST_STRATEGY=completion'] }
+
+ it 'suggests the first completion result' do
+ session.send_string('baz ')
+ wait_for { session.content }.to eq('baz bar')
+ end
+
+ it 'does not add extra carriage returns when prefix has a line feed' do
+ skip '`stty` does not work inside zpty below zsh version 5.0.3' if session.zsh_version < Gem::Version.new('5.0.3')
+ session.send_string('baz \\').send_keys('C-v', 'C-j')
+ wait_for { session.content }.to eq("baz \\\nbar")
+ end
+ end
+end
+
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/history_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/history_spec.rb
new file mode 100644
index 00000000..eee8efdf
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/history_spec.rb
@@ -0,0 +1,23 @@
+require 'strategies/special_characters_helper'
+
+describe 'the `history` suggestion strategy' do
+ it 'suggests the last matching history entry' do
+ with_history('ls foo', 'ls bar', 'echo baz') do
+ session.send_string('ls')
+ wait_for { session.content }.to eq('ls bar')
+ end
+ end
+
+ context 'when ZSH_AUTOSUGGEST_HISTORY_IGNORE is set to a pattern' do
+ let(:options) { ['ZSH_AUTOSUGGEST_HISTORY_IGNORE="* bar"'] }
+
+ it 'does not make suggestions that match the pattern' do
+ with_history('ls foo', 'ls bar', 'echo baz') do
+ session.send_string('ls')
+ wait_for { session.content }.to eq('ls foo')
+ end
+ end
+ end
+
+ include_examples 'special characters'
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/match_prev_cmd_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/match_prev_cmd_spec.rb
new file mode 100644
index 00000000..c435f162
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/match_prev_cmd_spec.rb
@@ -0,0 +1,34 @@
+require 'strategies/special_characters_helper'
+
+describe 'the `match_prev_cmd` strategy' do
+ let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd'] }
+
+ let(:history) { [
+ 'echo what',
+ 'ls foo',
+ 'echo what',
+ 'ls bar',
+ 'ls baz',
+ 'echo what'
+ ] }
+
+ it 'suggests the last matching history entry after the previous command' do
+ with_history(*history) do
+ session.send_string('ls')
+ wait_for { session.content }.to eq('ls bar')
+ end
+ end
+
+ context 'when ZSH_AUTOSUGGEST_HISTORY_IGNORE is set to a pattern' do
+ let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd', 'ZSH_AUTOSUGGEST_HISTORY_IGNORE="* bar"'] }
+
+ it 'does not make suggestions that match the pattern' do
+ with_history(*history) do
+ session.send_string('ls')
+ wait_for { session.content }.to eq('ls foo')
+ end
+ end
+ end
+
+ include_examples 'special characters'
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/special_characters_helper.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/special_characters_helper.rb
new file mode 100644
index 00000000..eb1f0cdd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/strategies/special_characters_helper.rb
@@ -0,0 +1,75 @@
+shared_examples 'special characters' do
+ describe 'a special character in the buffer should be treated like any other character' do
+ it 'asterisk' do
+ with_history('echo "hello*"', 'echo "hello."') do
+ session.send_string('echo "hello*')
+ wait_for { session.content }.to eq('echo "hello*"')
+ end
+ end
+
+ it 'question mark' do
+ with_history('echo "hello?"', 'echo "hello."') do
+ session.send_string('echo "hello?')
+ wait_for { session.content }.to eq('echo "hello?"')
+ end
+ end
+
+ it 'backslash' do
+ with_history('echo "hello\nworld"') do
+ session.send_string('echo "hello\\')
+ wait_for { session.content }.to eq('echo "hello\nworld"')
+ end
+ end
+
+ it 'double backslash' do
+ with_history('echo "\\\\"') do
+ session.send_string('echo "\\\\')
+ wait_for { session.content }.to eq('echo "\\\\"')
+ end
+ end
+
+ it 'tilde' do
+ with_history('echo ~/foo') do
+ session.send_string('echo ~')
+ wait_for { session.content }.to eq('echo ~/foo')
+ end
+ end
+
+ it 'parentheses' do
+ with_history('echo "$(ls foo)"') do
+ session.send_string('echo "$(')
+ wait_for { session.content }.to eq('echo "$(ls foo)"')
+ end
+ end
+
+ it 'square bracket' do
+ with_history('echo "$history[123]"') do
+ session.send_string('echo "$history[')
+ wait_for { session.content }.to eq('echo "$history[123]"')
+ session.send_string('123]')
+ wait_for { session.content }.to eq('echo "$history[123]"')
+ end
+ end
+
+ it 'octothorpe' do
+ with_history('echo "#yolo"') do
+ session.send_string('echo "#')
+ wait_for { session.content }.to eq('echo "#yolo"')
+ end
+ end
+
+ it 'caret' do
+ with_history('echo "^A"', 'echo "^B"') do
+ session.send_string('echo "^A')
+ wait_for { session.content }.to eq('echo "^A"')
+ end
+ end
+
+ it 'dash' do
+ with_history('-foo() {}') do
+ session.send_string('-')
+ wait_for { session.content }.to eq('-foo() {}')
+ end
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/terminal_session.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/terminal_session.rb
new file mode 100644
index 00000000..f91ee6cd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/terminal_session.rb
@@ -0,0 +1,99 @@
+require 'securerandom'
+
+class TerminalSession
+ ZSH_BIN = ENV['TEST_ZSH_BIN'] || 'zsh'
+
+ def initialize(opts = {})
+ opts = {
+ width: 80,
+ height: 24,
+ prompt: '',
+ term: 'xterm-256color',
+ zsh_bin: ZSH_BIN
+ }.merge(opts)
+
+ @opts = opts
+
+ cmd="PS1=\"#{opts[:prompt]}\" TERM=#{opts[:term]} #{ZSH_BIN} -f"
+ tmux_command("new-session -d -x #{opts[:width]} -y #{opts[:height]} '#{cmd}'")
+ end
+
+ def zsh_version
+ @zsh_version ||= Gem::Version.new(`#{ZSH_BIN} -c 'echo -n $ZSH_VERSION'`)
+ end
+
+ def tmux_socket_name
+ @tmux_socket_name ||= SecureRandom.hex(6)
+ end
+
+ def run_command(command)
+ send_string(command)
+ send_keys('enter')
+
+ self
+ end
+
+ def send_string(str)
+ tmux_command("send-keys -t 0 -l -- '#{str.gsub("'", "\\'")}'")
+
+ self
+ end
+
+ def send_keys(*keys)
+ tmux_command("send-keys -t 0 #{keys.join(' ')}")
+
+ self
+ end
+
+ def paste_string(str)
+ tmux_command("set-buffer -- '#{str}'")
+ tmux_command("paste-buffer -dpr -t 0")
+
+ self
+ end
+
+ def content(esc_seqs: false)
+ cmd = 'capture-pane -p -t 0'
+ cmd += ' -e' if esc_seqs
+ tmux_command(cmd).strip
+ end
+
+ def clear_screen
+ send_keys('C-l')
+
+ i = 0
+ until content == opts[:prompt] || i > 20 do
+ sleep(0.1)
+ i = i + 1
+ end
+
+ self
+ end
+
+ def destroy
+ tmux_command('kill-session')
+ end
+
+ def cursor
+ tmux_command("display-message -t 0 -p '\#{cursor_x},\#{cursor_y}'").
+ strip.
+ split(',').
+ map(&:to_i)
+ end
+
+ def attach!
+ tmux_command('attach-session')
+ end
+
+ private
+
+ attr_reader :opts
+
+ def tmux_command(cmd)
+ out = `tmux -u -L #{tmux_socket_name} #{cmd}`
+
+ raise("tmux error running: '#{cmd}'") unless $?.success?
+
+ out
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/disable_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/disable_spec.rb
new file mode 100644
index 00000000..b387a590
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/disable_spec.rb
@@ -0,0 +1,19 @@
+describe 'the `autosuggest-disable` widget' do
+ before do
+ session.run_command('bindkey ^B autosuggest-disable')
+ end
+
+ it 'disables suggestions and clears the suggestion' do
+ with_history('echo hello') do
+ session.send_string('echo')
+ wait_for { session.content }.to eq('echo hello')
+
+ session.send_keys('C-b')
+ wait_for { session.content }.to eq('echo')
+
+ session.send_string(' h')
+ sleep 1
+ expect(session.content).to eq('echo h')
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/enable_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/enable_spec.rb
new file mode 100644
index 00000000..3ad35a8c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/enable_spec.rb
@@ -0,0 +1,42 @@
+describe 'the `autosuggest-enable` widget' do
+ before do
+ session.
+ run_command('typeset -g _ZSH_AUTOSUGGEST_DISABLED').
+ run_command('bindkey ^B autosuggest-enable')
+ end
+
+ it 'enables suggestions and fetches a suggestion' do
+ with_history('echo hello') do
+ session.send_string('e')
+ sleep 1
+ expect(session.content).to eq('e')
+
+ session.send_keys('C-b')
+ session.send_string('c')
+ wait_for { session.content }.to eq('echo hello')
+ end
+ end
+
+ context 'invoked on an empty buffer' do
+ it 'does not fetch a suggestion' do
+ with_history('echo hello') do
+ session.send_keys('C-b')
+ sleep 1
+ expect(session.content).to eq('')
+ end
+ end
+ end
+
+ context 'invoked on a non-empty buffer' do
+ it 'fetches a suggestion' do
+ with_history('echo hello') do
+ session.send_string('e')
+ sleep 1
+ expect(session.content).to eq('e')
+
+ session.send_keys('C-b')
+ wait_for { session.content }.to eq('echo hello')
+ end
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/fetch_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/fetch_spec.rb
new file mode 100644
index 00000000..eb8f2ba5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/fetch_spec.rb
@@ -0,0 +1,24 @@
+describe 'the `autosuggest-fetch` widget' do
+ context 'when suggestions are disabled' do
+ before do
+ session.
+ run_command('bindkey ^B autosuggest-disable').
+ run_command('bindkey ^F autosuggest-fetch').
+ send_keys('C-b')
+ end
+
+ it 'will fetch and display a suggestion' do
+ with_history('echo hello') do
+ session.send_string('echo h')
+ sleep 1
+ expect(session.content).to eq('echo h')
+
+ session.send_keys('C-f')
+ wait_for { session.content }.to eq('echo hello')
+
+ session.send_string('e')
+ wait_for { session.content }.to eq('echo hello')
+ end
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/toggle_spec.rb b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/toggle_spec.rb
new file mode 100644
index 00000000..8f9f3c3d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/spec/widgets/toggle_spec.rb
@@ -0,0 +1,26 @@
+describe 'the `autosuggest-toggle` widget' do
+ before do
+ session.run_command('bindkey ^B autosuggest-toggle')
+ end
+
+ it 'toggles suggestions' do
+ with_history('echo world', 'echo hello') do
+ session.send_string('echo')
+ wait_for { session.content }.to eq('echo hello')
+
+ session.send_keys('C-b')
+ wait_for { session.content }.to eq('echo')
+
+ session.send_string(' h')
+ sleep 1
+ expect(session.content).to eq('echo h')
+
+ session.send_keys('C-b')
+ wait_for { session.content }.to eq('echo hello')
+
+ session.send_keys('C-h')
+ session.send_string('w')
+ wait_for { session.content }.to eq('echo world')
+ end
+ end
+end
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/async.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/async.zsh
new file mode 100644
index 00000000..218eb269
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/async.zsh
@@ -0,0 +1,76 @@
+
+#--------------------------------------------------------------------#
+# Async #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_async_request() {
+ zmodload zsh/system 2>/dev/null # For `$sysparams`
+
+ typeset -g _ZSH_AUTOSUGGEST_ASYNC_FD _ZSH_AUTOSUGGEST_CHILD_PID
+
+ # If we've got a pending request, cancel it
+ if [[ -n "$_ZSH_AUTOSUGGEST_ASYNC_FD" ]] && { true <&$_ZSH_AUTOSUGGEST_ASYNC_FD } 2>/dev/null; then
+ # Close the file descriptor and remove the handler
+ exec {_ZSH_AUTOSUGGEST_ASYNC_FD}<&-
+ zle -F $_ZSH_AUTOSUGGEST_ASYNC_FD
+
+ # We won't know the pid unless the user has zsh/system module installed
+ if [[ -n "$_ZSH_AUTOSUGGEST_CHILD_PID" ]]; then
+ # Zsh will make a new process group for the child process only if job
+ # control is enabled (MONITOR option)
+ if [[ -o MONITOR ]]; then
+ # Send the signal to the process group to kill any processes that may
+ # have been forked by the suggestion strategy
+ kill -TERM -$_ZSH_AUTOSUGGEST_CHILD_PID 2>/dev/null
+ else
+ # Kill just the child process since it wasn't placed in a new process
+ # group. If the suggestion strategy forked any child processes they may
+ # be orphaned and left behind.
+ kill -TERM $_ZSH_AUTOSUGGEST_CHILD_PID 2>/dev/null
+ fi
+ fi
+ fi
+
+ # Fork a process to fetch a suggestion and open a pipe to read from it
+ exec {_ZSH_AUTOSUGGEST_ASYNC_FD}< <(
+ # Tell parent process our pid
+ echo $sysparams[pid]
+
+ # Fetch and print the suggestion
+ local suggestion
+ _zsh_autosuggest_fetch_suggestion "$1"
+ echo -nE "$suggestion"
+ )
+
+ # There's a weird bug here where ^C stops working unless we force a fork
+ # See https://github.com/zsh-users/zsh-autosuggestions/issues/364
+ autoload -Uz is-at-least
+ is-at-least 5.8 || command true
+
+ # Read the pid from the child process
+ read _ZSH_AUTOSUGGEST_CHILD_PID <&$_ZSH_AUTOSUGGEST_ASYNC_FD
+
+ # When the fd is readable, call the response handler
+ zle -F "$_ZSH_AUTOSUGGEST_ASYNC_FD" _zsh_autosuggest_async_response
+}
+
+# Called when new data is ready to be read from the pipe
+# First arg will be fd ready for reading
+# Second arg will be passed in case of error
+_zsh_autosuggest_async_response() {
+ emulate -L zsh
+
+ local suggestion
+
+ if [[ -z "$2" || "$2" == "hup" ]]; then
+ # Read everything from the fd and give it as a suggestion
+ IFS='' read -rd '' -u $1 suggestion
+ zle autosuggest-suggest -- "$suggestion"
+
+ # Close the fd
+ exec {1}<&-
+ fi
+
+ # Always remove the handler
+ zle -F "$1"
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/bind.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/bind.zsh
new file mode 100644
index 00000000..1dde137c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/bind.zsh
@@ -0,0 +1,106 @@
+
+#--------------------------------------------------------------------#
+# Widget Helpers #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_incr_bind_count() {
+ typeset -gi bind_count=$((_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]+1))
+ _ZSH_AUTOSUGGEST_BIND_COUNTS[$1]=$bind_count
+}
+
+# Bind a single widget to an autosuggest widget, saving a reference to the original widget
+_zsh_autosuggest_bind_widget() {
+ typeset -gA _ZSH_AUTOSUGGEST_BIND_COUNTS
+
+ local widget=$1
+ local autosuggest_action=$2
+ local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX
+
+ local -i bind_count
+
+ # Save a reference to the original widget
+ case $widgets[$widget] in
+ # Already bound
+ user:_zsh_autosuggest_(bound|orig)_*)
+ bind_count=$((_ZSH_AUTOSUGGEST_BIND_COUNTS[$widget]))
+ ;;
+
+ # User-defined widget
+ user:*)
+ _zsh_autosuggest_incr_bind_count $widget
+ zle -N $prefix$bind_count-$widget ${widgets[$widget]#*:}
+ ;;
+
+ # Built-in widget
+ builtin)
+ _zsh_autosuggest_incr_bind_count $widget
+ eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }"
+ zle -N $prefix$bind_count-$widget _zsh_autosuggest_orig_$widget
+ ;;
+
+ # Completion widget
+ completion:*)
+ _zsh_autosuggest_incr_bind_count $widget
+ eval "zle -C $prefix$bind_count-${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}"
+ ;;
+ esac
+
+ # Pass the original widget's name explicitly into the autosuggest
+ # function. Use this passed in widget name to call the original
+ # widget instead of relying on the $WIDGET variable being set
+ # correctly. $WIDGET cannot be trusted because other plugins call
+ # zle without the `-w` flag (e.g. `zle self-insert` instead of
+ # `zle self-insert -w`).
+ eval "_zsh_autosuggest_bound_${bind_count}_${(q)widget}() {
+ _zsh_autosuggest_widget_$autosuggest_action $prefix$bind_count-${(q)widget} \$@
+ }"
+
+ # Create the bound widget
+ zle -N -- $widget _zsh_autosuggest_bound_${bind_count}_$widget
+}
+
+# Map all configured widgets to the right autosuggest widgets
+_zsh_autosuggest_bind_widgets() {
+ emulate -L zsh
+
+ local widget
+ local ignore_widgets
+
+ ignore_widgets=(
+ .\*
+ _\*
+ ${_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS/#/autosuggest-}
+ $ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
+ $ZSH_AUTOSUGGEST_IGNORE_WIDGETS
+ )
+
+ # Find every widget we might want to bind and bind it appropriately
+ for widget in ${${(f)"$(builtin zle -la)"}:#${(j:|:)~ignore_widgets}}; do
+ if [[ -n ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]]; then
+ _zsh_autosuggest_bind_widget $widget clear
+ elif [[ -n ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]]; then
+ _zsh_autosuggest_bind_widget $widget accept
+ elif [[ -n ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]]; then
+ _zsh_autosuggest_bind_widget $widget execute
+ elif [[ -n ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]]; then
+ _zsh_autosuggest_bind_widget $widget partial_accept
+ else
+ # Assume any unspecified widget might modify the buffer
+ _zsh_autosuggest_bind_widget $widget modify
+ fi
+ done
+}
+
+# Given the name of an original widget and args, invoke it, if it exists
+_zsh_autosuggest_invoke_original_widget() {
+ # Do nothing unless called with at least one arg
+ (( $# )) || return 0
+
+ local original_widget_name="$1"
+
+ shift
+
+ if (( ${+widgets[$original_widget_name]} )); then
+ zle $original_widget_name -- $@
+ fi
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/config.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/config.zsh
new file mode 100644
index 00000000..5a0ebd85
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/config.zsh
@@ -0,0 +1,93 @@
+
+#--------------------------------------------------------------------#
+# Global Configuration Variables #
+#--------------------------------------------------------------------#
+
+# Color to use when highlighting suggestion
+# Uses format of `region_highlight`
+# More info: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets
+(( ! ${+ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE} )) &&
+typeset -g ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'
+
+# Prefix to use when saving original versions of bound widgets
+(( ! ${+ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX} )) &&
+typeset -g ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig-
+
+# Strategies to use to fetch a suggestion
+# Will try each strategy in order until a suggestion is returned
+(( ! ${+ZSH_AUTOSUGGEST_STRATEGY} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_STRATEGY
+ ZSH_AUTOSUGGEST_STRATEGY=(history)
+}
+
+# Widgets that clear the suggestion
+(( ! ${+ZSH_AUTOSUGGEST_CLEAR_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_CLEAR_WIDGETS
+ ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
+ history-search-forward
+ history-search-backward
+ history-beginning-search-forward
+ history-beginning-search-backward
+ history-substring-search-up
+ history-substring-search-down
+ up-line-or-beginning-search
+ down-line-or-beginning-search
+ up-line-or-history
+ down-line-or-history
+ accept-line
+ copy-earlier-word
+ )
+}
+
+# Widgets that accept the entire suggestion
+(( ! ${+ZSH_AUTOSUGGEST_ACCEPT_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
+ ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
+ forward-char
+ end-of-line
+ vi-forward-char
+ vi-end-of-line
+ vi-add-eol
+ )
+}
+
+# Widgets that accept the entire suggestion and execute it
+(( ! ${+ZSH_AUTOSUGGEST_EXECUTE_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_EXECUTE_WIDGETS
+ ZSH_AUTOSUGGEST_EXECUTE_WIDGETS=(
+ )
+}
+
+# Widgets that accept the suggestion as far as the cursor moves
+(( ! ${+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
+ ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
+ forward-word
+ emacs-forward-word
+ vi-forward-word
+ vi-forward-word-end
+ vi-forward-blank-word
+ vi-forward-blank-word-end
+ vi-find-next-char
+ vi-find-next-char-skip
+ )
+}
+
+# Widgets that should be ignored (globbing supported but must be escaped)
+(( ! ${+ZSH_AUTOSUGGEST_IGNORE_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_IGNORE_WIDGETS
+ ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
+ orig-\*
+ beep
+ run-help
+ set-local-history
+ which-command
+ yank
+ yank-pop
+ zle-\*
+ )
+}
+
+# Pty name for capturing completions for completion suggestion strategy
+(( ! ${+ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME} )) &&
+typeset -g ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME=zsh_autosuggest_completion_pty
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/fetch.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/fetch.zsh
new file mode 100644
index 00000000..fef27152
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/fetch.zsh
@@ -0,0 +1,27 @@
+
+#--------------------------------------------------------------------#
+# Fetch Suggestion #
+#--------------------------------------------------------------------#
+# Loops through all specified strategies and returns a suggestion
+# from the first strategy to provide one.
+#
+
+_zsh_autosuggest_fetch_suggestion() {
+ typeset -g suggestion
+ local -a strategies
+ local strategy
+
+ # Ensure we are working with an array
+ strategies=(${=ZSH_AUTOSUGGEST_STRATEGY})
+
+ for strategy in $strategies; do
+ # Try to get a suggestion from this strategy
+ _zsh_autosuggest_strategy_$strategy "$1"
+
+ # Ensure the suggestion matches the prefix
+ [[ "$suggestion" != "$1"* ]] && unset suggestion
+
+ # Break once we've found a valid suggestion
+ [[ -n "$suggestion" ]] && break
+ done
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/highlight.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/highlight.zsh
new file mode 100644
index 00000000..273c03d5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/highlight.zsh
@@ -0,0 +1,26 @@
+
+#--------------------------------------------------------------------#
+# Highlighting #
+#--------------------------------------------------------------------#
+
+# If there was a highlight, remove it
+_zsh_autosuggest_highlight_reset() {
+ typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+
+ if [[ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]]; then
+ region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}")
+ unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+ fi
+}
+
+# If there's a suggestion, highlight it
+_zsh_autosuggest_highlight_apply() {
+ typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+
+ if (( $#POSTDISPLAY )); then
+ typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
+ region_highlight+=("$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT")
+ else
+ unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+ fi
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/start.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/start.zsh
new file mode 100644
index 00000000..5d4ee521
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/start.zsh
@@ -0,0 +1,33 @@
+
+#--------------------------------------------------------------------#
+# Start #
+#--------------------------------------------------------------------#
+
+# Start the autosuggestion widgets
+_zsh_autosuggest_start() {
+ # By default we re-bind widgets on every precmd to ensure we wrap other
+ # wrappers. Specifically, highlighting breaks if our widgets are wrapped by
+ # zsh-syntax-highlighting widgets. This also allows modifications to the
+ # widget list variables to take effect on the next precmd. However this has
+ # a decent performance hit, so users can set ZSH_AUTOSUGGEST_MANUAL_REBIND
+ # to disable the automatic re-binding.
+ if (( ${+ZSH_AUTOSUGGEST_MANUAL_REBIND} )); then
+ add-zsh-hook -d precmd _zsh_autosuggest_start
+ fi
+
+ _zsh_autosuggest_bind_widgets
+}
+
+# Mark for auto-loading the functions that we use
+autoload -Uz add-zsh-hook is-at-least
+
+# Automatically enable asynchronous mode in newer versions of zsh. Disable for
+# older versions because there is a bug when using async mode where ^C does not
+# work immediately after fetching a suggestion.
+# See https://github.com/zsh-users/zsh-autosuggestions/issues/364
+if is-at-least 5.0.8; then
+ typeset -g ZSH_AUTOSUGGEST_USE_ASYNC=
+fi
+
+# Start the autosuggestion widgets on the next precmd
+add-zsh-hook precmd _zsh_autosuggest_start
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/completion.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/completion.zsh
new file mode 100644
index 00000000..e2d114c8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/completion.zsh
@@ -0,0 +1,137 @@
+
+#--------------------------------------------------------------------#
+# Completion Suggestion Strategy #
+#--------------------------------------------------------------------#
+# Fetches a suggestion from the completion engine
+#
+
+_zsh_autosuggest_capture_postcompletion() {
+ # Always insert the first completion into the buffer
+ compstate[insert]=1
+
+ # Don't list completions
+ unset 'compstate[list]'
+}
+
+_zsh_autosuggest_capture_completion_widget() {
+ # Add a post-completion hook to be called after all completions have been
+ # gathered. The hook can modify compstate to affect what is done with the
+ # gathered completions.
+ local -a +h comppostfuncs
+ comppostfuncs=(_zsh_autosuggest_capture_postcompletion)
+
+ # Only capture completions at the end of the buffer
+ CURSOR=$#BUFFER
+
+ # Run the original widget wrapping `.complete-word` so we don't
+ # recursively try to fetch suggestions, since our pty is forked
+ # after autosuggestions is initialized.
+ zle -- ${(k)widgets[(r)completion:.complete-word:_main_complete]}
+
+ if is-at-least 5.0.3; then
+ # Don't do any cr/lf transformations. We need to do this immediately before
+ # output because if we do it in setup, onlcr will be re-enabled when we enter
+ # vared in the async code path. There is a bug in zpty module in older versions
+ # where the tty is not properly attached to the pty slave, resulting in stty
+ # getting stopped with a SIGTTOU. See zsh-workers thread 31660 and upstream
+ # commit f75904a38
+ stty -onlcr -ocrnl -F /dev/tty
+ fi
+
+ # The completion has been added, print the buffer as the suggestion
+ echo -nE - $'\0'$BUFFER$'\0'
+}
+
+zle -N autosuggest-capture-completion _zsh_autosuggest_capture_completion_widget
+
+_zsh_autosuggest_capture_setup() {
+ # There is a bug in zpty module in older zsh versions by which a
+ # zpty that exits will kill all zpty processes that were forked
+ # before it. Here we set up a zsh exit hook to SIGKILL the zpty
+ # process immediately, before it has a chance to kill any other
+ # zpty processes.
+ if ! is-at-least 5.4; then
+ zshexit() {
+ # The zsh builtin `kill` fails sometimes in older versions
+ # https://unix.stackexchange.com/a/477647/156673
+ kill -KILL $$ 2>&- || command kill -KILL $$
+
+ # Block for long enough for the signal to come through
+ sleep 1
+ }
+ fi
+
+ # Try to avoid any suggestions that wouldn't match the prefix
+ zstyle ':completion:*' matcher-list ''
+ zstyle ':completion:*' path-completion false
+ zstyle ':completion:*' max-errors 0 not-numeric
+
+ bindkey '^I' autosuggest-capture-completion
+}
+
+_zsh_autosuggest_capture_completion_sync() {
+ _zsh_autosuggest_capture_setup
+
+ zle autosuggest-capture-completion
+}
+
+_zsh_autosuggest_capture_completion_async() {
+ _zsh_autosuggest_capture_setup
+
+ zmodload zsh/parameter 2>/dev/null || return # For `$functions`
+
+ # Make vared completion work as if for a normal command line
+ # https://stackoverflow.com/a/7057118/154703
+ autoload +X _complete
+ functions[_original_complete]=$functions[_complete]
+ function _complete() {
+ unset 'compstate[vared]'
+ _original_complete "$@"
+ }
+
+ # Open zle with buffer set so we can capture completions for it
+ vared 1
+}
+
+_zsh_autosuggest_strategy_completion() {
+ # Reset options to defaults and enable LOCAL_OPTIONS
+ emulate -L zsh
+
+ # Enable extended glob for completion ignore pattern
+ setopt EXTENDED_GLOB
+
+ typeset -g suggestion
+ local line REPLY
+
+ # Exit if we don't have completions
+ whence compdef >/dev/null || return
+
+ # Exit if we don't have zpty
+ zmodload zsh/zpty 2>/dev/null || return
+
+ # Exit if our search string matches the ignore pattern
+ [[ -n "$ZSH_AUTOSUGGEST_COMPLETION_IGNORE" ]] && [[ "$1" == $~ZSH_AUTOSUGGEST_COMPLETION_IGNORE ]] && return
+
+ # Zle will be inactive if we are in async mode
+ if zle; then
+ zpty $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME _zsh_autosuggest_capture_completion_sync
+ else
+ zpty $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME _zsh_autosuggest_capture_completion_async "\$1"
+ zpty -w $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME $'\t'
+ fi
+
+ {
+ # The completion result is surrounded by null bytes, so read the
+ # content between the first two null bytes.
+ zpty -r $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME line '*'$'\0''*'$'\0'
+
+ # Extract the suggestion from between the null bytes. On older
+ # versions of zsh (older than 5.3), we sometimes get extra bytes after
+ # the second null byte, so trim those off the end.
+ # See http://www.zsh.org/mla/workers/2015/msg03290.html
+ suggestion="${${(@0)line}[2]}"
+ } always {
+ # Destroy the pty
+ zpty -d $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME
+ }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/history.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/history.zsh
new file mode 100644
index 00000000..0672a136
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/history.zsh
@@ -0,0 +1,32 @@
+
+#--------------------------------------------------------------------#
+# History Suggestion Strategy #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix.
+#
+
+_zsh_autosuggest_strategy_history() {
+ # Reset options to defaults and enable LOCAL_OPTIONS
+ emulate -L zsh
+
+ # Enable globbing flags so that we can use (#m) and (x~y) glob operator
+ setopt EXTENDED_GLOB
+
+ # Escape backslashes and all of the glob operators so we can use
+ # this string as a pattern to search the $history associative array.
+ # - (#m) globbing flag enables setting references for match data
+ # TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
+ local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
+
+ # Get the history items that match the prefix, excluding those that match
+ # the ignore pattern
+ local pattern="$prefix*"
+ if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then
+ pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)"
+ fi
+
+ # Give the first history item matching the pattern as the suggestion
+ # - (r) subscript flag makes the pattern match on values
+ typeset -g suggestion="${history[(r)$pattern]}"
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/match_prev_cmd.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/match_prev_cmd.zsh
new file mode 100644
index 00000000..b7097837
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/strategies/match_prev_cmd.zsh
@@ -0,0 +1,66 @@
+
+#--------------------------------------------------------------------#
+# Match Previous Command Suggestion Strategy #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix and whose preceding history item also matches the most
+# recently executed command.
+#
+# For example, suppose your history has the following entries:
+# - pwd
+# - ls foo
+# - ls bar
+# - pwd
+#
+# Given the history list above, when you type 'ls', the suggestion
+# will be 'ls foo' rather than 'ls bar' because your most recently
+# executed command (pwd) was previously followed by 'ls foo'.
+#
+# Note that this strategy won't work as expected with ZSH options that don't
+# preserve the history order such as `HIST_IGNORE_ALL_DUPS` or
+# `HIST_EXPIRE_DUPS_FIRST`.
+
+_zsh_autosuggest_strategy_match_prev_cmd() {
+ # Reset options to defaults and enable LOCAL_OPTIONS
+ emulate -L zsh
+
+ # Enable globbing flags so that we can use (#m) and (x~y) glob operator
+ setopt EXTENDED_GLOB
+
+ # TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
+ local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
+
+ # Get the history items that match the prefix, excluding those that match
+ # the ignore pattern
+ local pattern="$prefix*"
+ if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then
+ pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)"
+ fi
+
+ # Get all history event numbers that correspond to history
+ # entries that match the pattern
+ local history_match_keys
+ history_match_keys=(${(k)history[(R)$~pattern]})
+
+ # By default we use the first history number (most recent history entry)
+ local histkey="${history_match_keys[1]}"
+
+ # Get the previously executed command
+ local prev_cmd="$(_zsh_autosuggest_escape_command "${history[$((HISTCMD-1))]}")"
+
+ # Iterate up to the first 200 history event numbers that match $prefix
+ for key in "${(@)history_match_keys[1,200]}"; do
+ # Stop if we ran out of history
+ [[ $key -gt 1 ]] || break
+
+ # See if the history entry preceding the suggestion matches the
+ # previous command, and use it if it does
+ if [[ "${history[$((key - 1))]}" == "$prev_cmd" ]]; then
+ histkey="$key"
+ break
+ fi
+ done
+
+ # Give back the matched history entry
+ typeset -g suggestion="$history[$histkey]"
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/util.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/util.zsh
new file mode 100644
index 00000000..1f55d363
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/util.zsh
@@ -0,0 +1,11 @@
+
+#--------------------------------------------------------------------#
+# Utility Functions #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_escape_command() {
+ setopt localoptions EXTENDED_GLOB
+
+ # Escape special chars in the string (requires EXTENDED_GLOB)
+ echo -E "${1//(#m)[\"\'\\()\[\]|*?~]/\\$MATCH}"
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/widgets.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/widgets.zsh
new file mode 100644
index 00000000..bd616669
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/src/widgets.zsh
@@ -0,0 +1,231 @@
+
+#--------------------------------------------------------------------#
+# Autosuggest Widget Implementations #
+#--------------------------------------------------------------------#
+
+# Disable suggestions
+_zsh_autosuggest_disable() {
+ typeset -g _ZSH_AUTOSUGGEST_DISABLED
+ _zsh_autosuggest_clear
+}
+
+# Enable suggestions
+_zsh_autosuggest_enable() {
+ unset _ZSH_AUTOSUGGEST_DISABLED
+
+ if (( $#BUFFER )); then
+ _zsh_autosuggest_fetch
+ fi
+}
+
+# Toggle suggestions (enable/disable)
+_zsh_autosuggest_toggle() {
+ if (( ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
+ _zsh_autosuggest_enable
+ else
+ _zsh_autosuggest_disable
+ fi
+}
+
+# Clear the suggestion
+_zsh_autosuggest_clear() {
+ # Remove the suggestion
+ unset POSTDISPLAY
+
+ _zsh_autosuggest_invoke_original_widget $@
+}
+
+# Modify the buffer and get a new suggestion
+_zsh_autosuggest_modify() {
+ local -i retval
+
+ # Only available in zsh >= 5.4
+ local -i KEYS_QUEUED_COUNT
+
+ # Save the contents of the buffer/postdisplay
+ local orig_buffer="$BUFFER"
+ local orig_postdisplay="$POSTDISPLAY"
+
+ # Clear suggestion while waiting for next one
+ unset POSTDISPLAY
+
+ # Original widget may modify the buffer
+ _zsh_autosuggest_invoke_original_widget $@
+ retval=$?
+
+ emulate -L zsh
+
+ # Don't fetch a new suggestion if there's more input to be read immediately
+ if (( $PENDING > 0 || $KEYS_QUEUED_COUNT > 0 )); then
+ POSTDISPLAY="$orig_postdisplay"
+ return $retval
+ fi
+
+ # Optimize if manually typing in the suggestion or if buffer hasn't changed
+ if [[ "$BUFFER" = "$orig_buffer"* && "$orig_postdisplay" = "${BUFFER:$#orig_buffer}"* ]]; then
+ POSTDISPLAY="${orig_postdisplay:$(($#BUFFER - $#orig_buffer))}"
+ return $retval
+ fi
+
+ # Bail out if suggestions are disabled
+ if (( ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
+ return $?
+ fi
+
+ # Get a new suggestion if the buffer is not empty after modification
+ if (( $#BUFFER > 0 )); then
+ if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then
+ _zsh_autosuggest_fetch
+ fi
+ fi
+
+ return $retval
+}
+
+# Fetch a new suggestion based on what's currently in the buffer
+_zsh_autosuggest_fetch() {
+ if (( ${+ZSH_AUTOSUGGEST_USE_ASYNC} )); then
+ _zsh_autosuggest_async_request "$BUFFER"
+ else
+ local suggestion
+ _zsh_autosuggest_fetch_suggestion "$BUFFER"
+ _zsh_autosuggest_suggest "$suggestion"
+ fi
+}
+
+# Offer a suggestion
+_zsh_autosuggest_suggest() {
+ emulate -L zsh
+
+ local suggestion="$1"
+
+ if [[ -n "$suggestion" ]] && (( $#BUFFER )); then
+ POSTDISPLAY="${suggestion#$BUFFER}"
+ else
+ unset POSTDISPLAY
+ fi
+}
+
+# Accept the entire suggestion
+_zsh_autosuggest_accept() {
+ local -i retval max_cursor_pos=$#BUFFER
+
+ # When vicmd keymap is active, the cursor can't move all the way
+ # to the end of the buffer
+ if [[ "$KEYMAP" = "vicmd" ]]; then
+ max_cursor_pos=$((max_cursor_pos - 1))
+ fi
+
+ # If we're not in a valid state to accept a suggestion, just run the
+ # original widget and bail out
+ if (( $CURSOR != $max_cursor_pos || !$#POSTDISPLAY )); then
+ _zsh_autosuggest_invoke_original_widget $@
+ return
+ fi
+
+ # Only accept if the cursor is at the end of the buffer
+ # Add the suggestion to the buffer
+ BUFFER="$BUFFER$POSTDISPLAY"
+
+ # Remove the suggestion
+ unset POSTDISPLAY
+
+ # Run the original widget before manually moving the cursor so that the
+ # cursor movement doesn't make the widget do something unexpected
+ _zsh_autosuggest_invoke_original_widget $@
+ retval=$?
+
+ # Move the cursor to the end of the buffer
+ if [[ "$KEYMAP" = "vicmd" ]]; then
+ CURSOR=$(($#BUFFER - 1))
+ else
+ CURSOR=$#BUFFER
+ fi
+
+ return $retval
+}
+
+# Accept the entire suggestion and execute it
+_zsh_autosuggest_execute() {
+ # Add the suggestion to the buffer
+ BUFFER="$BUFFER$POSTDISPLAY"
+
+ # Remove the suggestion
+ unset POSTDISPLAY
+
+ # Call the original `accept-line` to handle syntax highlighting or
+ # other potential custom behavior
+ _zsh_autosuggest_invoke_original_widget "accept-line"
+}
+
+# Partially accept the suggestion
+_zsh_autosuggest_partial_accept() {
+ local -i retval cursor_loc
+
+ # Save the contents of the buffer so we can restore later if needed
+ local original_buffer="$BUFFER"
+
+ # Temporarily accept the suggestion.
+ BUFFER="$BUFFER$POSTDISPLAY"
+
+ # Original widget moves the cursor
+ _zsh_autosuggest_invoke_original_widget $@
+ retval=$?
+
+ # Normalize cursor location across vi/emacs modes
+ cursor_loc=$CURSOR
+ if [[ "$KEYMAP" = "vicmd" ]]; then
+ cursor_loc=$((cursor_loc + 1))
+ fi
+
+ # If we've moved past the end of the original buffer
+ if (( $cursor_loc > $#original_buffer )); then
+ # Set POSTDISPLAY to text right of the cursor
+ POSTDISPLAY="${BUFFER[$(($cursor_loc + 1)),$#BUFFER]}"
+
+ # Clip the buffer at the cursor
+ BUFFER="${BUFFER[1,$cursor_loc]}"
+ else
+ # Restore the original buffer
+ BUFFER="$original_buffer"
+ fi
+
+ return $retval
+}
+
+() {
+ typeset -ga _ZSH_AUTOSUGGEST_BUILTIN_ACTIONS
+
+ _ZSH_AUTOSUGGEST_BUILTIN_ACTIONS=(
+ clear
+ fetch
+ suggest
+ accept
+ execute
+ enable
+ disable
+ toggle
+ )
+
+ local action
+ for action in $_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS modify partial_accept; do
+ eval "_zsh_autosuggest_widget_$action() {
+ local -i retval
+
+ _zsh_autosuggest_highlight_reset
+
+ _zsh_autosuggest_$action \$@
+ retval=\$?
+
+ _zsh_autosuggest_highlight_apply
+
+ zle -R
+
+ return \$retval
+ }"
+ done
+
+ for action in $_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS; do
+ zle -N autosuggest-$action _zsh_autosuggest_widget_$action
+ done
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.plugin.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.plugin.zsh
new file mode 100644
index 00000000..16c22563
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.plugin.zsh
@@ -0,0 +1 @@
+source ${0:A:h}/zsh-autosuggestions.zsh
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
new file mode 100644
index 00000000..b19cac73
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
@@ -0,0 +1,864 @@
+# Fish-like fast/unobtrusive autosuggestions for zsh.
+# https://github.com/zsh-users/zsh-autosuggestions
+# v0.7.0
+# Copyright (c) 2013 Thiago de Arruda
+# Copyright (c) 2016-2021 Eric Freese
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+#--------------------------------------------------------------------#
+# Global Configuration Variables #
+#--------------------------------------------------------------------#
+
+# Color to use when highlighting suggestion
+# Uses format of `region_highlight`
+# More info: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets
+(( ! ${+ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE} )) &&
+typeset -g ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'
+
+# Prefix to use when saving original versions of bound widgets
+(( ! ${+ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX} )) &&
+typeset -g ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig-
+
+# Strategies to use to fetch a suggestion
+# Will try each strategy in order until a suggestion is returned
+(( ! ${+ZSH_AUTOSUGGEST_STRATEGY} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_STRATEGY
+ ZSH_AUTOSUGGEST_STRATEGY=(history)
+}
+
+# Widgets that clear the suggestion
+(( ! ${+ZSH_AUTOSUGGEST_CLEAR_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_CLEAR_WIDGETS
+ ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
+ history-search-forward
+ history-search-backward
+ history-beginning-search-forward
+ history-beginning-search-backward
+ history-substring-search-up
+ history-substring-search-down
+ up-line-or-beginning-search
+ down-line-or-beginning-search
+ up-line-or-history
+ down-line-or-history
+ accept-line
+ copy-earlier-word
+ )
+}
+
+# Widgets that accept the entire suggestion
+(( ! ${+ZSH_AUTOSUGGEST_ACCEPT_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
+ ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
+ forward-char
+ end-of-line
+ vi-forward-char
+ vi-end-of-line
+ vi-add-eol
+ )
+}
+
+# Widgets that accept the entire suggestion and execute it
+(( ! ${+ZSH_AUTOSUGGEST_EXECUTE_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_EXECUTE_WIDGETS
+ ZSH_AUTOSUGGEST_EXECUTE_WIDGETS=(
+ )
+}
+
+# Widgets that accept the suggestion as far as the cursor moves
+(( ! ${+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
+ ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
+ forward-word
+ emacs-forward-word
+ vi-forward-word
+ vi-forward-word-end
+ vi-forward-blank-word
+ vi-forward-blank-word-end
+ vi-find-next-char
+ vi-find-next-char-skip
+ )
+}
+
+# Widgets that should be ignored (globbing supported but must be escaped)
+(( ! ${+ZSH_AUTOSUGGEST_IGNORE_WIDGETS} )) && {
+ typeset -ga ZSH_AUTOSUGGEST_IGNORE_WIDGETS
+ ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
+ orig-\*
+ beep
+ run-help
+ set-local-history
+ which-command
+ yank
+ yank-pop
+ zle-\*
+ )
+}
+
+# Pty name for capturing completions for completion suggestion strategy
+(( ! ${+ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME} )) &&
+typeset -g ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME=zsh_autosuggest_completion_pty
+
+#--------------------------------------------------------------------#
+# Utility Functions #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_escape_command() {
+ setopt localoptions EXTENDED_GLOB
+
+ # Escape special chars in the string (requires EXTENDED_GLOB)
+ echo -E "${1//(#m)[\"\'\\()\[\]|*?~]/\\$MATCH}"
+}
+
+#--------------------------------------------------------------------#
+# Widget Helpers #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_incr_bind_count() {
+ typeset -gi bind_count=$((_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]+1))
+ _ZSH_AUTOSUGGEST_BIND_COUNTS[$1]=$bind_count
+}
+
+# Bind a single widget to an autosuggest widget, saving a reference to the original widget
+_zsh_autosuggest_bind_widget() {
+ typeset -gA _ZSH_AUTOSUGGEST_BIND_COUNTS
+
+ local widget=$1
+ local autosuggest_action=$2
+ local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX
+
+ local -i bind_count
+
+ # Save a reference to the original widget
+ case $widgets[$widget] in
+ # Already bound
+ user:_zsh_autosuggest_(bound|orig)_*)
+ bind_count=$((_ZSH_AUTOSUGGEST_BIND_COUNTS[$widget]))
+ ;;
+
+ # User-defined widget
+ user:*)
+ _zsh_autosuggest_incr_bind_count $widget
+ zle -N $prefix$bind_count-$widget ${widgets[$widget]#*:}
+ ;;
+
+ # Built-in widget
+ builtin)
+ _zsh_autosuggest_incr_bind_count $widget
+ eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }"
+ zle -N $prefix$bind_count-$widget _zsh_autosuggest_orig_$widget
+ ;;
+
+ # Completion widget
+ completion:*)
+ _zsh_autosuggest_incr_bind_count $widget
+ eval "zle -C $prefix$bind_count-${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}"
+ ;;
+ esac
+
+ # Pass the original widget's name explicitly into the autosuggest
+ # function. Use this passed in widget name to call the original
+ # widget instead of relying on the $WIDGET variable being set
+ # correctly. $WIDGET cannot be trusted because other plugins call
+ # zle without the `-w` flag (e.g. `zle self-insert` instead of
+ # `zle self-insert -w`).
+ eval "_zsh_autosuggest_bound_${bind_count}_${(q)widget}() {
+ _zsh_autosuggest_widget_$autosuggest_action $prefix$bind_count-${(q)widget} \$@
+ }"
+
+ # Create the bound widget
+ zle -N -- $widget _zsh_autosuggest_bound_${bind_count}_$widget
+}
+
+# Map all configured widgets to the right autosuggest widgets
+_zsh_autosuggest_bind_widgets() {
+ emulate -L zsh
+
+ local widget
+ local ignore_widgets
+
+ ignore_widgets=(
+ .\*
+ _\*
+ ${_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS/#/autosuggest-}
+ $ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
+ $ZSH_AUTOSUGGEST_IGNORE_WIDGETS
+ )
+
+ # Find every widget we might want to bind and bind it appropriately
+ for widget in ${${(f)"$(builtin zle -la)"}:#${(j:|:)~ignore_widgets}}; do
+ if [[ -n ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]]; then
+ _zsh_autosuggest_bind_widget $widget clear
+ elif [[ -n ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]]; then
+ _zsh_autosuggest_bind_widget $widget accept
+ elif [[ -n ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]]; then
+ _zsh_autosuggest_bind_widget $widget execute
+ elif [[ -n ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]]; then
+ _zsh_autosuggest_bind_widget $widget partial_accept
+ else
+ # Assume any unspecified widget might modify the buffer
+ _zsh_autosuggest_bind_widget $widget modify
+ fi
+ done
+}
+
+# Given the name of an original widget and args, invoke it, if it exists
+_zsh_autosuggest_invoke_original_widget() {
+ # Do nothing unless called with at least one arg
+ (( $# )) || return 0
+
+ local original_widget_name="$1"
+
+ shift
+
+ if (( ${+widgets[$original_widget_name]} )); then
+ zle $original_widget_name -- $@
+ fi
+}
+
+#--------------------------------------------------------------------#
+# Highlighting #
+#--------------------------------------------------------------------#
+
+# If there was a highlight, remove it
+_zsh_autosuggest_highlight_reset() {
+ typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+
+ if [[ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]]; then
+ region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}")
+ unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+ fi
+}
+
+# If there's a suggestion, highlight it
+_zsh_autosuggest_highlight_apply() {
+ typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+
+ if (( $#POSTDISPLAY )); then
+ typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
+ region_highlight+=("$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT")
+ else
+ unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
+ fi
+}
+
+#--------------------------------------------------------------------#
+# Autosuggest Widget Implementations #
+#--------------------------------------------------------------------#
+
+# Disable suggestions
+_zsh_autosuggest_disable() {
+ typeset -g _ZSH_AUTOSUGGEST_DISABLED
+ _zsh_autosuggest_clear
+}
+
+# Enable suggestions
+_zsh_autosuggest_enable() {
+ unset _ZSH_AUTOSUGGEST_DISABLED
+
+ if (( $#BUFFER )); then
+ _zsh_autosuggest_fetch
+ fi
+}
+
+# Toggle suggestions (enable/disable)
+_zsh_autosuggest_toggle() {
+ if (( ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
+ _zsh_autosuggest_enable
+ else
+ _zsh_autosuggest_disable
+ fi
+}
+
+# Clear the suggestion
+_zsh_autosuggest_clear() {
+ # Remove the suggestion
+ unset POSTDISPLAY
+
+ _zsh_autosuggest_invoke_original_widget $@
+}
+
+# Modify the buffer and get a new suggestion
+_zsh_autosuggest_modify() {
+ local -i retval
+
+ # Only available in zsh >= 5.4
+ local -i KEYS_QUEUED_COUNT
+
+ # Save the contents of the buffer/postdisplay
+ local orig_buffer="$BUFFER"
+ local orig_postdisplay="$POSTDISPLAY"
+
+ # Clear suggestion while waiting for next one
+ unset POSTDISPLAY
+
+ # Original widget may modify the buffer
+ _zsh_autosuggest_invoke_original_widget $@
+ retval=$?
+
+ emulate -L zsh
+
+ # Don't fetch a new suggestion if there's more input to be read immediately
+ if (( $PENDING > 0 || $KEYS_QUEUED_COUNT > 0 )); then
+ POSTDISPLAY="$orig_postdisplay"
+ return $retval
+ fi
+
+ # Optimize if manually typing in the suggestion or if buffer hasn't changed
+ if [[ "$BUFFER" = "$orig_buffer"* && "$orig_postdisplay" = "${BUFFER:$#orig_buffer}"* ]]; then
+ POSTDISPLAY="${orig_postdisplay:$(($#BUFFER - $#orig_buffer))}"
+ return $retval
+ fi
+
+ # Bail out if suggestions are disabled
+ if (( ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
+ return $?
+ fi
+
+ # Get a new suggestion if the buffer is not empty after modification
+ if (( $#BUFFER > 0 )); then
+ if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then
+ _zsh_autosuggest_fetch
+ fi
+ fi
+
+ return $retval
+}
+
+# Fetch a new suggestion based on what's currently in the buffer
+_zsh_autosuggest_fetch() {
+ if (( ${+ZSH_AUTOSUGGEST_USE_ASYNC} )); then
+ _zsh_autosuggest_async_request "$BUFFER"
+ else
+ local suggestion
+ _zsh_autosuggest_fetch_suggestion "$BUFFER"
+ _zsh_autosuggest_suggest "$suggestion"
+ fi
+}
+
+# Offer a suggestion
+_zsh_autosuggest_suggest() {
+ emulate -L zsh
+
+ local suggestion="$1"
+
+ if [[ -n "$suggestion" ]] && (( $#BUFFER )); then
+ POSTDISPLAY="${suggestion#$BUFFER}"
+ else
+ unset POSTDISPLAY
+ fi
+}
+
+# Accept the entire suggestion
+_zsh_autosuggest_accept() {
+ local -i retval max_cursor_pos=$#BUFFER
+
+ # When vicmd keymap is active, the cursor can't move all the way
+ # to the end of the buffer
+ if [[ "$KEYMAP" = "vicmd" ]]; then
+ max_cursor_pos=$((max_cursor_pos - 1))
+ fi
+
+ # If we're not in a valid state to accept a suggestion, just run the
+ # original widget and bail out
+ if (( $CURSOR != $max_cursor_pos || !$#POSTDISPLAY )); then
+ _zsh_autosuggest_invoke_original_widget $@
+ return
+ fi
+
+ # Only accept if the cursor is at the end of the buffer
+ # Add the suggestion to the buffer
+ BUFFER="$BUFFER$POSTDISPLAY"
+
+ # Remove the suggestion
+ unset POSTDISPLAY
+
+ # Run the original widget before manually moving the cursor so that the
+ # cursor movement doesn't make the widget do something unexpected
+ _zsh_autosuggest_invoke_original_widget $@
+ retval=$?
+
+ # Move the cursor to the end of the buffer
+ if [[ "$KEYMAP" = "vicmd" ]]; then
+ CURSOR=$(($#BUFFER - 1))
+ else
+ CURSOR=$#BUFFER
+ fi
+
+ return $retval
+}
+
+# Accept the entire suggestion and execute it
+_zsh_autosuggest_execute() {
+ # Add the suggestion to the buffer
+ BUFFER="$BUFFER$POSTDISPLAY"
+
+ # Remove the suggestion
+ unset POSTDISPLAY
+
+ # Call the original `accept-line` to handle syntax highlighting or
+ # other potential custom behavior
+ _zsh_autosuggest_invoke_original_widget "accept-line"
+}
+
+# Partially accept the suggestion
+_zsh_autosuggest_partial_accept() {
+ local -i retval cursor_loc
+
+ # Save the contents of the buffer so we can restore later if needed
+ local original_buffer="$BUFFER"
+
+ # Temporarily accept the suggestion.
+ BUFFER="$BUFFER$POSTDISPLAY"
+
+ # Original widget moves the cursor
+ _zsh_autosuggest_invoke_original_widget $@
+ retval=$?
+
+ # Normalize cursor location across vi/emacs modes
+ cursor_loc=$CURSOR
+ if [[ "$KEYMAP" = "vicmd" ]]; then
+ cursor_loc=$((cursor_loc + 1))
+ fi
+
+ # If we've moved past the end of the original buffer
+ if (( $cursor_loc > $#original_buffer )); then
+ # Set POSTDISPLAY to text right of the cursor
+ POSTDISPLAY="${BUFFER[$(($cursor_loc + 1)),$#BUFFER]}"
+
+ # Clip the buffer at the cursor
+ BUFFER="${BUFFER[1,$cursor_loc]}"
+ else
+ # Restore the original buffer
+ BUFFER="$original_buffer"
+ fi
+
+ return $retval
+}
+
+() {
+ typeset -ga _ZSH_AUTOSUGGEST_BUILTIN_ACTIONS
+
+ _ZSH_AUTOSUGGEST_BUILTIN_ACTIONS=(
+ clear
+ fetch
+ suggest
+ accept
+ execute
+ enable
+ disable
+ toggle
+ )
+
+ local action
+ for action in $_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS modify partial_accept; do
+ eval "_zsh_autosuggest_widget_$action() {
+ local -i retval
+
+ _zsh_autosuggest_highlight_reset
+
+ _zsh_autosuggest_$action \$@
+ retval=\$?
+
+ _zsh_autosuggest_highlight_apply
+
+ zle -R
+
+ return \$retval
+ }"
+ done
+
+ for action in $_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS; do
+ zle -N autosuggest-$action _zsh_autosuggest_widget_$action
+ done
+}
+
+#--------------------------------------------------------------------#
+# Completion Suggestion Strategy #
+#--------------------------------------------------------------------#
+# Fetches a suggestion from the completion engine
+#
+
+_zsh_autosuggest_capture_postcompletion() {
+ # Always insert the first completion into the buffer
+ compstate[insert]=1
+
+ # Don't list completions
+ unset 'compstate[list]'
+}
+
+_zsh_autosuggest_capture_completion_widget() {
+ # Add a post-completion hook to be called after all completions have been
+ # gathered. The hook can modify compstate to affect what is done with the
+ # gathered completions.
+ local -a +h comppostfuncs
+ comppostfuncs=(_zsh_autosuggest_capture_postcompletion)
+
+ # Only capture completions at the end of the buffer
+ CURSOR=$#BUFFER
+
+ # Run the original widget wrapping `.complete-word` so we don't
+ # recursively try to fetch suggestions, since our pty is forked
+ # after autosuggestions is initialized.
+ zle -- ${(k)widgets[(r)completion:.complete-word:_main_complete]}
+
+ if is-at-least 5.0.3; then
+ # Don't do any cr/lf transformations. We need to do this immediately before
+ # output because if we do it in setup, onlcr will be re-enabled when we enter
+ # vared in the async code path. There is a bug in zpty module in older versions
+ # where the tty is not properly attached to the pty slave, resulting in stty
+ # getting stopped with a SIGTTOU. See zsh-workers thread 31660 and upstream
+ # commit f75904a38
+ stty -onlcr -ocrnl -F /dev/tty
+ fi
+
+ # The completion has been added, print the buffer as the suggestion
+ echo -nE - $'\0'$BUFFER$'\0'
+}
+
+zle -N autosuggest-capture-completion _zsh_autosuggest_capture_completion_widget
+
+_zsh_autosuggest_capture_setup() {
+ # There is a bug in zpty module in older zsh versions by which a
+ # zpty that exits will kill all zpty processes that were forked
+ # before it. Here we set up a zsh exit hook to SIGKILL the zpty
+ # process immediately, before it has a chance to kill any other
+ # zpty processes.
+ if ! is-at-least 5.4; then
+ zshexit() {
+ # The zsh builtin `kill` fails sometimes in older versions
+ # https://unix.stackexchange.com/a/477647/156673
+ kill -KILL $$ 2>&- || command kill -KILL $$
+
+ # Block for long enough for the signal to come through
+ sleep 1
+ }
+ fi
+
+ # Try to avoid any suggestions that wouldn't match the prefix
+ zstyle ':completion:*' matcher-list ''
+ zstyle ':completion:*' path-completion false
+ zstyle ':completion:*' max-errors 0 not-numeric
+
+ bindkey '^I' autosuggest-capture-completion
+}
+
+_zsh_autosuggest_capture_completion_sync() {
+ _zsh_autosuggest_capture_setup
+
+ zle autosuggest-capture-completion
+}
+
+_zsh_autosuggest_capture_completion_async() {
+ _zsh_autosuggest_capture_setup
+
+ zmodload zsh/parameter 2>/dev/null || return # For `$functions`
+
+ # Make vared completion work as if for a normal command line
+ # https://stackoverflow.com/a/7057118/154703
+ autoload +X _complete
+ functions[_original_complete]=$functions[_complete]
+ function _complete() {
+ unset 'compstate[vared]'
+ _original_complete "$@"
+ }
+
+ # Open zle with buffer set so we can capture completions for it
+ vared 1
+}
+
+_zsh_autosuggest_strategy_completion() {
+ # Reset options to defaults and enable LOCAL_OPTIONS
+ emulate -L zsh
+
+ # Enable extended glob for completion ignore pattern
+ setopt EXTENDED_GLOB
+
+ typeset -g suggestion
+ local line REPLY
+
+ # Exit if we don't have completions
+ whence compdef >/dev/null || return
+
+ # Exit if we don't have zpty
+ zmodload zsh/zpty 2>/dev/null || return
+
+ # Exit if our search string matches the ignore pattern
+ [[ -n "$ZSH_AUTOSUGGEST_COMPLETION_IGNORE" ]] && [[ "$1" == $~ZSH_AUTOSUGGEST_COMPLETION_IGNORE ]] && return
+
+ # Zle will be inactive if we are in async mode
+ if zle; then
+ zpty $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME _zsh_autosuggest_capture_completion_sync
+ else
+ zpty $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME _zsh_autosuggest_capture_completion_async "\$1"
+ zpty -w $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME $'\t'
+ fi
+
+ {
+ # The completion result is surrounded by null bytes, so read the
+ # content between the first two null bytes.
+ zpty -r $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME line '*'$'\0''*'$'\0'
+
+ # Extract the suggestion from between the null bytes. On older
+ # versions of zsh (older than 5.3), we sometimes get extra bytes after
+ # the second null byte, so trim those off the end.
+ # See http://www.zsh.org/mla/workers/2015/msg03290.html
+ suggestion="${${(@0)line}[2]}"
+ } always {
+ # Destroy the pty
+ zpty -d $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME
+ }
+}
+
+#--------------------------------------------------------------------#
+# History Suggestion Strategy #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix.
+#
+
+_zsh_autosuggest_strategy_history() {
+ # Reset options to defaults and enable LOCAL_OPTIONS
+ emulate -L zsh
+
+ # Enable globbing flags so that we can use (#m) and (x~y) glob operator
+ setopt EXTENDED_GLOB
+
+ # Escape backslashes and all of the glob operators so we can use
+ # this string as a pattern to search the $history associative array.
+ # - (#m) globbing flag enables setting references for match data
+ # TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
+ local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
+
+ # Get the history items that match the prefix, excluding those that match
+ # the ignore pattern
+ local pattern="$prefix*"
+ if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then
+ pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)"
+ fi
+
+ # Give the first history item matching the pattern as the suggestion
+ # - (r) subscript flag makes the pattern match on values
+ typeset -g suggestion="${history[(r)$pattern]}"
+}
+
+#--------------------------------------------------------------------#
+# Match Previous Command Suggestion Strategy #
+#--------------------------------------------------------------------#
+# Suggests the most recent history item that matches the given
+# prefix and whose preceding history item also matches the most
+# recently executed command.
+#
+# For example, suppose your history has the following entries:
+# - pwd
+# - ls foo
+# - ls bar
+# - pwd
+#
+# Given the history list above, when you type 'ls', the suggestion
+# will be 'ls foo' rather than 'ls bar' because your most recently
+# executed command (pwd) was previously followed by 'ls foo'.
+#
+# Note that this strategy won't work as expected with ZSH options that don't
+# preserve the history order such as `HIST_IGNORE_ALL_DUPS` or
+# `HIST_EXPIRE_DUPS_FIRST`.
+
+_zsh_autosuggest_strategy_match_prev_cmd() {
+ # Reset options to defaults and enable LOCAL_OPTIONS
+ emulate -L zsh
+
+ # Enable globbing flags so that we can use (#m) and (x~y) glob operator
+ setopt EXTENDED_GLOB
+
+ # TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
+ local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
+
+ # Get the history items that match the prefix, excluding those that match
+ # the ignore pattern
+ local pattern="$prefix*"
+ if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then
+ pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)"
+ fi
+
+ # Get all history event numbers that correspond to history
+ # entries that match the pattern
+ local history_match_keys
+ history_match_keys=(${(k)history[(R)$~pattern]})
+
+ # By default we use the first history number (most recent history entry)
+ local histkey="${history_match_keys[1]}"
+
+ # Get the previously executed command
+ local prev_cmd="$(_zsh_autosuggest_escape_command "${history[$((HISTCMD-1))]}")"
+
+ # Iterate up to the first 200 history event numbers that match $prefix
+ for key in "${(@)history_match_keys[1,200]}"; do
+ # Stop if we ran out of history
+ [[ $key -gt 1 ]] || break
+
+ # See if the history entry preceding the suggestion matches the
+ # previous command, and use it if it does
+ if [[ "${history[$((key - 1))]}" == "$prev_cmd" ]]; then
+ histkey="$key"
+ break
+ fi
+ done
+
+ # Give back the matched history entry
+ typeset -g suggestion="$history[$histkey]"
+}
+
+#--------------------------------------------------------------------#
+# Fetch Suggestion #
+#--------------------------------------------------------------------#
+# Loops through all specified strategies and returns a suggestion
+# from the first strategy to provide one.
+#
+
+_zsh_autosuggest_fetch_suggestion() {
+ typeset -g suggestion
+ local -a strategies
+ local strategy
+
+ # Ensure we are working with an array
+ strategies=(${=ZSH_AUTOSUGGEST_STRATEGY})
+
+ for strategy in $strategies; do
+ # Try to get a suggestion from this strategy
+ _zsh_autosuggest_strategy_$strategy "$1"
+
+ # Ensure the suggestion matches the prefix
+ [[ "$suggestion" != "$1"* ]] && unset suggestion
+
+ # Break once we've found a valid suggestion
+ [[ -n "$suggestion" ]] && break
+ done
+}
+
+#--------------------------------------------------------------------#
+# Async #
+#--------------------------------------------------------------------#
+
+_zsh_autosuggest_async_request() {
+ zmodload zsh/system 2>/dev/null # For `$sysparams`
+
+ typeset -g _ZSH_AUTOSUGGEST_ASYNC_FD _ZSH_AUTOSUGGEST_CHILD_PID
+
+ # If we've got a pending request, cancel it
+ if [[ -n "$_ZSH_AUTOSUGGEST_ASYNC_FD" ]] && { true <&$_ZSH_AUTOSUGGEST_ASYNC_FD } 2>/dev/null; then
+ # Close the file descriptor and remove the handler
+ exec {_ZSH_AUTOSUGGEST_ASYNC_FD}<&-
+ zle -F $_ZSH_AUTOSUGGEST_ASYNC_FD
+
+ # We won't know the pid unless the user has zsh/system module installed
+ if [[ -n "$_ZSH_AUTOSUGGEST_CHILD_PID" ]]; then
+ # Zsh will make a new process group for the child process only if job
+ # control is enabled (MONITOR option)
+ if [[ -o MONITOR ]]; then
+ # Send the signal to the process group to kill any processes that may
+ # have been forked by the suggestion strategy
+ kill -TERM -$_ZSH_AUTOSUGGEST_CHILD_PID 2>/dev/null
+ else
+ # Kill just the child process since it wasn't placed in a new process
+ # group. If the suggestion strategy forked any child processes they may
+ # be orphaned and left behind.
+ kill -TERM $_ZSH_AUTOSUGGEST_CHILD_PID 2>/dev/null
+ fi
+ fi
+ fi
+
+ # Fork a process to fetch a suggestion and open a pipe to read from it
+ exec {_ZSH_AUTOSUGGEST_ASYNC_FD}< <(
+ # Tell parent process our pid
+ echo $sysparams[pid]
+
+ # Fetch and print the suggestion
+ local suggestion
+ _zsh_autosuggest_fetch_suggestion "$1"
+ echo -nE "$suggestion"
+ )
+
+ # There's a weird bug here where ^C stops working unless we force a fork
+ # See https://github.com/zsh-users/zsh-autosuggestions/issues/364
+ autoload -Uz is-at-least
+ is-at-least 5.8 || command true
+
+ # Read the pid from the child process
+ read _ZSH_AUTOSUGGEST_CHILD_PID <&$_ZSH_AUTOSUGGEST_ASYNC_FD
+
+ # When the fd is readable, call the response handler
+ zle -F "$_ZSH_AUTOSUGGEST_ASYNC_FD" _zsh_autosuggest_async_response
+}
+
+# Called when new data is ready to be read from the pipe
+# First arg will be fd ready for reading
+# Second arg will be passed in case of error
+_zsh_autosuggest_async_response() {
+ emulate -L zsh
+
+ local suggestion
+
+ if [[ -z "$2" || "$2" == "hup" ]]; then
+ # Read everything from the fd and give it as a suggestion
+ IFS='' read -rd '' -u $1 suggestion
+ zle autosuggest-suggest -- "$suggestion"
+
+ # Close the fd
+ exec {1}<&-
+ fi
+
+ # Always remove the handler
+ zle -F "$1"
+}
+
+#--------------------------------------------------------------------#
+# Start #
+#--------------------------------------------------------------------#
+
+# Start the autosuggestion widgets
+_zsh_autosuggest_start() {
+ # By default we re-bind widgets on every precmd to ensure we wrap other
+ # wrappers. Specifically, highlighting breaks if our widgets are wrapped by
+ # zsh-syntax-highlighting widgets. This also allows modifications to the
+ # widget list variables to take effect on the next precmd. However this has
+ # a decent performance hit, so users can set ZSH_AUTOSUGGEST_MANUAL_REBIND
+ # to disable the automatic re-binding.
+ if (( ${+ZSH_AUTOSUGGEST_MANUAL_REBIND} )); then
+ add-zsh-hook -d precmd _zsh_autosuggest_start
+ fi
+
+ _zsh_autosuggest_bind_widgets
+}
+
+# Mark for auto-loading the functions that we use
+autoload -Uz add-zsh-hook is-at-least
+
+# Automatically enable asynchronous mode in newer versions of zsh. Disable for
+# older versions because there is a bug when using async mode where ^C does not
+# work immediately after fetching a suggestion.
+# See https://github.com/zsh-users/zsh-autosuggestions/issues/364
+if is-at-least 5.0.8; then
+ typeset -g ZSH_AUTOSUGGEST_USE_ASYNC=
+fi
+
+# Start the autosuggestion widgets on the next precmd
+add-zsh-hook precmd _zsh_autosuggest_start
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-cwd-history/zsh-cwd-history.plugin.zsh b/dot-oh-my-zsh/custom/plugins/zsh-cwd-history/zsh-cwd-history.plugin.zsh
new file mode 100644
index 00000000..d5d717f6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-cwd-history/zsh-cwd-history.plugin.zsh
@@ -0,0 +1,150 @@
+# Scope history to the current working directory.
+# Idea from https://github.com/jimhester/per-directory-history
+# https://github.com/ericfreese/zsh-cwd-history
+# v0.2.1
+# Copyright (c) 2016 Eric Freese
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+#--------------------------------------------------------------------#
+# Global Config Variables #
+#--------------------------------------------------------------------#
+
+ZSH_CWD_HISTORY_DIR="$HOME/.zsh_cwd_history"
+ZSH_CWD_HISTORY_SHOW_TOGGLE_MSG=true
+ZSH_CWD_HISTORY_SHOW_CHPWD_MSG=false
+
+#--------------------------------------------------------------------#
+# Histfile Helper Functions #
+#--------------------------------------------------------------------#
+
+# Echo the name of the history file to use for current working dir
+# Uses the md5 hash of the absolute path
+_zsh_cwd_history_histfile_for_cwd() {
+ echo "$ZSH_CWD_HISTORY_DIR/.hist-$(echo "${PWD:A}" | md5 -q)"
+}
+
+# Switch to a new history file, writing to the old one
+_zsh_cwd_history_switch_histfile() {
+ local new_histfile=$1
+
+ # Write old histfile
+ fc -P
+
+ # Read new histfile
+ fc -p "$new_histfile"
+}
+
+#--------------------------------------------------------------------#
+# Display a Message #
+#--------------------------------------------------------------------#
+
+_zsh_cwd_history_message() {
+ local message=$1
+
+ if zle; then
+ zle -Rc "" $message
+ else
+ echo $message
+ fi
+}
+
+#--------------------------------------------------------------------#
+# Toggle Widget #
+#--------------------------------------------------------------------#
+
+# Implementation for toggle widget
+_zsh_cwd_history_toggle() {
+ if [ "$HISTFILE" = "$_ZSH_CWD_HISTORY_ORIG_HISTFILE" ]; then
+ # Switch to the cwd histfile
+ _zsh_cwd_history_switch_histfile $(_zsh_cwd_history_histfile_for_cwd)
+
+ # Add back the cwd hook
+ _zsh_cwd_history_add_cwd_hook
+
+ # Show message if necessary
+ if $ZSH_CWD_HISTORY_SHOW_TOGGLE_MSG; then
+ _zsh_cwd_history_message "Using cwd histfile: $HISTFILE"
+ fi
+ else
+ # Switch to the original histfile
+ _zsh_cwd_history_switch_histfile $_ZSH_CWD_HISTORY_ORIG_HISTFILE
+
+ # Temporarily remove the cwd hook
+ _zsh_cwd_history_remove_cwd_hook
+
+ # Show message if necessary
+ if $ZSH_CWD_HISTORY_SHOW_TOGGLE_MSG; then
+ _zsh_cwd_history_message "Using original histfile: $HISTFILE"
+ fi
+ fi
+}
+
+# Create the toggle widget
+zle -N cwd-history-toggle _zsh_cwd_history_toggle
+
+#--------------------------------------------------------------------#
+# Zsh Hooks #
+#--------------------------------------------------------------------#
+
+# Initialize on first prompt, then remove the precmd hook
+_zsh_cwd_history_initialize() {
+ # Simulate initial chpwd
+ _zsh_cwd_history_cwd_changed
+
+ # Add a hook to switch histfiles on chpwd
+ _zsh_cwd_history_add_cwd_hook
+
+ # Remove the precmd hook
+ add-zsh-hook -d precmd _zsh_cwd_history_initialize
+}
+
+# Load history for current working directory when changing dirs
+_zsh_cwd_history_cwd_changed() {
+ local cwd_histfile=$(_zsh_cwd_history_histfile_for_cwd)
+
+ # Save a reference to any original histfile from outside our dir
+ if [ "${HISTFILE:A:h}" != "$ZSH_CWD_HISTORY_DIR" ]; then
+ _ZSH_CWD_HISTORY_ORIG_HISTFILE="$HISTFILE"
+ fi
+
+ # Switch the histfile
+ _zsh_cwd_history_switch_histfile $cwd_histfile
+
+ # Show message if necessary
+ if $ZSH_CWD_HISTORY_SHOW_CHPWD_MSG; then
+ _zsh_cwd_history_message "Using cwd histfile: $HISTFILE"
+ fi
+}
+
+# Add the chpwd hook
+_zsh_cwd_history_add_cwd_hook() {
+ add-zsh-hook chpwd _zsh_cwd_history_cwd_changed
+}
+
+# Remove the chpwd hook
+_zsh_cwd_history_remove_cwd_hook() {
+ add-zsh-hook -d chpwd _zsh_cwd_history_cwd_changed
+}
+
+autoload -Uz add-zsh-hook
+add-zsh-hook precmd _zsh_cwd_history_initialize
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/README.md b/dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/README.md
new file mode 100644
index 00000000..aab5c17a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/README.md
@@ -0,0 +1,182 @@
+# zsh-history-substring-search
+
+This is a clean-room implementation of the [Fish shell][1]'s history search
+feature, where you can type in any part of any command from history and then
+press chosen keys, such as the UP and DOWN arrows, to cycle through matches.
+
+[1]: http://fishshell.com
+[2]: http://www.zsh.org/mla/users/2009/msg00818.html
+[3]: http://sourceforge.net/projects/fizsh/
+[4]: https://github.com/robbyrussell/oh-my-zsh/pull/215
+[5]: https://github.com/zsh-users/zsh-history-substring-search
+[6]: https://github.com/zsh-users/zsh-syntax-highlighting
+
+
+Requirements
+------------------------------------------------------------------------------
+
+* [ZSH](http://zsh.sourceforge.net) 4.3 or newer
+
+Install
+------------------------------------------------------------------------------
+
+Using the [Homebrew]( https://brew.sh ) package manager:
+
+ brew install zsh-history-substring-search
+ echo 'source /usr/local/share/zsh-history-substring-search/zsh-history-substring-search.zsh' >> ~/.zshrc
+
+Using [Oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh):
+
+1. Clone this repository in oh-my-zsh's plugins directory:
+
+ git clone https://github.com/zsh-users/zsh-history-substring-search ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-history-substring-search
+
+2. Activate the plugin in `~/.zshrc`:
+
+ plugins=( [plugins...] zsh-history-substring-search)
+
+3. Source `~/.zshrc` to take changes into account:
+
+ source ~/.zshrc
+
+Usage
+------------------------------------------------------------------------------
+
+1. Load this script into your interactive ZSH session:
+
+ % source zsh-history-substring-search.zsh
+
+ If you want to use [zsh-syntax-highlighting][6] along with this script,
+ then make sure that you load it *before* you load this script:
+
+ % source zsh-syntax-highlighting.zsh
+ % source zsh-history-substring-search.zsh
+
+2. Bind keyboard shortcuts to this script's functions.
+
+ Users typically bind their UP and DOWN arrow keys to this script, thus:
+ * Run `cat -v` in your favorite terminal emulator to observe key codes.
+      (**NOTE:** In some cases, `cat -v` shows the wrong key codes. If the
+ key codes shown by `cat -v` don't work for you, press `<C-v><UP>` and
+ `<C-v><DOWN>` at your ZSH command line prompt for correct key codes.)
+ * Press the UP arrow key and observe what is printed in your terminal.
+ * Press the DOWN arrow key and observe what is printed in your terminal.
+ * Press the Control and C keys simultaneously to terminate the `cat -v`.
+ * Use your observations from the previous steps to create key bindings.
+ For example, if you observed `^[[A` for UP and `^[[B` for DOWN, then:
+
+ bindkey '^[[A' history-substring-search-up
+ bindkey '^[[B' history-substring-search-down
+
+ However, if the observed values don't work, you can try using terminfo:
+
+ bindkey "$terminfo[kcuu1]" history-substring-search-up
+ bindkey "$terminfo[kcud1]" history-substring-search-down
+
+ You might also want to bind the Control-P/N keys for use in EMACS mode:
+
+ bindkey -M emacs '^P' history-substring-search-up
+ bindkey -M emacs '^N' history-substring-search-down
+
+ You might also want to bind the `k` and `j` keys for use in VI mode:
+
+ bindkey -M vicmd 'k' history-substring-search-up
+ bindkey -M vicmd 'j' history-substring-search-down
+
+3. Type any part of any previous command and then:
+
+ * Press the `history-substring-search-up` key, which was configured in
+ step 2 above, to select the nearest command that (1) contains your query
+ and (2) is also older than the current command in your command history.
+
+ * Press the `history-substring-search-down` key, which was configured in
+ step 2 above, to select the nearest command that (1) contains your query
+ and (2) is also newer than the current command in your command history.
+
+ * Press `^U` the Control and U keys simultaneously to abort the search.
+
+4. If a matching command spans more than one line of text, press the LEFT
+ arrow key to move the cursor away from the end of the command, and then:
+
+ * Press the `history-substring-search-up` key, which was configured in
+ step 2 above, to move the cursor to the line above the cursored line.
+ When the cursor reaches the first line of the command, pressing the
+ `history-substring-search-up` key again will cause this script to
+ perform another search.
+
+ * Press the `history-substring-search-down` key, which was configured in
+ step 2 above, to move the cursor to the line below the cursored line.
+ When the cursor reaches the last line of the command, pressing the
+ `history-substring-search-down` key, which was configured in step 2
+ above, again will cause this script to perform another search.
+
+
+Configuration
+------------------------------------------------------------------------------
+
+This script defines the following global variables. You may override their
+default values.
+
+* `HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND` is a global variable that defines
+ how the query should be highlighted inside a matching command. Its default
+ value causes this script to highlight using bold, white text on a magenta
+ background. See the "Character Highlighting" section in the zshzle(1) man
+ page to learn about the kinds of values you may assign to this variable.
+
+* `HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND` is a global variable that
+ defines how the query should be highlighted when no commands in the
+ history match it. Its default value causes this script to highlight using
+ bold, white text on a red background. See the "Character Highlighting"
+ section in the zshzle(1) man page to learn about the kinds of values you
+ may assign to this variable.
+
+* `HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS` is a global variable that defines
+ how the command history will be searched for your query. Its default value
+ causes this script to perform a case-insensitive search. See the "Globbing
+ Flags" section in the zshexpn(1) man page to learn about the kinds of
+ values you may assign to this variable.
+
+* `HISTORY_SUBSTRING_SEARCH_FUZZY` is a global variable that defines
+ how the command history will be searched for your query. If set to a non-empty
+ value, causes this script to perform a fuzzy search by words, matching in
+ given order e.g. `ab c` will match `*ab*c*`
+
+* `HISTORY_SUBSTRING_SEARCH_PREFIXED` is a global variable that defines how
+ the command history will be searched for your query. If set to a non-empty
+ value, your query will be matched against the start of each history entry.
+ For example, if this variable is empty, `ls` will match `ls -l` and `echo
+ ls`; if it is non-empty, `ls` will only match `ls -l`.
+
+* `HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE` is a global variable that defines
+ whether all search results returned are _unique_. If set to a non-empty
+ value, then only unique search results are presented. This behaviour is off
+ by default. An alternative way to ensure that search results are unique is
+ to use `setopt HIST_IGNORE_ALL_DUPS`. If this configuration variable is off
+ and `setopt HIST_IGNORE_ALL_DUPS` is unset, then `setopt HIST_FIND_NO_DUPS`
+ is still respected and it makes this script skip duplicate _adjacent_ search
+ results as you cycle through them, but this does not guarantee that search
+ results are unique: if your search results were "Dog", "Dog", "HotDog",
+ "Dog", then cycling them gives "Dog", "HotDog", "Dog". Notice that the "Dog"
+ search result appeared twice as you cycled through them. If you wish to
+ receive globally unique search results only once, then use this
+ configuration variable, or use `setopt HIST_IGNORE_ALL_DUPS`.
+
+
+History
+------------------------------------------------------------------------------
+
+* September 2009: [Peter Stephenson][2] originally wrote this script and it
+ published to the zsh-users mailing list.
+
+* January 2011: Guido van Steen (@guidovansteen) revised this script and
+ released it under the 3-clause BSD license as part of [fizsh][3], the
+ Friendly Interactive ZSHell.
+
+* January 2011: Suraj N. Kurapati (@sunaku) extracted this script from
+ [fizsh][3] 1.0.1, refactored it heavily, and finally repackaged it as an
+ [oh-my-zsh plugin][4] and as an independently loadable [ZSH script][5].
+
+* July 2011: Guido van Steen, Suraj N. Kurapati, and Sorin Ionescu
+ (@sorin-ionescu) [further developed it][4] with Vincent Guerci (@vguerci).
+
+* March 2016: Geza Lore (@gezalore) greatly refactored it in pull request #55.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/zsh-history-substring-search.plugin.zsh b/dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/zsh-history-substring-search.plugin.zsh
new file mode 100644
index 00000000..93f894d2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/zsh-history-substring-search.plugin.zsh
@@ -0,0 +1,2 @@
+0=${(%):-%N}
+source ${0:A:h}/zsh-history-substring-search.zsh
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/zsh-history-substring-search.zsh b/dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/zsh-history-substring-search.zsh
new file mode 100644
index 00000000..b0a0a8d9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-history-substring-search/zsh-history-substring-search.zsh
@@ -0,0 +1,829 @@
+#!/usr/bin/env zsh
+##############################################################################
+#
+# Copyright (c) 2009 Peter Stephenson
+# Copyright (c) 2011 Guido van Steen
+# Copyright (c) 2011 Suraj N. Kurapati
+# Copyright (c) 2011 Sorin Ionescu
+# Copyright (c) 2011 Vincent Guerci
+# Copyright (c) 2016 Geza Lore
+# Copyright (c) 2017 Bengt Brodersen
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+#
+# * Neither the name of the FIZSH nor the names of its contributors
+# may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+##############################################################################
+
+#-----------------------------------------------------------------------------
+# declare global configuration variables
+#-----------------------------------------------------------------------------
+
+: ${HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND='bg=magenta,fg=white,bold'}
+: ${HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND='bg=red,fg=white,bold'}
+: ${HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS='i'}
+: ${HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE=''}
+: ${HISTORY_SUBSTRING_SEARCH_FUZZY=''}
+: ${HISTORY_SUBSTRING_SEARCH_PREFIXED=''}
+
+#-----------------------------------------------------------------------------
+# declare internal global variables
+#-----------------------------------------------------------------------------
+
+typeset -g BUFFER MATCH MBEGIN MEND CURSOR
+typeset -g _history_substring_search_refresh_display
+typeset -g _history_substring_search_query_highlight
+typeset -g _history_substring_search_result
+typeset -g _history_substring_search_query
+typeset -g -a _history_substring_search_query_parts
+typeset -g -a _history_substring_search_raw_matches
+typeset -g -i _history_substring_search_raw_match_index
+typeset -g -a _history_substring_search_matches
+typeset -g -i _history_substring_search_match_index
+typeset -g -A _history_substring_search_unique_filter
+typeset -g -i _history_substring_search_zsh_5_9
+
+#-----------------------------------------------------------------------------
+# the main ZLE widgets
+#-----------------------------------------------------------------------------
+
+history-substring-search-up() {
+ _history-substring-search-begin
+
+ _history-substring-search-up-history ||
+ _history-substring-search-up-buffer ||
+ _history-substring-search-up-search
+
+ _history-substring-search-end
+}
+
+history-substring-search-down() {
+ _history-substring-search-begin
+
+ _history-substring-search-down-history ||
+ _history-substring-search-down-buffer ||
+ _history-substring-search-down-search
+
+ _history-substring-search-end
+}
+
+zle -N history-substring-search-up
+zle -N history-substring-search-down
+
+#-----------------------------------------------------------------------------
+# implementation details
+#-----------------------------------------------------------------------------
+
+zmodload -F zsh/parameter
+autoload -Uz is-at-least
+
+if is-at-least 5.9 $ZSH_VERSION; then
+ _history_substring_search_zsh_5_9=1
+fi
+
+#
+# We have to "override" some keys and widgets if the
+# zsh-syntax-highlighting plugin has not been loaded:
+#
+# https://github.com/nicoulaj/zsh-syntax-highlighting
+#
+if [[ $+functions[_zsh_highlight] -eq 0 ]]; then
+ #
+ # Dummy implementation of _zsh_highlight() that
+ # simply removes any existing highlights when the
+ # user inserts printable characters into $BUFFER.
+ #
+ _zsh_highlight() {
+ if [[ $KEYS == [[:print:]] ]]; then
+ region_highlight=()
+ fi
+ }
+
+ #
+ # Check if $1 denotes the name of a callable function, i.e. it is fully
+ # defined or it is marked for autoloading and autoloading it at the first
+ # call to it will succeed. In particular, if $1 has been marked for
+ # autoloading but is not available in $fpath, then it will return 1 (false).
+ #
+ # This is based on the zsh-syntax-highlighting plugin.
+ #
+ _history-substring-search-function-callable() {
+ if (( ${+functions[$1]} )) && ! [[ "$functions[$1]" == *"builtin autoload -X"* ]]; then
+ return 0 # already fully loaded
+ else
+ # "$1" is either an autoload stub, or not a function at all.
+ # We expect 'autoload +X' to return non-zero if it fails to fully load
+ # the function.
+ ( autoload -U +X -- "$1" 2>/dev/null )
+ return $?
+ fi
+ }
+
+ #
+ # The zsh-syntax-highlighting plugin uses zle-line-pre-redraw hook instead
+ # of the legacy "bind all widgets" if 1) zsh has the memo= feature (added in
+ # version 5.9) and 2) add-zle-hook-widget is available.
+ #
+ if [[ $_history_substring_search_zsh_5_9 -eq 1 ]] && _history-substring-search-function-callable add-zle-hook-widget; then
+ #
+ # The following code is based on the zsh-syntax-highlighting plugin.
+ #
+ autoload -U add-zle-hook-widget
+
+ _history-substring-search-zle-line-finish() {
+ #
+ # Reset $WIDGET since the 'main' highlighter depends on it.
+ #
+ # Since $WIDGET is declared by zle as read-only in this function's scope,
+ # a nested function is required in order to shadow its built-in value;
+ # see "User-defined widgets" in zshall.
+ #
+ () {
+ local -h -r WIDGET=zle-line-finish
+ _zsh_highlight
+ }
+ }
+
+ _history-substring-search-zle-line-pre-redraw() {
+ #
+ # If the zsh-syntax-highlighting plugin has been loaded (after our plugin
+ # plugin, otherwise this hook wouldn't be called), remove our hooks.
+ #
+ if [[ $+ZSH_HIGHLIGHT_VERSION -eq 1 ]]; then
+ autoload -U add-zle-hook-widget
+ add-zle-hook-widget -d zle-line-pre-redraw _history-substring-search-zle-line-pre-redraw
+ add-zle-hook-widget -d zle-line-finish _history-substring-search-zle-line-finish
+ return 0
+ fi
+ #
+ # Set $? to 0 for _zsh_highlight. Without this, subsequent
+ # zle-line-pre-redraw hooks won't run, since add-zle-hook-widget happens to
+ # call us with $? == 1 in the common case.
+ #
+ true && _zsh_highlight "$@"
+ }
+
+ if [[ -o zle ]]; then
+ add-zle-hook-widget zle-line-pre-redraw _history-substring-search-zle-line-pre-redraw
+ add-zle-hook-widget zle-line-finish _history-substring-search-zle-line-finish
+ fi
+ else
+ #
+ # The following snippet was taken from the zsh-syntax-highlighting project:
+ # https://github.com/zsh-users/zsh-syntax-highlighting/blob/56b134f5d62ae3d4e66c7f52bd0cc2595f9b305b/zsh-syntax-highlighting.zsh#L126-161
+ #
+ # SPDX-SnippetBegin
+ # SPDX-License-Identifier: BSD-3-Clause
+ # SPDX-SnippetCopyrightText: 2010-2011 zsh-syntax-highlighting contributors
+ #--------------8<-------------------8<-------------------8<-----------------
+ # 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
+ }
+
+ # 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
+
+ # 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]#*:}; \
+ _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]#*:}/:/ }; \
+ _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 }; \
+ zle -N $cur_widget _zsh_highlight_widget_$cur_widget";;
+
+ # Default: unhandled case.
+ *) echo "zsh-syntax-highlighting: unhandled ZLE widget '$cur_widget'" >&2 ;;
+ esac
+ done
+ }
+ #-------------->8------------------->8------------------->8-----------------
+ # SPDX-SnippetEnd
+
+ _zsh_highlight_bind_widgets
+ fi
+
+ unfunction _history-substring-search-function-callable
+fi
+
+_history-substring-search-begin() {
+ setopt localoptions extendedglob
+
+ _history_substring_search_refresh_display=
+ _history_substring_search_query_highlight=
+
+ #
+ # If the buffer is the same as the previously displayed history substring
+ # search result, then just keep stepping through the match list. Otherwise
+ # start a new search.
+ #
+ if [[ -n $BUFFER && $BUFFER == ${_history_substring_search_result:-} ]]; then
+ return;
+ fi
+
+ #
+ # Clear the previous result.
+ #
+ _history_substring_search_result=''
+
+ if [[ -z $BUFFER ]]; then
+ #
+ # If the buffer is empty, we will just act like up-history/down-history
+ # in ZSH, so we do not need to actually search the history. This should
+ # speed things up a little.
+ #
+ _history_substring_search_query=
+ _history_substring_search_query_parts=()
+ _history_substring_search_raw_matches=()
+
+ else
+ #
+ # For the purpose of highlighting we keep a copy of the original
+ # query string.
+ #
+ _history_substring_search_query=$BUFFER
+
+ #
+ # compose search pattern
+ #
+ if [[ -n $HISTORY_SUBSTRING_SEARCH_FUZZY ]]; then
+ #
+ # `=` split string in arguments
+ #
+ _history_substring_search_query_parts=(${=_history_substring_search_query})
+ else
+ _history_substring_search_query_parts=(${==_history_substring_search_query})
+ fi
+
+ #
+ # Escape and join query parts with wildcard character '*' as seperator
+ # `(j:CHAR:)` join array to string with CHAR as seperator
+ #
+ local search_pattern="${(j:*:)_history_substring_search_query_parts[@]//(#m)[\][()|\\*?#<>~^]/\\$MATCH}*"
+
+ #
+ # Support anchoring history search to the beginning of the command
+ #
+ if [[ -z $HISTORY_SUBSTRING_SEARCH_PREFIXED ]]; then
+ search_pattern="*${search_pattern}"
+ fi
+
+ #
+ # Find all occurrences of the search pattern in the history file.
+ #
+ # (k) returns the "keys" (history index numbers) instead of the values
+ # (R) returns values in reverse older, so the index of the youngest
+ # matching history entry is at the head of the list.
+ #
+ _history_substring_search_raw_matches=(${(k)history[(R)(#$HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS)${search_pattern}]})
+ fi
+
+ #
+ # In order to stay as responsive as possible, we will process the raw
+ # matches lazily (when the user requests the next match) to choose items
+ # that need to be displayed to the user.
+ # _history_substring_search_raw_match_index holds the index of the last
+ # unprocessed entry in _history_substring_search_raw_matches. Any items
+ # that need to be displayed will be added to
+ # _history_substring_search_matches.
+ #
+ # We use an associative array (_history_substring_search_unique_filter) as
+ # a 'set' data structure to ensure uniqueness of the results if desired.
+ # If an entry (key) is in the set (non-empty value), then we have already
+ # added that entry to _history_substring_search_matches.
+ #
+ _history_substring_search_raw_match_index=0
+ _history_substring_search_matches=()
+ _history_substring_search_unique_filter=()
+
+ #
+ # If $_history_substring_search_match_index is equal to
+ # $#_history_substring_search_matches + 1, this indicates that we
+ # are beyond the end of $_history_substring_search_matches and that we
+ # have also processed all entries in
+ # _history_substring_search_raw_matches.
+ #
+ # If $#_history_substring_search_match_index is equal to 0, this indicates
+ # that we are beyond the beginning of $_history_substring_search_matches.
+ #
+ # If we have initially pressed "up" we have to initialize
+ # $_history_substring_search_match_index to 0 so that it will be
+ # incremented to 1.
+ #
+ # If we have initially pressed "down" we have to initialize
+ # $_history_substring_search_match_index to 1 so that it will be
+ # decremented to 0.
+ #
+ if [[ $WIDGET == history-substring-search-down ]]; then
+ _history_substring_search_match_index=1
+ else
+ _history_substring_search_match_index=0
+ fi
+}
+
+_history-substring-search-end() {
+ setopt localoptions extendedglob
+
+ local highlight_memo=
+ _history_substring_search_result=$BUFFER
+
+ if [[ $_history_substring_search_zsh_5_9 -eq 1 ]]; then
+ highlight_memo='memo=history-substring-search'
+ fi
+
+ # the search was successful so display the result properly by clearing away
+ # existing highlights and moving the cursor to the end of the result buffer
+ if [[ $_history_substring_search_refresh_display -eq 1 ]]; then
+ if [[ -n $highlight_memo ]]; then
+ region_highlight=( "${(@)region_highlight:#*${highlight_memo}*}" )
+ else
+ region_highlight=()
+ fi
+ CURSOR=${#BUFFER}
+ fi
+
+ # highlight command line using zsh-syntax-highlighting
+ _zsh_highlight
+
+ # highlight the search query inside the command line
+ if [[ -n $_history_substring_search_query_highlight ]]; then
+ # highlight first matching query parts
+ local highlight_start_index=0
+ local highlight_end_index=0
+ local query_part
+ for query_part in $_history_substring_search_query_parts; do
+ local escaped_query_part=${query_part//(#m)[\][()|\\*?#<>~^]/\\$MATCH}
+ # (i) get index of pattern
+ local query_part_match_index="${${BUFFER:$highlight_start_index}[(i)(#$HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS)${escaped_query_part}]}"
+ if [[ $query_part_match_index -le ${#BUFFER:$highlight_start_index} ]]; then
+ highlight_start_index=$(( $highlight_start_index + $query_part_match_index ))
+ highlight_end_index=$(( $highlight_start_index + ${#query_part} ))
+ region_highlight+=(
+ "$(($highlight_start_index - 1)) $(($highlight_end_index - 1)) ${_history_substring_search_query_highlight}${highlight_memo:+,$highlight_memo}"
+ )
+ fi
+ done
+ fi
+
+ # For debugging purposes:
+ # zle -R "mn: "$_history_substring_search_match_index" m#: "${#_history_substring_search_matches}
+ # read -k -t 200 && zle -U $REPLY
+
+ # Exit successfully from the history-substring-search-* widgets.
+ return 0
+}
+
+_history-substring-search-up-buffer() {
+ #
+ # Check if the UP arrow was pressed to move the cursor within a multi-line
+ # buffer. This amounts to three tests:
+ #
+ # 1. $#buflines -gt 1.
+ #
+ # 2. $CURSOR -ne $#BUFFER.
+ #
+ # 3. Check if we are on the first line of the current multi-line buffer.
+ # If so, pressing UP would amount to leaving the multi-line buffer.
+ #
+ # We check this by adding an extra "x" to $LBUFFER, which makes
+ # sure that xlbuflines is always equal to the number of lines
+ # until $CURSOR (including the line with the cursor on it).
+ #
+ local buflines XLBUFFER xlbuflines
+ buflines=(${(f)BUFFER})
+ XLBUFFER=$LBUFFER"x"
+ xlbuflines=(${(f)XLBUFFER})
+
+ if [[ $#buflines -gt 1 && $CURSOR -ne $#BUFFER && $#xlbuflines -ne 1 ]]; then
+ zle up-line-or-history
+ return 0
+ fi
+
+ return 1
+}
+
+_history-substring-search-down-buffer() {
+ #
+ # Check if the DOWN arrow was pressed to move the cursor within a multi-line
+ # buffer. This amounts to three tests:
+ #
+ # 1. $#buflines -gt 1.
+ #
+ # 2. $CURSOR -ne $#BUFFER.
+ #
+ # 3. Check if we are on the last line of the current multi-line buffer.
+ # If so, pressing DOWN would amount to leaving the multi-line buffer.
+ #
+ # We check this by adding an extra "x" to $RBUFFER, which makes
+ # sure that xrbuflines is always equal to the number of lines
+ # from $CURSOR (including the line with the cursor on it).
+ #
+ local buflines XRBUFFER xrbuflines
+ buflines=(${(f)BUFFER})
+ XRBUFFER="x"$RBUFFER
+ xrbuflines=(${(f)XRBUFFER})
+
+ if [[ $#buflines -gt 1 && $CURSOR -ne $#BUFFER && $#xrbuflines -ne 1 ]]; then
+ zle down-line-or-history
+ return 0
+ fi
+
+ return 1
+}
+
+_history-substring-search-up-history() {
+ #
+ # Behave like up in ZSH, except clear the $BUFFER
+ # when beginning of history is reached like in Fish.
+ #
+ if [[ -z $_history_substring_search_query ]]; then
+
+ # we have reached the absolute top of history
+ if [[ $HISTNO -eq 1 ]]; then
+ BUFFER=
+
+ # going up from somewhere below the top of history
+ else
+ zle up-line-or-history
+ fi
+
+ return 0
+ fi
+
+ return 1
+}
+
+_history-substring-search-down-history() {
+ #
+ # Behave like down-history in ZSH, except clear the
+ # $BUFFER when end of history is reached like in Fish.
+ #
+ if [[ -z $_history_substring_search_query ]]; then
+
+ # going down from the absolute top of history
+ if [[ $HISTNO -eq 1 && -z $BUFFER ]]; then
+ BUFFER=${history[1]}
+ _history_substring_search_refresh_display=1
+
+ # going down from somewhere above the bottom of history
+ else
+ zle down-line-or-history
+ fi
+
+ return 0
+ fi
+
+ return 1
+}
+
+_history_substring_search_process_raw_matches() {
+ #
+ # Process more outstanding raw matches and append any matches that need to
+ # be displayed to the user to _history_substring_search_matches.
+ # Return whether there were any more results appended.
+ #
+
+ #
+ # While we have more raw matches. Process them to see if there are any more
+ # matches that need to be displayed to the user.
+ #
+ while [[ $_history_substring_search_raw_match_index -lt $#_history_substring_search_raw_matches ]]; do
+ #
+ # Move on to the next raw entry and get its history index.
+ #
+ _history_substring_search_raw_match_index+=1
+ local index=${_history_substring_search_raw_matches[$_history_substring_search_raw_match_index]}
+
+ #
+ # If HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE is set to a non-empty value,
+ # then ensure that only unique matches are presented to the user.
+ # When HIST_IGNORE_ALL_DUPS is set, ZSH already ensures a unique history,
+ # so in this case we do not need to do anything.
+ #
+ if [[ ! -o HIST_IGNORE_ALL_DUPS && -n $HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE ]]; then
+ #
+ # Get the actual history entry at the new index, and check if we have
+ # already added it to _history_substring_search_matches.
+ #
+ local entry=${history[$index]}
+
+ if [[ -z ${_history_substring_search_unique_filter[$entry]} ]]; then
+ #
+ # This is a new unique entry. Add it to the filter and append the
+ # index to _history_substring_search_matches.
+ #
+ _history_substring_search_unique_filter[$entry]=1
+ _history_substring_search_matches+=($index)
+
+ #
+ # Indicate that we did find a match.
+ #
+ return 0
+ fi
+
+ else
+ #
+ # Just append the new history index to the processed matches.
+ #
+ _history_substring_search_matches+=($index)
+
+ #
+ # Indicate that we did find a match.
+ #
+ return 0
+ fi
+
+ done
+
+ #
+ # We are beyond the end of the list of raw matches. Indicate that no
+ # more matches are available.
+ #
+ return 1
+}
+
+_history-substring-search-has-next() {
+ #
+ # Predicate function that returns whether any more older matches are
+ # available.
+ #
+
+ if [[ $_history_substring_search_match_index -lt $#_history_substring_search_matches ]]; then
+ #
+ # We did not reach the end of the processed list, so we do have further
+ # matches.
+ #
+ return 0
+
+ else
+ #
+ # We are at the end of the processed list. Try to process further
+ # unprocessed matches. _history_substring_search_process_raw_matches
+ # returns whether any more matches were available, so just return
+ # that result.
+ #
+ _history_substring_search_process_raw_matches
+ return $?
+ fi
+}
+
+_history-substring-search-has-prev() {
+ #
+ # Predicate function that returns whether any more younger matches are
+ # available.
+ #
+
+ if [[ $_history_substring_search_match_index -gt 1 ]]; then
+ #
+ # We did not reach the beginning of the processed list, so we do have
+ # further matches.
+ #
+ return 0
+
+ else
+ #
+ # We are at the beginning of the processed list. We do not have any more
+ # matches.
+ #
+ return 1
+ fi
+}
+
+_history-substring-search-found() {
+ #
+ # A match is available. The index of the match is held in
+ # $_history_substring_search_match_index
+ #
+ # 1. Make $BUFFER equal to the matching history entry.
+ #
+ # 2. Use $HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND
+ # to highlight the current buffer.
+ #
+ BUFFER=$history[$_history_substring_search_matches[$_history_substring_search_match_index]]
+ _history_substring_search_query_highlight=$HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND
+}
+
+_history-substring-search-not-found() {
+ #
+ # No more matches are available.
+ #
+ # 1. Make $BUFFER equal to $_history_substring_search_query so the user can
+ # revise it and search again.
+ #
+ # 2. Use $HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND
+ # to highlight the current buffer.
+ #
+ BUFFER=$_history_substring_search_query
+ _history_substring_search_query_highlight=$HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND
+}
+
+_history-substring-search-up-search() {
+ _history_substring_search_refresh_display=1
+
+ #
+ # Select history entry during history-substring-down-search:
+ #
+ # The following variables have been initialized in
+ # _history-substring-search-up/down-search():
+ #
+ # $_history_substring_search_matches is the current list of matches that
+ # need to be displayed to the user.
+ # $_history_substring_search_match_index is the index of the current match
+ # that is being displayed to the user.
+ #
+ # The range of values that $_history_substring_search_match_index can take
+ # is: [0, $#_history_substring_search_matches + 1]. A value of 0
+ # indicates that we are beyond the beginning of
+ # $_history_substring_search_matches. A value of
+ # $#_history_substring_search_matches + 1 indicates that we are beyond
+ # the end of $_history_substring_search_matches and that we have also
+ # processed all entries in _history_substring_search_raw_matches.
+ #
+ # If $_history_substring_search_match_index equals
+ # $#_history_substring_search_matches and
+ # $_history_substring_search_raw_match_index is not greater than
+ # $#_history_substring_search_raw_matches, then we need to further process
+ # $_history_substring_search_raw_matches to see if there are any more
+ # entries that need to be displayed to the user.
+ #
+ # In _history-substring-search-up-search() the initial value of
+ # $_history_substring_search_match_index is 0. This value is set in
+ # _history-substring-search-begin(). _history-substring-search-up-search()
+ # will initially increment it to 1.
+ #
+
+ if [[ $_history_substring_search_match_index -gt $#_history_substring_search_matches ]]; then
+ #
+ # We are beyond the end of $_history_substring_search_matches. This
+ # can only happen if we have also exhausted the unprocessed matches in
+ # _history_substring_search_raw_matches.
+ #
+ # 1. Update display to indicate search not found.
+ #
+ _history-substring-search-not-found
+ return
+ fi
+
+ if _history-substring-search-has-next; then
+ #
+ # We do have older matches.
+ #
+ # 1. Move index to point to the next match.
+ # 2. Update display to indicate search found.
+ #
+ _history_substring_search_match_index+=1
+ _history-substring-search-found
+
+ else
+ #
+ # We do not have older matches.
+ #
+ # 1. Move the index beyond the end of
+ # _history_substring_search_matches.
+ # 2. Update display to indicate search not found.
+ #
+ _history_substring_search_match_index+=1
+ _history-substring-search-not-found
+ fi
+
+ #
+ # When HIST_FIND_NO_DUPS is set, meaning that only unique command lines from
+ # history should be matched, make sure the new and old results are different.
+ #
+ # However, if the HIST_IGNORE_ALL_DUPS shell option, or
+ # HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE is set, then we already have a
+ # unique history, so in this case we do not need to do anything.
+ #
+ if [[ -o HIST_IGNORE_ALL_DUPS || -n $HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE ]]; then
+ return
+ fi
+
+ if [[ -o HIST_FIND_NO_DUPS && $BUFFER == $_history_substring_search_result ]]; then
+ #
+ # Repeat the current search so that a different (unique) match is found.
+ #
+ _history-substring-search-up-search
+ fi
+}
+
+_history-substring-search-down-search() {
+ _history_substring_search_refresh_display=1
+
+ #
+ # Select history entry during history-substring-down-search:
+ #
+ # The following variables have been initialized in
+ # _history-substring-search-up/down-search():
+ #
+ # $_history_substring_search_matches is the current list of matches that
+ # need to be displayed to the user.
+ # $_history_substring_search_match_index is the index of the current match
+ # that is being displayed to the user.
+ #
+ # The range of values that $_history_substring_search_match_index can take
+ # is: [0, $#_history_substring_search_matches + 1]. A value of 0
+ # indicates that we are beyond the beginning of
+ # $_history_substring_search_matches. A value of
+ # $#_history_substring_search_matches + 1 indicates that we are beyond
+ # the end of $_history_substring_search_matches and that we have also
+ # processed all entries in _history_substring_search_raw_matches.
+ #
+ # In _history-substring-search-down-search() the initial value of
+ # $_history_substring_search_match_index is 1. This value is set in
+ # _history-substring-search-begin(). _history-substring-search-down-search()
+ # will initially decrement it to 0.
+ #
+
+ if [[ $_history_substring_search_match_index -lt 1 ]]; then
+ #
+ # We are beyond the beginning of $_history_substring_search_matches.
+ #
+ # 1. Update display to indicate search not found.
+ #
+ _history-substring-search-not-found
+ return
+ fi
+
+ if _history-substring-search-has-prev; then
+ #
+ # We do have younger matches.
+ #
+ # 1. Move index to point to the previous match.
+ # 2. Update display to indicate search found.
+ #
+ _history_substring_search_match_index+=-1
+ _history-substring-search-found
+
+ else
+ #
+ # We do not have younger matches.
+ #
+ # 1. Move the index beyond the beginning of
+ # _history_substring_search_matches.
+ # 2. Update display to indicate search not found.
+ #
+ _history_substring_search_match_index+=-1
+ _history-substring-search-not-found
+ fi
+
+ #
+ # When HIST_FIND_NO_DUPS is set, meaning that only unique command lines from
+ # history should be matched, make sure the new and old results are different.
+ #
+ # However, if the HIST_IGNORE_ALL_DUPS shell option, or
+ # HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE is set, then we already have a
+ # unique history, so in this case we do not need to do anything.
+ #
+ if [[ -o HIST_IGNORE_ALL_DUPS || -n $HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE ]]; then
+ return
+ fi
+
+ if [[ -o HIST_FIND_NO_DUPS && $BUFFER == $_history_substring_search_result ]]; then
+ #
+ # Repeat the current search so that a different (unique) match is found.
+ #
+ _history-substring-search-down-search
+ fi
+}
+
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.editorconfig b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.editorconfig
new file mode 100644
index 00000000..cda541d5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.editorconfig
@@ -0,0 +1,15 @@
+# Top-most editorconfig file
+
+root = true
+
+[*]
+end_of_line = lf
+tab_width = 2
+indent_size = 2
+indent_style = space
+
+[Makefile]
+tab_width = 8
+indent_size = 8
+indent_style = tab
+
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.revision-hash b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.revision-hash
new file mode 100644
index 00000000..6828f88d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.revision-hash
@@ -0,0 +1 @@
+$Format:%H$
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.version b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.version
new file mode 100644
index 00000000..9fb12109
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.version
@@ -0,0 +1 @@
+0.8.0-alpha2-dev
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/COPYING.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/COPYING.md
new file mode 100644
index 00000000..cacbcbee
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/COPYING.md
@@ -0,0 +1,23 @@
+Copyright (c) 2010-2020 zsh-syntax-highlighting contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted
+provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of
+ conditions and the following disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+ may be used to endorse or promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/HACKING.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/HACKING.md
new file mode 100644
index 00000000..ddd39a4e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/HACKING.md
@@ -0,0 +1,99 @@
+Hacking on zsh-syntax-highlighting itself
+=========================================
+
+This document includes information for people working on z-sy-h itself: on the
+core driver (`zsh-syntax-highlighting.zsh`), on the highlighters in the
+distribution, and on the test suite. It does not target third-party
+highlighter authors (although they may find it an interesting read).
+
+The `main` highlighter
+----------------------
+
+The following function `pz` is useful when working on the `main` highlighting:
+
+```zsh
+pq() {
+ (( $#argv )) || return 0
+ print -r -l -- ${(qqqq)argv}
+}
+pz() {
+ local arg
+ for arg; do
+ pq ${(z)arg}
+ done
+}
+```
+
+It prints, for each argument, its token breakdown, similar to how the main
+loop of the `main` highlighter sees it.
+
+Testing the `brackets` highlighter
+----------------------------------
+
+Since the test harness empties `ZSH_HIGHLIGHT_STYLES` and the `brackets`
+highlighter interrogates `ZSH_HIGHLIGHT_STYLES` to determine how to highlight,
+tests must set the `bracket-level-#` keys themselves. For example:
+
+```zsh
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-2]=
+
+BUFFER='echo ({x})'
+
+expected_region_highlight=(
+ "6 6 bracket-level-1" # (
+ "7 7 bracket-level-2" # {
+ "9 9 bracket-level-2" # }
+ "10 10 bracket-level-1" # )
+)
+```
+
+Testing the `pattern` and `regexp` highlighters
+-----------------------------------------------
+
+Because the `pattern` and `regexp` highlighters modifies `region_highlight`
+directly instead of using `_zsh_highlight_add_highlight`, the test harness
+cannot get the `ZSH_HIGHLIGHT_STYLES` keys. Therefore, when writing tests, use
+the style itself as third word (cf. the
+[documentation for `expected_region_highlight`](docs/highlighters.md)). For example:
+
+```zsh
+ZSH_HIGHLIGHT_PATTERNS+=('rm -rf *' 'fg=white,bold,bg=red')
+
+BUFFER='rm -rf /'
+
+expected_region_highlight=(
+ "1 8 fg=white,bold,bg=red" # rm -rf /
+)
+```
+
+Memos and commas
+----------------
+
+We append to `region_highlight` as follows:
+
+
+```zsh
+region_highlight+=("$start $end $spec, memo=zsh-syntax-highlighting")
+```
+
+That comma is required to cause zsh 5.8 and older to ignore the memo without
+ignoring the `$spec`. It's a hack, but given that no further 5.8.x patch
+releases are planned, it's been deemed acceptable. See issue #418 and the
+cross-referenced issues.
+
+
+Miscellany
+----------
+
+If you work on the driver (`zsh-syntax-highlighting.zsh`), you may find the following zstyle useful:
+
+```zsh
+zstyle ':completion:*:*:*:*:globbed-files' ignored-patterns {'*/',}zsh-syntax-highlighting.plugin.zsh
+```
+
+IRC channel
+-----------
+
+We're on #zsh-syntax-highlighting on Libera.Chat.
+
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/INSTALL.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/INSTALL.md
new file mode 100644
index 00000000..024dbd9c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/INSTALL.md
@@ -0,0 +1,137 @@
+How to install
+--------------
+
+### Using packages
+
+* Arch Linux: [community/zsh-syntax-highlighting][arch-package] / [AUR/zsh-syntax-highlighting-git][AUR-package]
+* Debian: `zsh-syntax-highlighting` package [in `stretch`][debian-package] (or in [OBS repository][obs-repository])
+* Fedora: [zsh-syntax-highlighting package][fedora-package-alt] in Fedora 24+ (or in [OBS repository][obs-repository])
+* FreeBSD: `pkg install zsh-syntax-highlighting` (port name: [`shells/zsh-syntax-highlighting`][freebsd-port])
+* Gentoo: [app-shells/zsh-syntax-highlighting][gentoo-repository]
+* Mac OS X / Homebrew: [brew install zsh-syntax-highlighting][brew-package]
+* NetBSD: `pkg_add zsh-syntax-highlighting` (port name: [`shells/zsh-syntax-highlighting`][netbsd-port])
+* OpenBSD: `pkg_add zsh-syntax-highlighting` (port name: [`shells/zsh-syntax-highlighting`][openbsd-port])
+* openSUSE / SLE: `zsh-syntax-highlighting` package in [OBS repository][obs-repository]
+* RHEL / CentOS / Scientific Linux: `zsh-syntax-highlighting` package in [OBS repository][obs-repository]
+* Ubuntu: `zsh-syntax-highlighting` package [in Xenial][ubuntu-package] (or in [OBS repository][obs-repository])
+* Void Linux: `zsh-syntax-highlighting package` [in XBPS][void-package]
+
+[arch-package]: https://www.archlinux.org/packages/zsh-syntax-highlighting
+[AUR-package]: https://aur.archlinux.org/packages/zsh-syntax-highlighting-git
+[brew-package]: https://github.com/Homebrew/homebrew-core/blob/master/Formula/zsh-syntax-highlighting.rb
+[debian-package]: https://packages.debian.org/zsh-syntax-highlighting
+[fedora-package]: https://apps.fedoraproject.org/packages/zsh-syntax-highlighting
+[fedora-package-alt]: https://bodhi.fedoraproject.org/updates/?packages=zsh-syntax-highlighting
+[freebsd-port]: http://www.freshports.org/textproc/zsh-syntax-highlighting/
+[gentoo-repository]: https://packages.gentoo.org/packages/app-shells/zsh-syntax-highlighting
+[netbsd-port]: http://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/shells/zsh-syntax-highlighting/
+[obs-repository]: https://software.opensuse.org/download.html?project=shells%3Azsh-users%3Azsh-syntax-highlighting&package=zsh-syntax-highlighting
+[openbsd-port]: https://cvsweb.openbsd.org/ports/shells/zsh-syntax-highlighting/
+[ubuntu-package]: https://launchpad.net/ubuntu/+source/zsh-syntax-highlighting
+[void-package]: https://github.com/void-linux/void-packages/tree/master/srcpkgs/zsh-syntax-highlighting
+
+See also [repology's cross-distro index](https://repology.org/metapackage/zsh-syntax-highlighting/versions)
+
+
+### In your ~/.zshrc
+
+Simply clone this repository and source the script:
+
+```zsh
+git clone https://github.com/zsh-users/zsh-syntax-highlighting.git
+echo "source ${(q-)PWD}/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" >> ${ZDOTDIR:-$HOME}/.zshrc
+```
+
+ Then, enable syntax highlighting in the current interactive shell:
+
+```zsh
+source ./zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
+```
+
+ If `git` is not installed, download and extract a snapshot of the latest
+ development tree from:
+
+```
+https://github.com/zsh-users/zsh-syntax-highlighting/archive/master.tar.gz
+```
+
+ Note the `source` command must be **at the end** of `~/.zshrc`.
+
+
+### With a plugin manager
+
+Note that `zsh-syntax-highlighting` must be the last plugin sourced.
+
+The zsh-syntax-highlighting authors recommend manual installation over the use
+of a framework or plugin manager.
+
+This list is incomplete as there are too many
+[frameworks / plugin managers][framework-list] to list them all here.
+
+[framework-list]: https://github.com/unixorn/awesome-zsh-plugins#frameworks
+
+#### [Antigen](https://github.com/zsh-users/antigen)
+
+Add `antigen bundle zsh-users/zsh-syntax-highlighting` as the last bundle in
+your `.zshrc`.
+
+#### [Fig](https://fig.io)
+
+Click the `Install Plugin` button on the [Fig plugin page][fig-plugin].
+
+[fig-plugin]: https://fig.io/plugins/other/zsh-syntax-highlighting
+
+#### [Oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh)
+
+1. Clone this repository in oh-my-zsh's plugins directory:
+
+ ```zsh
+ git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
+ ```
+
+2. Activate the plugin in `~/.zshrc`:
+
+ ```zsh
+ plugins=( [plugins...] zsh-syntax-highlighting)
+ ```
+
+3. Restart zsh (such as by opening a new instance of your terminal emulator).
+
+#### [Prezto](https://github.com/sorin-ionescu/prezto)
+
+Zsh-syntax-highlighting is included with Prezto. See the
+[Prezto documentation][prezto-docs] to enable and configure highlighters.
+
+[prezto-docs]: https://github.com/sorin-ionescu/prezto/tree/master/modules/syntax-highlighting
+
+#### [zgen](https://github.com/tarjoilija/zgen)
+
+Add `zgen load zsh-users/zsh-syntax-highlighting` to the end of your `.zshrc`.
+
+#### [zplug](https://github.com/zplug/zplug)
+
+Add `zplug "zsh-users/zsh-syntax-highlighting", defer:2` to your `.zshrc`.
+
+#### [zplugin](https://github.com/psprint/zplugin)
+
+Add `zplugin load zsh-users/zsh-syntax-highlighting` to the end of your
+`.zshrc`.
+
+
+### System-wide installation
+
+Any of the above methods is suitable for a single-user installation,
+which requires no special privileges. If, however, you desire to install
+zsh-syntax-highlighting system-wide, you may do so by running
+
+```zsh
+make install
+```
+
+and directing your users to add
+
+```zsh
+source /usr/local/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
+```
+
+to their `.zshrc`s.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/Makefile b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/Makefile
new file mode 100644
index 00000000..bbc1d439
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/Makefile
@@ -0,0 +1,64 @@
+NAME=zsh-syntax-highlighting
+
+INSTALL?=install -c
+PREFIX?=/usr/local
+SHARE_DIR?=$(DESTDIR)$(PREFIX)/share/$(NAME)
+DOC_DIR?=$(DESTDIR)$(PREFIX)/share/doc/$(NAME)
+ZSH?=zsh # zsh binary to run tests with
+
+all:
+ cd docs && \
+ cp highlighters.md all.md && \
+ printf '\n\nIndividual highlighters documentation\n=====================================' >> all.md && \
+ for doc in highlighters/*.md; do printf '\n\n'; cat "$$doc"; done >> all.md
+
+install: all
+ $(INSTALL) -d $(SHARE_DIR)
+ $(INSTALL) -d $(DOC_DIR)
+ cp .version zsh-syntax-highlighting.zsh $(SHARE_DIR)
+ cp COPYING.md README.md changelog.md $(DOC_DIR)
+ sed -e '1s/ .*//' -e '/^\[build-status-[a-z]*\]: /d' < README.md > $(DOC_DIR)/README.md
+ if [ x"true" = x"`git rev-parse --is-inside-work-tree 2>/dev/null`" ]; then \
+ git rev-parse HEAD; \
+ else \
+ cat .revision-hash; \
+ fi > $(SHARE_DIR)/.revision-hash
+ :
+# The [ -e ] check below is to because sh evaluates this with (the moral
+# equivalent of) NONOMATCH in effect, and highlighters/*.zsh has no matches.
+ for dirname in highlighters highlighters/*/ ; do \
+ $(INSTALL) -d $(SHARE_DIR)/"$$dirname"; \
+ for fname in "$$dirname"/*.zsh ; do [ -e "$$fname" ] && cp "$$fname" $(SHARE_DIR)"/$$dirname"; done; \
+ done
+ cp -R docs/* $(DOC_DIR)
+
+clean:
+ rm -f docs/all.md
+
+test:
+ @$(ZSH) -fc 'echo ZSH_PATCHLEVEL=$$ZSH_PATCHLEVEL'
+ @result=0; \
+ for test in highlighters/*; do \
+ if [ -d $$test/test-data ]; then \
+ echo "Running test $${test##*/}"; \
+ env -i QUIET=$$QUIET $${TERM:+"TERM=$$TERM"} $(ZSH) -f tests/test-highlighting.zsh "$${test##*/}"; \
+ : $$(( result |= $$? )); \
+ fi \
+ done; \
+ exit $$result
+
+quiet-test:
+ $(MAKE) test QUIET=y
+
+perf:
+ @result=0; \
+ for test in highlighters/*; do \
+ if [ -d $$test/test-data ]; then \
+ echo "Running test $${test##*/}"; \
+ $(ZSH) -f tests/test-perfs.zsh "$${test##*/}"; \
+ : $$(( result |= $$? )); \
+ fi \
+ done; \
+ exit $$result
+
+.PHONY: all install clean test perf
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/README.md
new file mode 100644
index 00000000..4768b3dd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/README.md
@@ -0,0 +1,97 @@
+zsh-syntax-highlighting [![Build Status][build-status-image]][build-status]
+=======================
+
+**[Fish shell][fish]-like syntax highlighting for [Zsh][zsh].**
+
+*Requirements: zsh 4.3.11+.*
+
+[fish]: https://fishshell.com/
+[zsh]: https://www.zsh.org/
+
+This package provides syntax highlighting for the shell zsh. It enables
+highlighting of commands whilst they are typed at a zsh prompt into an
+interactive terminal. This helps in reviewing commands before running
+them, particularly in catching syntax errors.
+
+Some examples:
+
+Before: [![Screenshot #1.1](images/before1-smaller.png)](images/before1.png)
+<br/>
+After:&nbsp; [![Screenshot #1.2](images/after1-smaller.png)](images/after1.png)
+
+Before: [![Screenshot #2.1](images/before2-smaller.png)](images/before2.png)
+<br/>
+After:&nbsp; [![Screenshot #2.2](images/after2-smaller.png)](images/after2.png)
+
+Before: [![Screenshot #3.1](images/before3-smaller.png)](images/before3.png)
+<br/>
+After:&nbsp; [![Screenshot #3.2](images/after3-smaller.png)](images/after3.png)
+
+Before: [![Screenshot #4.1](images/before4-smaller.png)](images/before4-smaller.png)
+<br/>
+After:&nbsp; [![Screenshot #4.2](images/after4-smaller.png)](images/after4-smaller.png)
+
+
+
+How to install
+--------------
+
+See [INSTALL.md](INSTALL.md).
+
+
+FAQ
+---
+
+### Why must `zsh-syntax-highlighting.zsh` be sourced at the end of the `.zshrc` file?
+
+zsh-syntax-highlighting works by hooking into the Zsh Line Editor (ZLE) and
+computing syntax highlighting for the command-line buffer as it stands at the
+time z-sy-h's hook is invoked.
+
+In zsh 5.2 and older,
+`zsh-syntax-highlighting.zsh` hooks into ZLE by wrapping ZLE widgets. It must
+be sourced after all custom widgets have been created (i.e., after all `zle -N`
+calls and after running `compinit`) in order to be able to wrap all of them.
+Widgets created after z-sy-h is sourced will work, but will not update the
+syntax highlighting.
+
+In zsh newer than 5.8 (not including 5.8 itself),
+zsh-syntax-highlighting uses the `add-zle-hook-widget` facility to install
+a `zle-line-pre-redraw` hook. Hooks are run in order of registration,
+therefore, z-sy-h must be sourced (and register its hook) after anything else
+that adds hooks that modify the command-line buffer.
+
+### Does syntax highlighting work during incremental history search?
+
+Highlighting the command line during an incremental history search (by default bound to
+to <kbd>Ctrl+R</kbd> in zsh's emacs keymap) requires zsh 5.4 or newer.
+
+Under zsh versions older than 5.4, the zsh-default [underlining][zshzle-Character-Highlighting]
+of the matched portion of the buffer remains available, but zsh-syntax-highlighting's
+additional highlighting is unavailable. (Those versions of zsh do not provide
+enough information to allow computing the highlighting correctly.)
+
+See issues [#288][i288] and [#415][i415] for details.
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
+[i288]: https://github.com/zsh-users/zsh-syntax-highlighting/pull/288
+[i415]: https://github.com/zsh-users/zsh-syntax-highlighting/pull/415
+
+### How are new releases announced?
+
+There is currently no "push" announcements channel. However, the following
+alternatives exist:
+
+- GitHub's RSS feed of releases: https://github.com/zsh-users/zsh-syntax-highlighting/releases.atom
+- An anitya entry: https://release-monitoring.org/project/7552/
+
+
+How to tweak
+------------
+
+Syntax highlighting is done by pluggable highlighter scripts. See the
+[documentation on highlighters](docs/highlighters.md) for details and
+configuration settings.
+
+[build-status]: https://github.com/zsh-users/zsh-syntax-highlighting/actions
+[build-status-image]: https://github.com/zsh-users/zsh-syntax-highlighting/workflows/Tests/badge.svg
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/changelog.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/changelog.md
new file mode 100644
index 00000000..861fea5f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/changelog.md
@@ -0,0 +1,884 @@
+# Changes in HEAD
+
+
+## Changes fixed as part of the switch to zle-line-pre-redraw
+
+The changes in this section were fixed by switching to a `zle-line-pre-redraw`-based
+implementation.
+
+Note: The new implementation will only be used on future zsh releases,
+numbered 5.8.1.1 and newer, due to interoperability issues with other plugins
+(issues #418 and #579). The underlying zsh feature has been available since
+zsh 5.3.
+
+Whilst under development, the new implementation was known as the
+"feature/redrawhook" topic branch.
+
+- Fixed: Highlighting not triggered after popping a buffer from the buffer stack
+ (using the `push-line` widget, default binding: `M-q`)
+ [#40]
+
+- Fixed: Invoking completion when there were no matches removed highlighting
+ [#90, #470]
+
+- Fixed: Two successive deletes followed by a yank only yanked the latest
+ delete, rather than both of them
+ [#150, #151, #160; cf. #183]
+
+- Presumed fixed: Completing `$(xsel)` results in an error message from `xsel`,
+ with pre-2017 versions of `xsel`. (For 2017 vintage and newer, see the issue
+ for details.)
+ [#154]
+
+- Fixed: When the standard `bracketed-paste-magic` widget is in use, pastes were slow
+ [#295]
+
+- Fixed: No way to prevent a widget from being wrapped
+ [#324]
+
+- Fixed: No highlighting while cycling menu completion
+ [#375]
+
+- Fixed: Does not coexist with the `IGNORE_EOF` option
+ [#377]
+
+- Fixed: The `undefined-key` widget was wrapped
+ [#421]
+
+- Fixed: Does not coexist with the standard `surround` family of widgets
+ [#520]
+
+- Fixed: First completed filename doesn't get `path` highlighting
+ [#632]
+
+
+## Other changes
+
+- Add issue #712 to the previous release's changelog (hereinafter).
+
+
+# Changes in 0.8.0-alpha1-pre-redrawhook
+
+## Notice about an improbable-but-not-impossible forward incompatibility
+
+Everyone can probably skip this section.
+
+The `master` branch of zsh-syntax-highlighting uses a zsh feature that has not
+yet appeared in a zsh release: the `memo=` feature, added to zsh in commit
+zsh-5.8-172-gdd6e702ee (after zsh 5.8, before zsh 5.9). In the unlikely event
+that this zsh feature should change in an incompatible way before the next
+stable zsh release, set `zsh_highlight__memo_feature=0` in your .zshrc files to
+disable use of the new feature.
+
+z-sy-h dogfoods the new, unreleased zsh feature because that feature was
+added to zsh at z-sy-h's initiative. The new feature is used in the fix
+to issue #418.
+
+
+## Incompatible changes:
+
+- An unsuccessful completion (a <kbd>⮀ Tab</kbd> press that doesn't change the
+ command line) no longer causes highlighting to be lost. Visual feedback can
+ alternatively be achieved by setting the `format` zstyle under the `warnings`
+ tag, for example,
+
+ zstyle ':completion:*:warnings' format '%F{red}No matches%f'
+
+ Refer to the [description of the `format` style in `zshcompsys(1)`]
+ [zshcompsys-Standard-Styles-format].
+
+ (#90, part of #245 (feature/redrawhook))
+
+[zshcompsys-Standard-Styles]: https://zsh.sourceforge.io/Doc/Release/Completion-System.html#Standard-Styles
+[zshcompsys-Standard-Styles-format]: https://zsh.sourceforge.io/Doc/Release/Completion-System.html#index-format_002c-completion-style
+
+
+
+## Other changes:
+
+- Document `$ZSH_HIGHLIGHT_MAXLENGTH`.
+ [#698]
+
+- Optimize highlighting unquoted words (words that are not in single quotes, double quotes, backticks, or dollar-single-quotes)
+ [#730]
+
+- Redirection operators (e.g., `<` and `>`) are now highlighted by default
+ [#646]
+
+- Propertly terminate `noglob` scope in try/always blocks
+ [#577]
+
+- Don't error out when `KSH_ARRAYS` is set in the calling scope
+ [#622, #689]
+
+- Literal semicolons in array assignments (`foo=( bar ; baz )`) are now
+ highlighted as errors.
+ [3ca93f864fb6]
+
+- Command separators in array assignments (`foo=( bar | baz )`) are now
+ highlighted as errors.
+ [#651, 81267ca3130c]
+
+- Support parameter elision in command position (e.g., `$foo ls` where `$foo` is unset or empty)
+ [#667]
+
+- Don't consider the filename in `sudo -e /path/to/file` to be a command position
+ [#678]
+
+- Don't look up absolute directory names in $cdpath
+ [2cc2583f8f12, part of #669]
+
+- Fix `exec 2>&1;` being highlighted as an error.
+ [#676]
+
+- Fix `: $(<*)` being highlighted as globbing.
+ [#582]
+
+- Fix `cat < *` being highlighting as globbing when the `MULTIOS` option is unset.
+ [#583]
+
+- Fix `echo >&2` highlighting the `2` as a filename if a file by that name happened to exist
+ [#694, part of #645]
+
+- Fix `echo >&-` highlighting the `-` as a filename if a file by that name happened to exist
+ [part of #645]
+
+- Fix `echo >&p` highlighting the `p` as a filename if a file by that name happened to exist
+ [part of #645]
+
+- Fix wrong highlighting of unquoted parameter expansions under zsh 5.2 and older
+ [e165f18c758e]
+
+- Highlight global aliases
+ [#700]
+
+- Highlight `: =nosuchcommand' as an error (when the `EQUALS` option hasn't been unset).
+ [#430]
+
+- Highlight reserved word after assignments as errors (e.g., `foo=bar (ls;)`)
+ [#461]
+
+- Correctly highlight `[[ foo && bar || baz ]]`.
+
+- Highlight non-executable files in command position correctly (e.g., `% /etc/passwd`)
+ [#202, #669]
+
+- Highlight directories in command position correctly, including `AUTO_CD` support
+ [#669]
+
+- Recognize `env` as a precommand (e.g., `env FOO=bar ls`)
+
+- Recognize `strace` as a precommand
+
+- Fix an error message on stderr before every prompt when the `WARN_NESTED_VAR` zsh option is set:
+ `_zsh_highlight_main__precmd_hook:1: array parameter _zsh_highlight_main__command_type_cache set in enclosing scope in function _zsh_highlight_main__precmd_hook`
+ [#727, #731, #732, #733]
+
+- Fix highlighting of alias whose definitions use a simple command terminator
+ (such as `;`, `|`, `&&`) before a newline
+ [#677; had regressed in 0.7.0]
+
+- Highlight arithmetic expansions (e.g., `$(( 42 ))`)
+ [#607 #649 #704]
+
+- Highlight the parentheses of array assignments as reserved words (`foo=( bar )`).
+ The `assign` style remains supported and has precedence.
+ [#585]
+
+- Fix interoperability issue with other plugins that use highlighting. The fix
+ requires zsh 5.8.0.3 or newer. (zsh 5.8.0.2-dev from the `master` branch,
+ revision zsh-5.8-172-gdd6e702ee or newer is also fine.)
+ [#418, https://github.com/okapia/zsh-viexchange/issues/1]
+
+- Improve performance of the `brackets` highlighter.
+
+- Fix highlighting of pre-command redirections (e.g., the `$fn` in `<$fn cat`)
+ [#712]
+
+
+# Changes in version 0.7.1
+
+- Remove out-of-date information from the 0.7.0 changelog.
+
+
+# Changes in version 0.7.0
+
+This is a stable bugfix and feature release. Major new features and changes include:
+
+- Add `ZSH_HIGHLIGHT_DIRS_BLACKLIST` to disable "path" and "path prefix"
+ highlighting for specific directories
+ [#379]
+
+- Add the "regexp" highlighter, modelled after the pattern highlighter
+ [4e6f60063f1c]
+
+- When a word uses globbing, only the globbing metacharacters will be highlighted as globbing:
+ in `: foo*bar`, only the `*` will be blue.
+ [e48af357532c]
+
+- Highlight pasted quotes (e.g., `: foo"bar"`)
+ [dc1b2f6fa4bb]
+
+- Highlight command substitutions (`` : `ls` ``, `: $(ls)`)
+ [c0e64fe13178 and parents, e86f75a840e7, et al]
+
+- Highlight process substitutions (`: >(nl)`, `: <(pwd)`, `: =(git diff)`)
+ [c0e64fe13178 and parents, e86f75a840e7, et al]
+
+- Highlight command substitutions inside double quotes (``: "`foo`"``)
+ [f16e858f0c83]
+
+- Highlight many precommands (e.g., `nice`, `stdbuf`, `eatmydata`;
+ see `$precommand_options` in the source)
+
+- Highlight numeric globs (e.g., `echo /lib<->`)
+
+- Assorted improvements to aliases highlighting
+ (e.g.,
+ `alias sudo_u='sudo -u'; sudo_u jrandom ls`,
+ `alias x=y y=z z=nosuchcommand; x`,
+ `alias ls='ls -l'; \ls`)
+ [f3410c5862fc, 57386f30aec8, #544, and many others]
+
+- Highlight some more syntax errors
+ [dea05e44e671, 298ef6a2fa30]
+
+- New styles: named file descriptors, `RC_QUOTES`, and unclosed quotes (e.g., `echo "foo<CURSOR>`)
+ [38c794a978cd, 25ae1c01216c, 967335dfc5fd]
+
+- The 'brackets' highlighting no longer treats quotes specially.
+ [ecdda36ef56f]
+
+
+Selected bugfixes include:
+
+- Highlight `sudo` correctly when it's not installed
+ [26a82113b08b]
+
+- Handle some non-default options being set in zshrc
+ [b07ada1255b7, a2a899b41b8, 972ad197c13d, b3f66fc8748f]
+
+- Fix off-by-one highlighting in vi "visual" mode (vicmd keymap)
+ [be3882aeb054]
+
+- The 'yank-pop' widget is not wrapped
+ [#183]
+
+
+Known issues include:
+
+- A multiline alias that uses a simple command terminator (such as `;`, `|`, `&&`)
+ before a newline will incorrectly be highlighted as an error. See issue #677
+ for examples and workarounds.
+ [#677]
+ [UPDATE: Fixed in 0.8.0]
+
+
+# Changes in version 0.6.0
+
+This is a stable release, featuring bugfixes and minor improvements.
+
+
+## Performance improvements:
+
+(none)
+
+
+## Added highlighting of:
+
+- The `isearch` and `suffix` [`$zle_highlight` settings][zshzle-Character-Highlighting].
+ (79e4d3d12405, 15db71abd0cc, b56ee542d619; requires zsh 5.3 for `$ISEARCHMATCH_ACTIVE` / `$SUFFIX_ACTIVE` support)
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
+
+- Possible history expansions in double-quoted strings.
+ (76ea9e1df316)
+
+- Mismatched `if`/`then`/`elif`/`else`/`fi`.
+ (73cb83270262)
+
+
+## Fixed highlighting of:
+
+- A comment line followed by a non-comment line.
+ (#385, 9396ad5c5f9c)
+
+- An unquoted `$*` (expands to the positional parameters).
+ (237f89ad629f)
+
+- history-incremental-pattern-search-backward under zsh 5.3.1.
+ (#407, #415, 462779629a0c)
+
+
+## API changes (for highlighter authors):
+
+(none)
+
+
+## Developer-visible changes:
+
+- tests: Set the `ALIAS_FUNC_DEF` option for zsh 5.4 compatibility.
+ (9523d6d49cb3)
+
+
+## Other changes:
+
+- docs: Added before/after screenshots.
+ (cd9ec14a65ec..b7e277106b49)
+
+- docs: Link Fedora package.
+ (3d74aa47e4a7, 5feed23962df)
+
+- docs: Link FreeBSD port.
+ (626c034c68d7)
+
+- docs: Link OpenSUSE Build Service packages
+ (#419, dea1fedc7358)
+
+- Prevent user-defined aliases from taking effect in z-sy-h's own code.
+ (#390, 2dce602727d7, 8d5afe47f774; and #392, #395, b8fa1b9dc954)
+
+- docs: Update zplug installation instructions.
+ (#399, 4f49c4a35f17)
+
+- Improve "unhandled ZLE widget 'foo'" error message.
+ (#409, be083d7f3710)
+
+- Fix printing of "failed loading highlighters" error message.
+ (#426, ad522a091429)
+
+
+# Changes in version 0.5.0
+
+
+## Performance improvements:
+
+We thank Sebastian Gniazdowski and "m0viefreak" for significant contributions
+in this area.
+
+- Optimize string operations in the `main` (default) highlighter.
+ (#372/3cb58fd7d7b9, 02229ebd6328, ef4bfe5bcc14, #372/c6b6513ac0d6, #374/15461e7d21c3)
+
+- Command word highlighting: Use the `zsh/parameter` module to avoid forks.
+ Memoize (cache) the results.
+ (#298, 3ce01076b521, 2f18ba64e397, 12b879caf7a6; #320, 3b67e656bff5)
+
+- Avoid forks in the driver and in the `root` highlighter.
+ (b9112aec798a, 38c8fbea2dd2)
+
+
+## Added highlighting of:
+
+- `pkexec` (a precommand).
+ (#248, 4f3910cbbaa5)
+
+- Aliases that cannot be defined normally nor invoked normally (highlighted as an error).
+ (#263 (in part), 28932316cca6)
+
+- Path separators (`/`) — the default behaviour remains to highlight path separators
+ and path components the same way.
+ (#136, #260, 6cd39e7c70d3, 9a934d291e7c, f3d3aaa00cc4)
+
+- Assignments to individual positional arguments (`42=foo` to assign to `$42`).
+ (f4036a09cee3)
+
+- Linewise region (the `visual-line-mode` widget, bound to `V` in zsh's `vi` keymap).
+ (#267, a7a7f8b42280, ee07588cfd9b)
+
+- Command-lines recalled by `isearch` mode; requires zsh≥5.3.
+ (#261 (in part); #257; 4ad311ec0a68)
+
+- Command-lines whilst the `IGNORE_BRACES` or `IGNORE_CLOSE_BRACES` option is in effect.
+ (a8a6384356af, 02807f1826a5)
+
+- Mismatched parentheses and braces (in the `main` highlighter).
+ (51b9d79c3bb6, 2fabf7ca64b7, a4196eda5e6f, and others)
+
+- Mismatched `do`/`done` keywords.
+ (b2733a64da93)
+
+- Mismatched `foreach`/`end` keywords.
+ (#96, 2bb8f0703d8f)
+
+- In Bourne-style function definitions, when the `MULTI_FUNC_DEF` option is set
+ (which is the default), highlight the first word in the function body as
+ a command word: `f() { g "$@" }`.
+ (6f91850a01e1)
+
+- `always` blocks.
+ (#335, e5782e4ddfb6)
+
+- Command substitutions inside double quotes, `"$(echo foo)"`.
+ (#139 (in part), c3913e0d8ead)
+
+- Non-alphabetic parameters inside double quotes (`"$$"`, `"$#"`, `"$*"`, `"$@"`, `"$?"`, `"$-"`).
+ (4afe670f7a1b, 44ef6e38e5a7)
+
+- Command words from future versions of zsh (forward compatibly).
+ This also adds an `arg0` style that all other command word styles fall back to.
+ (b4537a972eed, bccc3dc26943)
+
+- Escaped history expansions inside double quotes: `: "\!"`
+ (28d7056a7a06, et seq)
+
+
+## Fixed highlighting of:
+
+- Command separator tokens in syntactically-invalid positions.
+ (09c4114eb980)
+
+- Redirections with a file descriptor number at command word.
+ (#238 (in part), 73ee7c1f6c4a)
+
+- The `select` prompt, `$PS3`.
+ (#268, 451665cb2a8b)
+
+- Values of variables in `vared`.
+ (e500ca246286)
+
+- `!` as an argument (neither a history expansion nor a reserved word).
+ (4c23a2fd1b90)
+
+- "division by zero" error under the `brackets` highlighter when `$ZSH_HIGHLIGHT_STYLES` is empty.
+ (f73f3d53d3a6)
+
+- Process substitutions, `<(pwd)` and `>(wc -l)`.
+ (#302, 6889ff6bd2ad, bfabffbf975c, fc9c892a3f15)
+
+- The non-`SHORT_LOOPS` form of `repeat` loops: `repeat 42; do true; done`.
+ (#290, 4832f18c50a5, ef68f50c048f, 6362c757b6f7)
+
+- Broken symlinks (are now highlighted as files).
+ (#342, 95f7206a9373, 53083da8215e)
+
+- Lines accepted from `isearch` mode.
+ (#284; #257, #259, #288; 5bae6219008b, a8fe22d42251)
+
+- Work around upstream bug that triggered when the command word was a relative
+ path, that when interpreted relative to a $PATH directory denoted a command;
+ the effect of that upstream bug was that the relative path was cached as
+ a "valid external command name".
+ (#354, #355, 51614ca2c994, fdaeec45146b, 7d38d07255e4;
+ upstream fix slated to be released in 5.3 (workers/39104))
+
+- After accepting a line with the cursor on a bracket, the matching bracket
+ of the bracket under the cursor no longer remains highlighted (with the
+ `brackets` highlighter).
+ (4c4baede519a)
+
+- The first word on a new line within an array assignment or initialization is no
+ longer considered a command position.
+ (8bf423d16d46)
+
+- Subshells that end at command position, `(A=42)`, `(true;)`.
+ (#231, 7fb6f9979121; #344, 4fc35362ee5a)
+
+- Command word after array assignment, `a=(lorem ipsum) pwd`.
+ (#330, 7fb6f9979121)
+
+
+## API changes (for highlighter authors):
+
+- New interface `_zsh_highlight_add_highlight`.
+ (341a3ae1f015, c346f6eb6fb6)
+
+- tests: Specify the style key, not its value, in test expectations.
+ (a830613467af, fd061b5730bf, eaa4335c3441, among others)
+
+- Module author documentation improvements.
+ (#306 (in part), 217669270418, 0ff354b44b6e, 80148f6c8402, 364f206a547f, and others)
+
+- The driver no longer defines a `_zsh_highlight_${highlighter}_highlighter_cache`
+ variable, which is in the highlighters' namespace.
+ (3e59ab41b6b8, 80148f6c8402, f91a7b885e7d)
+
+- Rename highlighter entry points. The old names remain supported for
+ backwards compatibility.
+ (a3d5dfcbdae9, c793e0dceab1)
+
+- tests: Add the "NONE" expectation.
+ (4da9889d1545, 13018f3dd735, d37c55c788cd)
+
+- tests: consider a test that writes to stderr to have failed.
+ (#291, 1082067f9315)
+
+
+## Developer-visible changes:
+
+- Add `make quiet-test`.
+ (9b64ad750f35)
+
+- test harness: Better quote replaceables in error messages.
+ (30d8f92df225)
+
+- test harness: Fix exit code for XPASS.
+ (bb8d325c0cbd)
+
+- Create [HACKING.md](HACKING.md).
+ (cef49752fd0e)
+
+- tests: Emit a description for PASS test points.
+ (6aa57d60aa64, f0bae44b76dd)
+
+- tests: Create a script that generates a test file.
+ (8013dc3b8db6, et seq; `tests/generate.zsh`)
+
+
+## Other changes:
+
+- Under zsh≤5.2, widgets whose names start with a `_` are no longer excluded
+ from highlighting.
+ (ed33d2cb1388; reverts part of 186d80054a40 which was for #65)
+
+- Under zsh≤5.2, widgets implemented by a function named after the widget are
+ no longer excluded from highlighting.
+ (487b122c480d; reverts part of 776453cb5b69)
+
+- Under zsh≤5.2, shell-unsafe widget names can now be wrapped.
+ (#278, 6a634fac9fb9, et seq)
+
+- Correct some test expectations.
+ (78290e043bc5)
+
+- `zsh-syntax-highlighting.plugin.zsh`: Convert from symlink to plain file
+ for msys2 compatibility.
+ (#292, d4f8edc9f3ad)
+
+- Document installation under some plugin managers.
+ (e635f766bef9, 9cab566f539b)
+
+- Don't leak the `PATH_DIRS` option.
+ (7b82b88a7166)
+
+- Don't require the `FUNCTION_ARGZERO` option to be set.
+ (#338, 750aebc553f2)
+
+- Under zsh≤5.2, support binding incomplete/nonexistent widgets.
+ (9e569bb0fe04, part of #288)
+
+- Make the driver reentrant, fixing possibility of infinite recursion
+ under zsh≤5.2 under interaction with theoretical third-party code.
+ (#305, d711563fe1bf, 295d62ec888d, f3242cbd6aba)
+
+- Fix warnings when `WARN_CREATE_GLOBAL` is set prior to sourcing zsh-syntax-highlighting.
+ (z-sy-h already sets `WARN_CREATE_GLOBAL` internally.)
+ (da60234fb236)
+
+- Warn only once, rather than once per keypress, when a highlighter is unavailable.
+ (0a9b347483ae)
+
+
+# Changes in version 0.4.1
+
+## Fixes:
+
+- Arguments to widgets were not properly dash-escaped. Only matters for widgets
+ that take arguments (i.e., that are invoked as `zle ${widget} -- ${args}`).
+ (282c7134e8ac, reverts c808d2187a73)
+
+
+# Changes in version 0.4.0
+
+
+## Added highlighting of:
+
+- incomplete sudo commands
+ (a3047a912100, 2f05620b19ae)
+
+ ```zsh
+ sudo;
+ sudo -u;
+ ```
+
+- command words following reserved words
+ (#207, #222, b397b12ac139 et seq, 6fbd2aa9579b et seq, 8b4adbd991b0)
+
+ ```zsh
+ if ls; then ls; else ls; fi
+ repeat 10 do ls; done
+ ```
+
+ (The `ls` are now highlighted as a command.)
+
+- comments (when `INTERACTIVE_COMMENTS` is set)
+ (#163, #167, 693de99a9030)
+
+ ```zsh
+ echo Hello # comment
+ ```
+
+- closing brackets of arithmetic expansion, subshells, and blocks
+ (#226, a59f442d2d34, et seq)
+
+ ```zsh
+ (( foo ))
+ ( foo )
+ { foo }
+ ```
+
+- command names enabled by the `PATH_DIRS` option
+ (#228, 96ee5116b182)
+
+ ```zsh
+ # When ~/bin/foo/bar exists, is executable, ~/bin is in $PATH,
+ # and 'setopt PATH_DIRS' is in effect
+ foo/bar
+ ```
+
+- parameter expansions with braces inside double quotes
+ (#186, 6e3720f39d84)
+
+ ```zsh
+ echo "${foo}"
+ ```
+
+- parameter expansions in command word
+ (#101, 4fcfb15913a2)
+
+ ```zsh
+ x=/bin/ls
+ $x -l
+ ```
+
+- the command separators '\|&', '&!', '&\|'
+
+ ```zsh
+ view file.pdf &! ls
+ ```
+
+
+## Fixed highlighting of:
+
+- precommand modifiers at non-command-word position
+ (#209, 2c9f8c8c95fa)
+
+ ```zsh
+ ls command foo
+ ```
+
+- sudo commands with infix redirections
+ (#221, be006aded590, 86e924970911)
+
+ ```zsh
+ sudo -u >/tmp/foo.out user ls
+ ```
+
+- subshells; anonymous functions
+ (#166, #194, 0d1bfbcbfa67, 9e178f9f3948)
+
+ ```zsh
+ (true)
+ () { true }
+ ```
+
+- parameter assignment statements with no command
+ (#205, 01d7eeb3c713)
+
+ ```zsh
+ A=1;
+ ```
+
+ (The semicolon used to be highlighted as a mistake)
+
+- cursor highlighter: Remove the cursor highlighting when accepting a line.
+ (#109, 4f0c293fdef0)
+
+
+## Removed features:
+
+- Removed highlighting of approximate paths (`path_approx`).
+ (#187, 98aee7f8b9a3)
+
+
+## Other changes:
+
+- main highlighter refactored to use states rather than booleans.
+ (2080a441ac49, et seq)
+
+- Fix initialization when sourcing `zsh-syntax-highlighting.zsh` via a symlink
+ (083c47b00707)
+
+- docs: Add screenshot.
+ (57624bb9f64b)
+
+- widgets wrapping: Don't add '--' when invoking widgets.
+ (c808d2187a73) [_reverted in 0.4.1_]
+
+- Refresh highlighting upon `accept-*` widgets (`accept-line` et al).
+ (59fbdda64c21)
+
+- Stop leaking match/mbegin/mend to global scope (thanks to upstream
+ `WARN_CREATE_GLOBAL` improvements).
+ (d3deffbf46a4)
+
+- 'make install': Permit setting `$(SHARE_DIR)` from the environment.
+ (e1078a8b4cf1)
+
+- driver: Tolerate KSH_ARRAYS being set in the calling context.
+ (#162, 8f19af6b319d)
+
+- 'make install': Install documentation fully and properly.
+ (#219, b1619c001390, et seq)
+
+- docs: Improve 'main' highlighter's documentation.
+ (00de155063f5, 7d4252f5f596)
+
+- docs: Moved to a new docs/ tree; assorted minor updates
+ (c575f8f37567, 5b34c23cfad5, et seq)
+
+- docs: Split README.md into INSTALL.md
+ (0b3183f6cb9a)
+
+- driver: Report `$ZSH_HIGHLIGHT_REVISION` when running from git
+ (84734ba95026)
+
+
+## Developer-visible changes:
+
+- Test harness converted to [TAP](http://testanything.org/tap-specification.html) format
+ (d99aa58aaaef, et seq)
+
+- Run each test in a separate subprocess, isolating them from each other
+ (d99aa58aaaef, et seq)
+
+- Fix test failure with nonexisting $HOME
+ (#216, b2ac98b98150)
+
+- Test output is now colorized.
+ (4d3da30f8b72, 6fe07c096109)
+
+- Document `make install`
+ (a18a7427fd2c)
+
+- tests: Allow specifying the zsh binary to use.
+ (557bb7e0c6a0)
+
+- tests: Add 'make perf' target
+ (4513eaea71d7)
+
+- tests: Run each test in a sandbox directory
+ (c01533920245)
+
+
+# Changes in version 0.3.0
+
+
+## Added highlighting of:
+
+- suffix aliases (requires zsh 5.1.1 or newer):
+
+ ```zsh
+ alias -s png=display
+ foo.png
+ ```
+
+- prefix redirections:
+
+ ```zsh
+ <foo.txt cat
+ ```
+
+- redirection operators:
+
+ ```zsh
+ echo > foo.txt
+ ```
+
+- arithmetic evaluations:
+
+ ```zsh
+ (( 42 ))
+ ```
+
+- $'' strings, including \x/\octal/\u/\U escapes
+
+ ```zsh
+ : $'foo\u0040bar'
+ ```
+
+- multiline strings:
+
+ ```zsh
+ % echo "line 1
+ line 2"
+ ```
+
+- string literals that haven't been finished:
+
+ ```zsh
+ % echo "Hello, world
+ ```
+- command words that involve tilde expansion:
+
+ ```zsh
+ % ~/bin/foo
+ ```
+
+## Fixed highlighting of:
+
+- quoted command words:
+
+ ```zsh
+ % \ls
+ ```
+
+- backslash escapes in "" strings:
+
+ ```zsh
+ % echo "\x41"
+ ```
+
+- noglob after command separator:
+
+ ```zsh
+ % :; noglob echo *
+ ```
+
+- glob after command separator, when the first command starts with 'noglob':
+
+ ```zsh
+ % noglob true; echo *
+ ```
+
+- the region (vi visual mode / set-mark-command) (issue #165)
+
+- redirection and command separators that would be highlighted as `path_approx`
+
+ ```zsh
+ % echo foo;‸
+ % echo <‸
+ ```
+
+ (where `‸` represents the cursor location)
+
+- escaped globbing (outside quotes)
+
+ ```zsh
+ % echo \*
+ ```
+
+
+## Other changes:
+
+- implemented compatibility with zsh's paste highlighting (issue #175)
+
+- `$?` propagated correctly to wrapped widgets
+
+- don't leak $REPLY into global scope
+
+
+## Developer-visible changes:
+
+- added makefile with `install` and `test` targets
+
+- set `warn_create_global` internally
+
+- document release process
+
+
+
+
+# Version 0.2.1
+
+(Start of changelog.)
+
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters.md
new file mode 100644
index 00000000..3a289cab
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters.md
@@ -0,0 +1,134 @@
+zsh-syntax-highlighting / highlighters
+======================================
+
+Syntax highlighting is done by pluggable highlighters:
+
+* `main` - the base highlighter, and the only one [active by default][main].
+* `brackets` - [matches brackets][brackets] and parenthesis.
+* `pattern` - matches [user-defined patterns][pattern].
+* `regexp` - matches [user-defined regular expressions][regexp].
+* `cursor` - matches [the cursor position][cursor].
+* `root` - highlights the whole command line [if the current user is root][root].
+* `line` - applied to [the whole command line][line].
+
+[main]: highlighters/main.md
+[brackets]: highlighters/brackets.md
+[pattern]: highlighters/pattern.md
+[regexp]: highlighters/regexp.md
+[cursor]: highlighters/cursor.md
+[root]: highlighters/root.md
+[line]: highlighters/line.md
+
+
+Highlighter-independent settings
+--------------------------------
+
+By default, all command lines are highlighted. However, it is possible to
+prevent command lines longer than a fixed number of characters from being
+highlighted by setting the variable `${ZSH_HIGHLIGHT_MAXLENGTH}` to the maximum
+length (in characters) of command lines to be highlighter. This is useful when
+editing very long command lines (for example, with the [`fned`][fned] utility
+function). Example:
+
+[fned]: https://zsh.sourceforge.io/Doc/Release/User-Contributions.html#index-zed
+
+```zsh
+ZSH_HIGHLIGHT_MAXLENGTH=512
+```
+
+
+How to activate highlighters
+----------------------------
+
+To activate an highlighter, add it to the `ZSH_HIGHLIGHT_HIGHLIGHTERS` array in
+`~/.zshrc`, for example:
+
+```zsh
+ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern cursor)
+```
+
+By default, `$ZSH_HIGHLIGHT_HIGHLIGHTERS` is unset and only the `main`
+highlighter is active.
+
+
+How to tweak highlighters
+-------------------------
+
+Highlighters look up styles from the `ZSH_HIGHLIGHT_STYLES` associative array.
+Navigate into the [individual highlighters' documentation](highlighters/) to
+see what styles (keys) each highlighter defines; the syntax for values is the
+same as the syntax of "types of highlighting" of the zsh builtin
+`$zle_highlight` array, which is documented in [the `zshzle(1)` manual
+page][zshzle-Character-Highlighting].
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
+
+Some highlighters support additional configuration parameters; see each
+highlighter's documentation for details and examples.
+
+
+How to implement a new highlighter
+----------------------------------
+
+To create your own `acme` highlighter:
+
+* Create your script at
+ `highlighters/acme/acme-highlighter.zsh`.
+
+* Implement the `_zsh_highlight_highlighter_acme_predicate` function.
+ This function must return 0 when the highlighter needs to be called and
+ non-zero otherwise, for example:
+
+ ```zsh
+ _zsh_highlight_highlighter_acme_predicate() {
+ # Call this highlighter in SVN working copies
+ [[ -d .svn ]]
+ }
+ ```
+
+* Implement the `_zsh_highlight_highlighter_acme_paint` function.
+ This function does the actual syntax highlighting, by calling
+ `_zsh_highlight_add_highlight` with the start and end of the region to
+ be highlighted and the `ZSH_HIGHLIGHT_STYLES` key to use. Define the default
+ style for that key in the highlighter script outside of any function with
+ `: ${ZSH_HIGHLIGHT_STYLES[key]:=value}`, being sure to prefix
+ the key with your highlighter name and a colon. For example:
+
+ ```zsh
+ : ${ZSH_HIGHLIGHT_STYLES[acme:aurora]:=fg=green}
+
+ _zsh_highlight_highlighter_acme_paint() {
+ # Colorize the whole buffer with the 'aurora' style
+ _zsh_highlight_add_highlight 0 $#BUFFER acme:aurora
+ }
+ ```
+
+ If you need to test which options the user has set, test `zsyh_user_options`
+ with a sensible default if the option is not present in supported zsh
+ versions. For example:
+
+ ```zsh
+ [[ ${zsyh_user_options[ignoreclosebraces]:-off} == on ]]
+ ```
+
+ The option name must be all lowercase with no underscores and not an alias.
+
+* Name your own functions and global variables `_zsh_highlight_acme_*`.
+
+ - In zsh-syntax-highlighting 0.4.0 and earlier, the entrypoints
+ `_zsh_highlight_highlighter_acme_predicate` and
+ `_zsh_highlight_highlighter_acme_paint`
+ were named
+ `_zsh_highlight_acme_highlighter_predicate` and
+ `_zsh_highlight_highlighter_acme_paint` respectively.
+
+ These names are still supported for backwards compatibility;
+ however, support for them will be removed in a future major or minor release (v0.x.0 or v1.0.0).
+
+* Activate your highlighter in `~/.zshrc`:
+
+ ```zsh
+ ZSH_HIGHLIGHT_HIGHLIGHTERS+=(acme)
+ ```
+
+* [Write tests](../tests/README.md).
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/brackets.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/brackets.md
new file mode 100644
index 00000000..0101699e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/brackets.md
@@ -0,0 +1,31 @@
+zsh-syntax-highlighting / highlighters / brackets
+-------------------------------------------------
+
+This is the `brackets` highlighter, that highlights brackets and parentheses, and
+matches them.
+
+
+### How to tweak it
+
+This highlighter defines the following styles:
+
+* `bracket-error` - unmatched brackets
+* `bracket-level-N` - brackets with nest level N
+* `cursor-matchingbracket` - the matching bracket, if cursor is on a bracket
+
+To override one of those styles, change its entry in `ZSH_HIGHLIGHT_STYLES`,
+for example in `~/.zshrc`:
+
+```zsh
+# To define styles for nested brackets up to level 4
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]='fg=blue,bold'
+ZSH_HIGHLIGHT_STYLES[bracket-level-2]='fg=red,bold'
+ZSH_HIGHLIGHT_STYLES[bracket-level-3]='fg=yellow,bold'
+ZSH_HIGHLIGHT_STYLES[bracket-level-4]='fg=magenta,bold'
+```
+
+The syntax for values is the same as the syntax of "types of highlighting" of
+the zsh builtin `$zle_highlight` array, which is documented in [the `zshzle(1)`
+manual page][zshzle-Character-Highlighting].
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/cursor.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/cursor.md
new file mode 100644
index 00000000..3f87d422
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/cursor.md
@@ -0,0 +1,24 @@
+zsh-syntax-highlighting / highlighters / cursor
+-----------------------------------------------
+
+This is the `cursor` highlighter, that highlights the cursor.
+
+
+### How to tweak it
+
+This highlighter defines the following styles:
+
+* `cursor` - the style for the current cursor position
+
+To override one of those styles, change its entry in `ZSH_HIGHLIGHT_STYLES`,
+for example in `~/.zshrc`:
+
+```zsh
+ZSH_HIGHLIGHT_STYLES[cursor]='bg=blue'
+```
+
+The syntax for values is the same as the syntax of "types of highlighting" of
+the zsh builtin `$zle_highlight` array, which is documented in [the `zshzle(1)`
+manual page][zshzle-Character-Highlighting].
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/line.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/line.md
new file mode 100644
index 00000000..f76639ee
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/line.md
@@ -0,0 +1,24 @@
+zsh-syntax-highlighting / highlighters / line
+---------------------------------------------
+
+This is the `line` highlighter, that highlights the whole line.
+
+
+### How to tweak it
+
+This highlighter defines the following styles:
+
+* `line` - the style for the whole line
+
+To override one of those styles, change its entry in `ZSH_HIGHLIGHT_STYLES`,
+for example in `~/.zshrc`:
+
+```zsh
+ZSH_HIGHLIGHT_STYLES[line]='bold'
+```
+
+The syntax for values is the same as the syntax of "types of highlighting" of
+the zsh builtin `$zle_highlight` array, which is documented in [the `zshzle(1)`
+manual page][zshzle-Character-Highlighting].
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/main.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/main.md
new file mode 100644
index 00000000..4a27653f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/main.md
@@ -0,0 +1,121 @@
+zsh-syntax-highlighting / highlighters / main
+---------------------------------------------
+
+This is the `main` highlighter, that highlights:
+
+* Commands
+* Options
+* Arguments
+* Paths
+* Strings
+
+This highlighter is active by default.
+
+
+### How to tweak it
+
+This highlighter defines the following styles:
+
+* `unknown-token` - unknown tokens / errors
+* `reserved-word` - shell reserved words (`if`, `for`)
+* `alias` - aliases
+* `suffix-alias` - suffix aliases (requires zsh 5.1.1 or newer)
+* `global-alias` - global aliases
+* `builtin` - shell builtin commands (`shift`, `pwd`, `zstyle`)
+* `function` - function names
+* `command` - command names
+* `precommand` - precommand modifiers (e.g., `noglob`, `builtin`)
+* `commandseparator` - command separation tokens (`;`, `&&`)
+* `hashed-command` - hashed commands
+* `autodirectory` - a directory name in command position when the `AUTO_CD` option is set
+* `path` - existing filenames
+* `path_pathseparator` - path separators in filenames (`/`); if unset, `path` is used (default)
+* `path_prefix` - prefixes of existing filenames
+* `path_prefix_pathseparator` - path separators in prefixes of existing filenames (`/`); if unset, `path_prefix` is used (default)
+* `globbing` - globbing expressions (`*.txt`)
+* `history-expansion` - history expansion expressions (`!foo` and `^foo^bar`)
+* `command-substitution` - command substitutions (`$(echo foo)`)
+* `command-substitution-unquoted` - an unquoted command substitution (`$(echo foo)`)
+* `command-substitution-quoted` - a quoted command substitution (`"$(echo foo)"`)
+* `command-substitution-delimiter` - command substitution delimiters (`$(` and `)`)
+* `command-substitution-delimiter-unquoted` - an unquoted command substitution delimiters (`$(` and `)`)
+* `command-substitution-delimiter-quoted` - a quoted command substitution delimiters (`"$(` and `)"`)
+* `process-substitution` - process substitutions (`<(echo foo)`)
+* `process-substitution-delimiter` - process substitution delimiters (`<(` and `)`)
+* `arithmetic-expansion` - arithmetic expansion `$(( 42 ))`)
+* `single-hyphen-option` - single-hyphen options (`-o`)
+* `double-hyphen-option` - double-hyphen options (`--option`)
+* `back-quoted-argument` - backtick command substitution (`` `foo` ``)
+* `back-quoted-argument-unclosed` - unclosed backtick command substitution (`` `foo ``)
+* `back-quoted-argument-delimiter` - backtick command substitution delimiters (`` ` ``)
+* `single-quoted-argument` - single-quoted arguments (`` 'foo' ``)
+* `single-quoted-argument-unclosed` - unclosed single-quoted arguments (`` 'foo ``)
+* `double-quoted-argument` - double-quoted arguments (`` "foo" ``)
+* `double-quoted-argument-unclosed` - unclosed double-quoted arguments (`` "foo ``)
+* `dollar-quoted-argument` - dollar-quoted arguments (`` $'foo' ``)
+* `dollar-quoted-argument-unclosed` - unclosed dollar-quoted arguments (`` $'foo ``)
+* `rc-quote` - two single quotes inside single quotes when the `RC_QUOTES` option is set (`` 'foo''bar' ``)
+* `dollar-double-quoted-argument` - parameter expansion inside double quotes (`$foo` inside `""`)
+* `back-double-quoted-argument` - backslash escape sequences inside double-quoted arguments (`\"` in `"foo\"bar"`)
+* `back-dollar-quoted-argument` - backslash escape sequences inside dollar-quoted arguments (`\x` in `$'\x48'`)
+* `assign` - parameter assignments (`x=foo` and `x=( )`)
+* `redirection` - redirection operators (`<`, `>`, etc)
+* `comment` - comments, when `setopt INTERACTIVE_COMMENTS` is in effect (`echo # foo`)
+* `comment` - elided parameters in command position (`$x ls` when `$x` is unset or empty)
+* `named-fd` - named file descriptor (the `fd` in `echo foo {fd}>&2`)
+* `numeric-fd` - numeric file descriptor (the `2` in `echo foo {fd}>&2`)
+* `arg0` - a command word other than one of those enumerated above (other than a command, precommand, alias, function, or shell builtin command).
+* `default` - everything else
+
+To override one of those styles, change its entry in `ZSH_HIGHLIGHT_STYLES`,
+for example in `~/.zshrc`:
+
+```zsh
+# Declare the variable
+typeset -A ZSH_HIGHLIGHT_STYLES
+
+# To differentiate aliases from other command types
+ZSH_HIGHLIGHT_STYLES[alias]='fg=magenta,bold'
+
+# To have paths colored instead of underlined
+ZSH_HIGHLIGHT_STYLES[path]='fg=cyan'
+
+# To disable highlighting of globbing expressions
+ZSH_HIGHLIGHT_STYLES[globbing]='none'
+```
+
+The syntax for values is the same as the syntax of "types of highlighting" of
+the zsh builtin `$zle_highlight` array, which is documented in [the `zshzle(1)`
+manual page][zshzle-Character-Highlighting].
+
+#### Parameters
+
+To avoid partial path lookups on a path, add the path to the `ZSH_HIGHLIGHT_DIRS_BLACKLIST` array.
+
+```zsh
+ZSH_HIGHLIGHT_DIRS_BLACKLIST+=(/mnt/slow_share)
+```
+
+### Useless trivia
+
+#### Forward compatibility.
+
+zsh-syntax-highlighting attempts to be forward-compatible with zsh.
+Specifically, we attempt to facilitate highlighting _command word_ types that
+had not yet been invented when this version of zsh-syntax-highlighting was
+released.
+
+A _command word_ is something like a function name, external command name, et
+cetera. (See
+[Simple Commands & Pipelines in `zshmisc(1)`][zshmisc-Simple-Commands-And-Pipelines]
+for a formal definition.)
+
+If a new _kind_ of command word is ever added to zsh — something conceptually
+different than "function" and "alias" and "external command" — then command words
+of that (new) kind will be highlighted by the style `arg0_$kind`,
+where `$kind` is the output of `type -w` on the new kind of command word. If that
+style is not defined, then the style `arg0` will be used instead.
+
+[zshmisc-Simple-Commands-And-Pipelines]: https://zsh.sourceforge.io/Doc/Release/Shell-Grammar.html#Simple-Commands-_0026-Pipelines
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/pattern.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/pattern.md
new file mode 100644
index 00000000..ecaa6a7f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/pattern.md
@@ -0,0 +1,24 @@
+zsh-syntax-highlighting / highlighters / pattern
+------------------------------------------------
+
+This is the `pattern` highlighter, that highlights user-defined patterns.
+
+
+### How to tweak it
+
+To use this highlighter, associate patterns with styles in the
+`ZSH_HIGHLIGHT_PATTERNS` associative array, for example in `~/.zshrc`:
+
+```zsh
+# Declare the variable
+typeset -A ZSH_HIGHLIGHT_PATTERNS
+
+# To have commands starting with `rm -rf` in red:
+ZSH_HIGHLIGHT_PATTERNS+=('rm -rf *' 'fg=white,bold,bg=red')
+```
+
+The syntax for values is the same as the syntax of "types of highlighting" of
+the zsh builtin `$zle_highlight` array, which is documented in [the `zshzle(1)`
+manual page][zshzle-Character-Highlighting].
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/regexp.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/regexp.md
new file mode 100644
index 00000000..b1bed914
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/regexp.md
@@ -0,0 +1,65 @@
+zsh-syntax-highlighting / highlighters / regexp
+------------------------------------------------
+
+This is the `regexp` highlighter, that highlights user-defined regular
+expressions. It's similar to the `pattern` highlighter, but allows more complex
+patterns.
+
+### How to tweak it
+
+To use this highlighter, associate regular expressions with styles in the
+`ZSH_HIGHLIGHT_REGEXP` associative array, for example in `~/.zshrc`:
+
+```zsh
+typeset -A ZSH_HIGHLIGHT_REGEXP
+ZSH_HIGHLIGHT_REGEXP+=('^rm .*' fg=red,bold)
+```
+
+This will highlight lines that start with a call to the `rm` command.
+
+The regular expressions flavour used is [PCRE][pcresyntax] when the
+`RE_MATCH_PCRE` option is set and POSIX Extended Regular Expressions (ERE),
+as implemented by the platform's C library, otherwise. For details on the
+latter, see [the `zsh/regex` module's documentation][MAN_ZSH_REGEX] and the
+`regcomp(3)` and `re_format(7)` manual pages on your system.
+
+For instance, to highlight `sudo` only as a complete word, i.e., `sudo cmd`,
+but not `sudoedit`, one might use:
+
+* When the `RE_MATCH_PCRE` is set:
+
+ ```zsh
+ typeset -A ZSH_HIGHLIGHT_REGEXP
+ ZSH_HIGHLIGHT_REGEXP+=('\bsudo\b' fg=123,bold)
+ ```
+
+* When the `RE_MATCH_PCRE` is unset, on platforms with GNU `libc` (e.g., many GNU/Linux distributions):
+
+ ```zsh
+ typeset -A ZSH_HIGHLIGHT_REGEXP
+ ZSH_HIGHLIGHT_REGEXP+=('\<sudo\>' fg=123,bold)
+ ```
+
+* When the `RE_MATCH_PCRE` is unset, on BSD-based platforms (e.g., macOS):
+
+ ```zsh
+ typeset -A ZSH_HIGHLIGHT_REGEXP
+ ZSH_HIGHLIGHT_REGEXP+=('[[:<:]]sudo[[:>:]]' fg=123,bold)
+ ```
+
+Note, however, that PCRE and POSIX ERE have a large common subset:
+for instance, the regular expressions `[abc]`, `a*`, and `(a|b)` have the same
+meaning in both flavours.
+
+The syntax for values is the same as the syntax of "types of highlighting" of
+the zsh builtin `$zle_highlight` array, which is documented in [the `zshzle(1)`
+manual page][zshzle-Character-Highlighting].
+
+See also: [regular expressions tutorial][perlretut], zsh regexp operator `=~`
+in [the `zshmisc(1)` manual page][zshmisc-Conditional-Expressions]
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
+[perlretut]: http://perldoc.perl.org/perlretut.html
+[zshmisc-Conditional-Expressions]: https://zsh.sourceforge.io/Doc/Release/Conditional-Expressions.html#Conditional-Expressions
+[MAN_ZSH_REGEX]: https://zsh.sourceforge.io/Doc/Release/Zsh-Modules.html#The-zsh_002fregex-Module
+[pcresyntax]: https://www.pcre.org/original/doc/html/pcresyntax.html
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/root.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/root.md
new file mode 100644
index 00000000..8197e4bd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/docs/highlighters/root.md
@@ -0,0 +1,25 @@
+zsh-syntax-highlighting / highlighters / root
+---------------------------------------------
+
+This is the `root` highlighter, that highlights the whole line if the current
+user is root.
+
+
+### How to tweak it
+
+This highlighter defines the following styles:
+
+* `root` - the style for the whole line if the current user is root.
+
+To override one of those styles, change its entry in `ZSH_HIGHLIGHT_STYLES`,
+for example in `~/.zshrc`:
+
+```zsh
+ZSH_HIGHLIGHT_STYLES[root]='bg=red'
+```
+
+The syntax for values is the same as the syntax of "types of highlighting" of
+the zsh builtin `$zle_highlight` array, which is documented in [the `zshzle(1)`
+manual page][zshzle-Character-Highlighting].
+
+[zshzle-Character-Highlighting]: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/README.md
new file mode 100644
index 00000000..8490ddf4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/README.md
@@ -0,0 +1,8 @@
+zsh-syntax-highlighting / highlighters
+======================================
+
+Navigate into the individual highlighters' documentation to see
+what styles (`$ZSH_HIGHLIGHT_STYLES` keys) each highlighter defines.
+
+Refer to the [documentation on highlighters](../docs/highlighters.md) for further
+information.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/README.md
new file mode 120000
index 00000000..6997bd60
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/README.md
@@ -0,0 +1 @@
+../../docs/highlighters/brackets.md \ No newline at end of file
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/brackets-highlighter.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/brackets-highlighter.zsh
new file mode 100644
index 00000000..bc388fdb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/brackets-highlighter.zsh
@@ -0,0 +1,107 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+
+# Define default styles.
+: ${ZSH_HIGHLIGHT_STYLES[bracket-error]:=fg=red,bold}
+: ${ZSH_HIGHLIGHT_STYLES[bracket-level-1]:=fg=blue,bold}
+: ${ZSH_HIGHLIGHT_STYLES[bracket-level-2]:=fg=green,bold}
+: ${ZSH_HIGHLIGHT_STYLES[bracket-level-3]:=fg=magenta,bold}
+: ${ZSH_HIGHLIGHT_STYLES[bracket-level-4]:=fg=yellow,bold}
+: ${ZSH_HIGHLIGHT_STYLES[bracket-level-5]:=fg=cyan,bold}
+: ${ZSH_HIGHLIGHT_STYLES[cursor-matchingbracket]:=standout}
+
+# Whether the brackets highlighter should be called or not.
+_zsh_highlight_highlighter_brackets_predicate()
+{
+ [[ $WIDGET == zle-line-finish ]] || _zsh_highlight_cursor_moved || _zsh_highlight_buffer_modified
+}
+
+# Brackets highlighting function.
+_zsh_highlight_highlighter_brackets_paint()
+{
+ local char style
+ local -i bracket_color_size=${#ZSH_HIGHLIGHT_STYLES[(I)bracket-level-*]} buflen=${#BUFFER} level=0 matchingpos pos
+ local -A levelpos lastoflevel matching
+
+ # Find all brackets and remember which one is matching
+ pos=0
+ for char in ${(s..)BUFFER} ; do
+ (( ++pos ))
+ case $char in
+ ["([{"])
+ levelpos[$pos]=$((++level))
+ lastoflevel[$level]=$pos
+ ;;
+ [")]}"])
+ if (( level > 0 )); then
+ matchingpos=$lastoflevel[$level]
+ levelpos[$pos]=$((level--))
+ if _zsh_highlight_brackets_match $matchingpos $pos; then
+ matching[$matchingpos]=$pos
+ matching[$pos]=$matchingpos
+ fi
+ else
+ levelpos[$pos]=-1
+ fi
+ ;;
+ esac
+ done
+
+ # Now highlight all found brackets
+ for pos in ${(k)levelpos}; do
+ if (( $+matching[$pos] )); then
+ if (( bracket_color_size )); then
+ _zsh_highlight_add_highlight $((pos - 1)) $pos bracket-level-$(( (levelpos[$pos] - 1) % bracket_color_size + 1 ))
+ fi
+ else
+ _zsh_highlight_add_highlight $((pos - 1)) $pos bracket-error
+ fi
+ done
+
+ # If cursor is on a bracket, then highlight corresponding bracket, if any.
+ if [[ $WIDGET != zle-line-finish ]]; then
+ pos=$((CURSOR + 1))
+ if (( $+levelpos[$pos] )) && (( $+matching[$pos] )); then
+ local -i otherpos=$matching[$pos]
+ _zsh_highlight_add_highlight $((otherpos - 1)) $otherpos cursor-matchingbracket
+ fi
+ fi
+}
+
+# Helper function to differentiate type
+_zsh_highlight_brackets_match()
+{
+ case $BUFFER[$1] in
+ \() [[ $BUFFER[$2] == \) ]];;
+ \[) [[ $BUFFER[$2] == \] ]];;
+ \{) [[ $BUFFER[$2] == \} ]];;
+ *) false;;
+ esac
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/cursor-matchingbracket-line-finish.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/cursor-matchingbracket-line-finish.zsh
new file mode 100644
index 00000000..b2acd31d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/cursor-matchingbracket-line-finish.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+WIDGET=zle-line-finish
+
+BUFFER=': $foo[bar]'
+CURSOR=6 # cursor is zero-based
+
+expected_region_highlight=(
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/cursor-matchingbracket.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/cursor-matchingbracket.zsh
new file mode 100644
index 00000000..e05b4e90
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/cursor-matchingbracket.zsh
@@ -0,0 +1,47 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsorted=1
+
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-2]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-3]=
+
+BUFFER=': ((( )))'
+CURSOR=2 # cursor is zero-based
+
+expected_region_highlight=(
+ "3 3 bracket-level-1"
+ "4 4 bracket-level-2"
+ "5 5 bracket-level-3"
+ "7 7 bracket-level-3"
+ "8 8 bracket-level-2"
+ "9 9 bracket-level-1"
+ "9 9 cursor-matchingbracket"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/empty-styles.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/empty-styles.zsh
new file mode 100644
index 00000000..e60657bc
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/empty-styles.zsh
@@ -0,0 +1,33 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': (x)'
+
+expected_region_highlight=(
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/loop-styles.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/loop-styles.zsh
new file mode 100644
index 00000000..e5cfcdf0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/loop-styles.zsh
@@ -0,0 +1,53 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsorted=1
+
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-2]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-3]=
+
+BUFFER=': ({[({[(x)]})]})'
+
+expected_region_highlight=(
+ "3 3 bracket-level-1"
+ "4 4 bracket-level-2"
+ "5 5 bracket-level-3"
+ "6 6 bracket-level-1"
+ "7 7 bracket-level-2"
+ "8 8 bracket-level-3"
+ "9 9 bracket-level-1"
+ "11 11 bracket-level-1"
+ "12 12 bracket-level-3"
+ "13 13 bracket-level-2"
+ "14 14 bracket-level-1"
+ "15 15 bracket-level-3"
+ "16 16 bracket-level-2"
+ "17 17 bracket-level-1"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/mismatch-patentheses.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/mismatch-patentheses.zsh
new file mode 100644
index 00000000..5cc588fa
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/mismatch-patentheses.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsorted=1
+
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-2]=
+
+BUFFER='echo ({x}]'
+
+expected_region_highlight=(
+ "6 6 bracket-error" # (
+ "7 7 bracket-level-2" # {
+ "9 9 bracket-level-2" # }
+ "10 10 bracket-error" # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/near-quotes.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/near-quotes.zsh
new file mode 100644
index 00000000..49f002be
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/near-quotes.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsorted=1
+
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-2]=
+
+BUFFER=': {"{x}"}'
+
+expected_region_highlight=(
+ "3 3 bracket-level-1"
+ "5 5 bracket-level-2"
+ "7 7 bracket-level-2"
+ "9 9 bracket-level-1"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/nested-parentheses.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/nested-parentheses.zsh
new file mode 100644
index 00000000..21a20fb3
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/nested-parentheses.zsh
@@ -0,0 +1,45 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsorted=1
+
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-2]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-3]=
+
+BUFFER='echo $(echo ${(z)array})'
+
+expected_region_highlight=(
+ "7 7 bracket-level-1" # (
+ "14 14 bracket-level-2" # {
+ "15 15 bracket-level-3" # (
+ "17 17 bracket-level-3" # )
+ "23 23 bracket-level-2" # }
+ "24 24 bracket-level-1" # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/only-error.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/only-error.zsh
new file mode 100644
index 00000000..00fe557c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/only-error.zsh
@@ -0,0 +1,34 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': x)'
+
+expected_region_highlight=(
+ "4 4 bracket-error" # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/quoted-patentheses.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/quoted-patentheses.zsh
new file mode 100644
index 00000000..81ee04f2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/quoted-patentheses.zsh
@@ -0,0 +1,34 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo "foo ( bar"'
+
+expected_region_highlight=(
+"11 11 bracket-error"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/simple-parentheses.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/simple-parentheses.zsh
new file mode 100644
index 00000000..2ccfbab0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/simple-parentheses.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsorted=1
+
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-2]=
+
+BUFFER='echo ({x})'
+
+expected_region_highlight=(
+ "6 6 bracket-level-1" # (
+ "7 7 bracket-level-2" # {
+ "9 9 bracket-level-2" # }
+ "10 10 bracket-level-1" # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/unclosed-patentheses.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/unclosed-patentheses.zsh
new file mode 100644
index 00000000..d3f6560d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/unclosed-patentheses.zsh
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsorted=1
+
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]=
+ZSH_HIGHLIGHT_STYLES[bracket-level-2]=
+
+BUFFER='echo ({x}'
+
+expected_region_highlight=(
+ "6 6 bracket-error" # (
+ "7 7 bracket-level-2" # {
+ "9 9 bracket-level-2" # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/unclosed-patentheses2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/unclosed-patentheses2.zsh
new file mode 100644
index 00000000..2c489c30
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/brackets/test-data/unclosed-patentheses2.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsorted=1
+
+ZSH_HIGHLIGHT_STYLES[bracket-level-1]=
+
+BUFFER='echo {x})'
+
+expected_region_highlight=(
+ "6 6 bracket-level-1" # {
+ "8 8 bracket-level-1" # }
+ "9 9 bracket-error" # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/cursor/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/cursor/README.md
new file mode 120000
index 00000000..70e0c8c4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/cursor/README.md
@@ -0,0 +1 @@
+../../docs/highlighters/cursor.md \ No newline at end of file
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/cursor/cursor-highlighter.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/cursor/cursor-highlighter.zsh
new file mode 100644
index 00000000..81633a3c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/cursor/cursor-highlighter.zsh
@@ -0,0 +1,47 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+
+# Define default styles.
+: ${ZSH_HIGHLIGHT_STYLES[cursor]:=standout}
+
+# Whether the cursor highlighter should be called or not.
+_zsh_highlight_highlighter_cursor_predicate()
+{
+ # remove cursor highlighting when the line is finished
+ [[ $WIDGET == zle-line-finish ]] || _zsh_highlight_cursor_moved
+}
+
+# Cursor highlighting function.
+_zsh_highlight_highlighter_cursor_paint()
+{
+ [[ $WIDGET == zle-line-finish ]] && return
+
+ _zsh_highlight_add_highlight $CURSOR $(( $CURSOR + 1 )) cursor
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/line/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/line/README.md
new file mode 120000
index 00000000..052fe20b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/line/README.md
@@ -0,0 +1 @@
+../../docs/highlighters/line.md \ No newline at end of file
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/line/line-highlighter.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/line/line-highlighter.zsh
new file mode 100644
index 00000000..f922dc9b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/line/line-highlighter.zsh
@@ -0,0 +1,44 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+
+# Define default styles.
+: ${ZSH_HIGHLIGHT_STYLES[line]:=}
+
+# Whether the root highlighter should be called or not.
+_zsh_highlight_highlighter_line_predicate()
+{
+ _zsh_highlight_buffer_modified
+}
+
+# root highlighting function.
+_zsh_highlight_highlighter_line_paint()
+{
+ _zsh_highlight_add_highlight 0 $#BUFFER line
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/README.md
new file mode 120000
index 00000000..03547318
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/README.md
@@ -0,0 +1 @@
+../../docs/highlighters/main.md \ No newline at end of file
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/main-highlighter.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/main-highlighter.zsh
new file mode 100644
index 00000000..7ec6249b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/main-highlighter.zsh
@@ -0,0 +1,1846 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+
+# Define default styles.
+: ${ZSH_HIGHLIGHT_STYLES[default]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[unknown-token]:=fg=red,bold}
+: ${ZSH_HIGHLIGHT_STYLES[reserved-word]:=fg=yellow}
+: ${ZSH_HIGHLIGHT_STYLES[suffix-alias]:=fg=green,underline}
+: ${ZSH_HIGHLIGHT_STYLES[global-alias]:=fg=cyan}
+: ${ZSH_HIGHLIGHT_STYLES[precommand]:=fg=green,underline}
+: ${ZSH_HIGHLIGHT_STYLES[commandseparator]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[autodirectory]:=fg=green,underline}
+: ${ZSH_HIGHLIGHT_STYLES[path]:=underline}
+: ${ZSH_HIGHLIGHT_STYLES[path_pathseparator]:=}
+: ${ZSH_HIGHLIGHT_STYLES[path_prefix_pathseparator]:=}
+: ${ZSH_HIGHLIGHT_STYLES[globbing]:=fg=blue}
+: ${ZSH_HIGHLIGHT_STYLES[history-expansion]:=fg=blue}
+: ${ZSH_HIGHLIGHT_STYLES[command-substitution]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[command-substitution-delimiter]:=fg=magenta}
+: ${ZSH_HIGHLIGHT_STYLES[process-substitution]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[process-substitution-delimiter]:=fg=magenta}
+: ${ZSH_HIGHLIGHT_STYLES[single-hyphen-option]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[double-hyphen-option]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[back-quoted-argument]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[back-quoted-argument-delimiter]:=fg=magenta}
+: ${ZSH_HIGHLIGHT_STYLES[single-quoted-argument]:=fg=yellow}
+: ${ZSH_HIGHLIGHT_STYLES[double-quoted-argument]:=fg=yellow}
+: ${ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]:=fg=yellow}
+: ${ZSH_HIGHLIGHT_STYLES[rc-quote]:=fg=cyan}
+: ${ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]:=fg=cyan}
+: ${ZSH_HIGHLIGHT_STYLES[back-double-quoted-argument]:=fg=cyan}
+: ${ZSH_HIGHLIGHT_STYLES[back-dollar-quoted-argument]:=fg=cyan}
+: ${ZSH_HIGHLIGHT_STYLES[assign]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[redirection]:=fg=yellow}
+: ${ZSH_HIGHLIGHT_STYLES[comment]:=fg=black,bold}
+: ${ZSH_HIGHLIGHT_STYLES[named-fd]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[numeric-fd]:=none}
+: ${ZSH_HIGHLIGHT_STYLES[arg0]:=fg=green}
+
+# Whether the highlighter should be called or not.
+_zsh_highlight_highlighter_main_predicate()
+{
+ # may need to remove path_prefix highlighting when the line ends
+ [[ $WIDGET == zle-line-finish ]] || _zsh_highlight_buffer_modified
+}
+
+# Helper to deal with tokens crossing line boundaries.
+_zsh_highlight_main_add_region_highlight() {
+ integer start=$1 end=$2
+ shift 2
+
+ if (( $#in_alias )); then
+ [[ $1 == unknown-token ]] && alias_style=unknown-token
+ return
+ fi
+ if (( in_param )); then
+ if [[ $1 == unknown-token ]]; then
+ param_style=unknown-token
+ fi
+ if [[ -n $param_style ]]; then
+ return
+ fi
+ param_style=$1
+ return
+ fi
+
+ # The calculation was relative to $buf but region_highlight is relative to $BUFFER.
+ (( start += buf_offset ))
+ (( end += buf_offset ))
+
+ list_highlights+=($start $end $1)
+}
+
+_zsh_highlight_main_add_many_region_highlights() {
+ for 1 2 3; do
+ _zsh_highlight_main_add_region_highlight $1 $2 $3
+ done
+}
+
+_zsh_highlight_main_calculate_fallback() {
+ local -A fallback_of; fallback_of=(
+ alias arg0
+ suffix-alias arg0
+ global-alias dollar-double-quoted-argument
+ builtin arg0
+ function arg0
+ command arg0
+ precommand arg0
+ hashed-command arg0
+ autodirectory arg0
+ arg0_\* arg0
+
+ # TODO: Maybe these? —
+ # named-fd file-descriptor
+ # numeric-fd file-descriptor
+
+ path_prefix path
+ # The path separator fallback won't ever be used, due to the optimisation
+ # in _zsh_highlight_main_highlighter_highlight_path_separators().
+ path_pathseparator path
+ path_prefix_pathseparator path_prefix
+
+ single-quoted-argument{-unclosed,}
+ double-quoted-argument{-unclosed,}
+ dollar-quoted-argument{-unclosed,}
+ back-quoted-argument{-unclosed,}
+
+ command-substitution{-quoted,,-unquoted,}
+ command-substitution-delimiter{-quoted,,-unquoted,}
+
+ command-substitution{-delimiter,}
+ process-substitution{-delimiter,}
+ back-quoted-argument{-delimiter,}
+ )
+ local needle=$1 value
+ reply=($1)
+ while [[ -n ${value::=$fallback_of[(k)$needle]} ]]; do
+ unset "fallback_of[$needle]" # paranoia against infinite loops
+ reply+=($value)
+ needle=$value
+ done
+}
+
+# Get the type of a command.
+#
+# Uses the zsh/parameter module if available to avoid forks, and a
+# wrapper around 'type -w' as fallback.
+#
+# If $2 is 0, do not consider aliases.
+#
+# The result will be stored in REPLY.
+_zsh_highlight_main__type() {
+ integer -r aliases_allowed=${2-1}
+ # We won't cache replies of anything that exists as an alias at all, to
+ # ensure the cached value is correct regardless of $aliases_allowed.
+ #
+ # ### We probably _should_ cache them in a cache that's keyed on the value of
+ # ### $aliases_allowed, on the assumption that aliases are the common case.
+ integer may_cache=1
+
+ # Cache lookup
+ if (( $+_zsh_highlight_main__command_type_cache )); then
+ REPLY=$_zsh_highlight_main__command_type_cache[(e)$1]
+ if [[ -n "$REPLY" ]]; then
+ return
+ fi
+ fi
+
+ # Main logic
+ if (( $#options_to_set )); then
+ setopt localoptions $options_to_set;
+ fi
+ unset REPLY
+ if zmodload -e zsh/parameter; then
+ if (( $+aliases[(e)$1] )); then
+ may_cache=0
+ fi
+ if (( ${+galiases[(e)$1]} )) && (( aliases_allowed )); then
+ REPLY='global alias'
+ elif (( $+aliases[(e)$1] )) && (( aliases_allowed )); then
+ REPLY=alias
+ elif [[ $1 == *.* && -n ${1%.*} ]] && (( $+saliases[(e)${1##*.}] )); then
+ REPLY='suffix alias'
+ elif (( $reswords[(Ie)$1] )); then
+ REPLY=reserved
+ elif (( $+functions[(e)$1] )); then
+ REPLY=function
+ elif (( $+builtins[(e)$1] )); then
+ REPLY=builtin
+ elif (( $+commands[(e)$1] )); then
+ REPLY=command
+ # None of the special hashes had a match, so fall back to 'type -w', for
+ # forward compatibility with future versions of zsh that may add new command
+ # types.
+ #
+ # zsh 5.2 and older have a bug whereby running 'type -w ./sudo' implicitly
+ # runs 'hash ./sudo=/usr/local/bin/./sudo' (assuming /usr/local/bin/sudo
+ # exists and is in $PATH). Avoid triggering the bug, at the expense of
+ # falling through to the $() below, incurring a fork. (Issue #354.)
+ #
+ # The first disjunct mimics the isrelative() C call from the zsh bug.
+ elif { [[ $1 != */* ]] || is-at-least 5.3 } &&
+ # Add a subshell to avoid a zsh upstream bug; see issue #606.
+ # ### Remove the subshell when we stop supporting zsh 5.7.1 (I assume 5.8 will have the bugfix).
+ ! (builtin type -w -- "$1") >/dev/null 2>&1; then
+ REPLY=none
+ fi
+ fi
+ if ! (( $+REPLY )); then
+ # zsh/parameter not available or had no matches.
+ #
+ # Note that 'type -w' will run 'rehash' implicitly.
+ #
+ # We 'unalias' in a subshell, so the parent shell is not affected.
+ #
+ # The colon command is there just to avoid a command substitution that
+ # starts with an arithmetic expression [«((…))» as the first thing inside
+ # «$(…)»], which is area that has had some parsing bugs before 5.6
+ # (approximately).
+ REPLY="${$(:; (( aliases_allowed )) || unalias -- "$1" 2>/dev/null; LC_ALL=C builtin type -w -- "$1" 2>/dev/null)##*: }"
+ if [[ $REPLY == 'alias' ]]; then
+ may_cache=0
+ fi
+ fi
+
+ # Cache population
+ if (( may_cache )) && (( $+_zsh_highlight_main__command_type_cache )); then
+ _zsh_highlight_main__command_type_cache[(e)$1]=$REPLY
+ fi
+ [[ -n $REPLY ]]
+ return $?
+}
+
+# Checks whether $1 is something that can be run.
+#
+# Return 0 if runnable, 1 if not runnable, 2 if trouble.
+_zsh_highlight_main__is_runnable() {
+ if _zsh_highlight_main__type "$1"; then
+ [[ $REPLY != none ]]
+ else
+ return 2
+ fi
+}
+
+# Check whether the first argument is a redirection operator token.
+# Report result via the exit code.
+_zsh_highlight_main__is_redirection() {
+ # A redirection operator token:
+ # - starts with an optional single-digit number;
+ # - then, has a '<' or '>' character;
+ # - is not a process substitution [<(...) or >(...)].
+ # - is not a numeric glob <->
+ [[ $1 == (<0-9>|)(\<|\>)* ]] && [[ $1 != (\<|\>)$'\x28'* ]] && [[ $1 != *'<'*'-'*'>'* ]]
+}
+
+# Resolve alias.
+#
+# Takes a single argument.
+#
+# The result will be stored in REPLY.
+_zsh_highlight_main__resolve_alias() {
+ if zmodload -e zsh/parameter; then
+ REPLY=${aliases[$arg]}
+ else
+ REPLY="${"$(alias -- $arg)"#*=}"
+ fi
+}
+
+# Return true iff $1 is a global alias
+_zsh_highlight_main__is_global_alias() {
+ if zmodload -e zsh/parameter; then
+ (( ${+galiases[$arg]} ))
+ elif [[ $arg == '='* ]]; then
+ # avoid running into «alias -L '=foo'» erroring out with 'bad assignment'
+ return 1
+ else
+ alias -L -g -- "$1" >/dev/null
+ fi
+}
+
+# Check that the top of $braces_stack has the expected value. If it does, set
+# the style according to $2; otherwise, set style=unknown-token.
+#
+# $1: character expected to be at the top of $braces_stack
+# $2: optional assignment to style it if matches
+# return value is 0 if there is a match else 1
+_zsh_highlight_main__stack_pop() {
+ if [[ $braces_stack[1] == $1 ]]; then
+ braces_stack=${braces_stack:1}
+ if (( $+2 )); then
+ style=$2
+ fi
+ return 0
+ else
+ style=unknown-token
+ return 1
+ fi
+}
+
+# Main syntax highlighting function.
+_zsh_highlight_highlighter_main_paint()
+{
+ setopt localoptions extendedglob
+
+ # At the PS3 prompt and in vared, highlight nothing.
+ #
+ # (We can't check this in _zsh_highlight_highlighter_main_predicate because
+ # if the predicate returns false, the previous value of region_highlight
+ # would be reused.)
+ if [[ $CONTEXT == (select|vared) ]]; then
+ return
+ fi
+
+ typeset -a ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR
+ typeset -a ZSH_HIGHLIGHT_TOKENS_CONTROL_FLOW
+ local -a options_to_set reply # used in callees
+ local REPLY
+
+ # $flags_with_argument is a set of letters, corresponding to the option letters
+ # that would be followed by a colon in a getopts specification.
+ local flags_with_argument
+ # $flags_sans_argument is a set of letters, corresponding to the option letters
+ # that wouldn't be followed by a colon in a getopts specification.
+ local flags_sans_argument
+ # $flags_solo is a set of letters, corresponding to option letters that, if
+ # present, mean the precommand will not be acting as a precommand, i.e., will
+ # not be followed by a :start: word.
+ local flags_solo
+ # $precommand_options maps precommand name to values of $flags_with_argument,
+ # $flags_sans_argument, and flags_solo for that precommand, joined by a
+ # colon. (The value is NOT a getopt(3) spec, although it resembles one.)
+ #
+ # Currently, setting $flags_sans_argument is only important for commands that
+ # have a non-empty $flags_with_argument; see test-data/precommand4.zsh.
+ local -A precommand_options
+ precommand_options=(
+ # Precommand modifiers as of zsh 5.6.2 cf. zshmisc(1).
+ '-' ''
+ 'builtin' ''
+ 'command' :pvV
+ 'exec' a:cl
+ 'noglob' ''
+ # 'time' and 'nocorrect' shouldn't be added here; they're reserved words, not precommands.
+
+ # miscellaneous commands
+ 'doas' aCu:Lns # as of OpenBSD's doas(1) dated September 4, 2016
+ 'nice' n: # as of current POSIX spec
+ 'pkexec' '' # doesn't take short options; immune to #121 because it's usually not passed --option flags
+ # Not listed: -h, which has two different meanings.
+ 'sudo' Cgprtu:AEHPSbilns:eKkVv # as of sudo 1.8.21p2
+ 'stdbuf' ioe:
+ 'eatmydata' ''
+ 'catchsegv' ''
+ 'nohup' ''
+ 'setsid' :wc
+ 'env' u:i
+ 'ionice' cn:t:pPu # util-linux 2.33.1-0.1
+ 'strace' IbeaosXPpEuOS:ACdfhikqrtTvVxyDc # strace 4.26-0.2
+ 'proxychains' q:f # proxychains 4.4.0
+ 'torsocks' idq:upaP # Torsocks 2.3.0
+ 'torify' idq:upaP # Torsocks 2.3.0
+ 'ssh-agent' aEPt:csDd:k # As of OpenSSH 8.1p1
+ 'tabbed' gnprtTuU:cdfhs:v # suckless-tools v44
+ 'chronic' :ev # moreutils 0.62-1
+ 'ifne' :n # moreutils 0.62-1
+ 'grc' :se # grc - a "generic colouriser" (that's their spelling, not mine)
+ 'cpulimit' elp:ivz # cpulimit 0.2
+ )
+ # Commands that would need to skip one positional argument:
+ # flock
+ # ssh
+ # _wanted (skip two)
+
+ if [[ $zsyh_user_options[ignorebraces] == on || ${zsyh_user_options[ignoreclosebraces]:-off} == on ]]; then
+ local right_brace_is_recognised_everywhere=false
+ else
+ local right_brace_is_recognised_everywhere=true
+ fi
+
+ if [[ $zsyh_user_options[pathdirs] == on ]]; then
+ options_to_set+=( PATH_DIRS )
+ fi
+
+ ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR=(
+ '|' '||' ';' '&' '&&'
+ $'\n' # ${(z)} returns ';' but we convert it to $'\n'
+ '|&'
+ '&!' '&|'
+ # ### 'case' syntax, but followed by a pattern, not by a command
+ # ';;' ';&' ';|'
+ )
+
+ # Tokens that, at (naively-determined) "command position", are followed by
+ # a de jure command position. All of these are reserved words.
+ ZSH_HIGHLIGHT_TOKENS_CONTROL_FLOW=(
+ $'\x7b' # block
+ $'\x28' # subshell
+ '()' # anonymous function
+ 'while'
+ 'until'
+ 'if'
+ 'then'
+ 'elif'
+ 'else'
+ 'do'
+ 'time'
+ 'coproc'
+ '!' # reserved word; unrelated to $histchars[1]
+ )
+
+ if (( $+X_ZSH_HIGHLIGHT_DIRS_BLACKLIST )); then
+ print >&2 'zsh-syntax-highlighting: X_ZSH_HIGHLIGHT_DIRS_BLACKLIST is deprecated. Please use ZSH_HIGHLIGHT_DIRS_BLACKLIST.'
+ ZSH_HIGHLIGHT_DIRS_BLACKLIST=($X_ZSH_HIGHLIGHT_DIRS_BLACKLIST)
+ unset X_ZSH_HIGHLIGHT_DIRS_BLACKLIST
+ fi
+
+ _zsh_highlight_main_highlighter_highlight_list -$#PREBUFFER '' 1 "$PREBUFFER$BUFFER"
+
+ # end is a reserved word
+ local start end_ style
+ for start end_ style in $reply; do
+ (( start >= end_ )) && { print -r -- >&2 "zsh-syntax-highlighting: BUG: _zsh_highlight_highlighter_main_paint: start($start) >= end($end_)"; return }
+ (( end_ <= 0 )) && continue
+ (( start < 0 )) && start=0 # having start<0 is normal with e.g. multiline strings
+ _zsh_highlight_main_calculate_fallback $style
+ _zsh_highlight_add_highlight $start $end_ $reply
+ done
+}
+
+# Try to expand $1, if it's possible to do so safely.
+#
+# Uses two parameters from the caller: $parameter_name_pattern and $res.
+#
+# If expansion was done, set $reply to the expansion and return true.
+# Otherwise, return false.
+_zsh_highlight_main_highlighter__try_expand_parameter()
+{
+ local arg="$1"
+ unset reply
+ {
+ # ### For now, expand just '$foo' or '${foo}', possibly with braces, but with
+ # ### no other features of the parameter expansion syntax. (No ${(x)foo},
+ # ### no ${foo[x]}, no ${foo:-x}.)
+ {
+ local -a match mbegin mend
+ local MATCH; integer MBEGIN MEND
+ local parameter_name
+ local -a words
+ if [[ $arg[1] != '$' ]]; then
+ return 1
+ fi
+ if [[ ${arg[2]} == '{' ]] && [[ ${arg[-1]} == '}' ]]; then
+ parameter_name=${${arg:2}%?}
+ else
+ parameter_name=${arg:1}
+ fi
+ if [[ $res == none ]] &&
+ [[ ${parameter_name} =~ ^${~parameter_name_pattern}$ ]] &&
+ [[ ${(tP)MATCH} != *special* ]]
+ then
+ # Set $arg and update $res.
+ case ${(tP)MATCH} in
+ (*array*|*assoc*)
+ words=( ${(P)MATCH} )
+ ;;
+ ("")
+ # not set
+ words=( )
+ ;;
+ (*)
+ # scalar, presumably
+ if [[ $zsyh_user_options[shwordsplit] == on ]]; then
+ words=( ${(P)=MATCH} )
+ else
+ words=( ${(P)MATCH} )
+ fi
+ ;;
+ esac
+ reply=( "${words[@]}" )
+ else
+ return 1
+ fi
+ }
+ }
+}
+
+# $1 is the offset of $4 from the parent buffer. Added to the returned highlights.
+# $2 is the initial braces_stack (for a closing paren).
+# $3 is 1 if $4 contains the end of $BUFFER, else 0.
+# $4 is the buffer to highlight.
+# Returns:
+# $REPLY: $buf[REPLY] is the last character parsed.
+# $reply is an array of region_highlight additions.
+# exit code is 0 if the braces_stack is empty, 1 otherwise.
+_zsh_highlight_main_highlighter_highlight_list()
+{
+ integer start_pos end_pos=0 buf_offset=$1 has_end=$3
+ # alias_style is the style to apply to an alias once $#in_alias == 0
+ # Usually 'alias' but set to 'unknown-token' if any word expanded from
+ # the alias would be highlighted as unknown-token
+ # param_style is analogous for parameter expansions
+ local alias_style param_style last_arg arg buf=$4 highlight_glob=true saw_assignment=false style
+ local in_array_assignment=false # true between 'a=(' and the matching ')'
+ # in_alias is an array of integers with each element equal to the number
+ # of shifts needed until arg=args[1] pops an arg from the next level up
+ # alias or from BUFFER.
+ # in_param is analogous for parameter expansions
+ integer in_param=0 len=$#buf
+ local -a in_alias match mbegin mend list_highlights
+ # seen_alias is a map of aliases already seen to avoid loops like alias a=b b=a
+ local -A seen_alias
+ # Pattern for parameter names
+ readonly parameter_name_pattern='([A-Za-z_][A-Za-z0-9_]*|[0-9]+)'
+ list_highlights=()
+
+ # "R" for round
+ # "Q" for square
+ # "Y" for curly
+ # "T" for [[ ]]
+ # "S" for $( ), =( ), <( ), >( )
+ # "D" for do/done
+ # "$" for 'end' (matches 'foreach' always; also used with cshjunkiequotes in repeat/while)
+ # "?" for 'if'/'fi'; also checked by 'elif'/'else'
+ # ":" for 'then'
+ local braces_stack=$2
+
+ # State machine
+ #
+ # The states are:
+ # - :start: Command word
+ # - :start_of_pipeline: Start of a 'pipeline' as defined in zshmisc(1).
+ # Only valid when :start: is present
+ # - :sudo_opt: A leading-dash option to a precommand, whether it takes an
+ # argument or not. (Example: sudo's "-u" or "-i".)
+ # - :sudo_arg: The argument to a precommand's leading-dash option,
+ # when given as a separate word; i.e., "foo" in "-u foo" (two
+ # words) but not in "-ufoo" (one word).
+ # Note: :sudo_opt: and :sudo_arg: are used for any precommand
+ # declared in ${precommand_options}, not just for sudo(8).
+ # The naming is historical.
+ # - :regular: "Not a command word", and command delimiters are permitted.
+ # Mainly used to detect premature termination of commands.
+ # - :always: The word 'always' in the «{ foo } always { bar }» syntax.
+ #
+ # When the kind of a word is not yet known, $this_word / $next_word may contain
+ # multiple states. For example, after "sudo -i", the next word may be either
+ # another --flag or a command name, hence the state would include both ':start:'
+ # and ':sudo_opt:'.
+ #
+ # The tokens are always added with both leading and trailing colons to serve as
+ # word delimiters (an improvised array); [[ $x == *':foo:'* ]] and x=${x//:foo:/}
+ # will DTRT regardless of how many elements or repetitions $x has.
+ #
+ # Handling of redirections: upon seeing a redirection token, we must stall
+ # the current state --- that is, the value of $this_word --- for two iterations
+ # (one for the redirection operator, one for the word following it representing
+ # the redirection target). Therefore, we set $in_redirection to 2 upon seeing a
+ # redirection operator, decrement it each iteration, and stall the current state
+ # when it is non-zero. Thus, upon reaching the next word (the one that follows
+ # the redirection operator and target), $this_word will still contain values
+ # appropriate for the word immediately following the word that preceded the
+ # redirection operator.
+ #
+ # The "the previous word was a redirection operator" state is not communicated
+ # to the next iteration via $next_word/$this_word as usual, but via
+ # $in_redirection. The value of $next_word from the iteration that processed
+ # the operator is discarded.
+ #
+ # $in_redirection is currently used for:
+ # - comments
+ # - aliases
+ # - redirections
+ # - parameter elision in command position
+ # - 'repeat' loops
+ #
+ local this_word next_word=':start::start_of_pipeline:'
+ integer in_redirection
+ # Processing buffer
+ local proc_buf="$buf"
+ local -a args
+ if [[ $zsyh_user_options[interactivecomments] == on ]]; then
+ args=(${(zZ+c+)buf})
+ else
+ args=(${(z)buf})
+ fi
+
+ # Special case: $(<*) isn't globbing.
+ if [[ $braces_stack == 'S' ]] && (( $+args[3] && ! $+args[4] )) && [[ $args[3] == $'\x29' ]] &&
+ [[ $args[1] == *'<'* ]] && _zsh_highlight_main__is_redirection $args[1]; then
+ highlight_glob=false
+ fi
+
+ while (( $#args )); do
+ last_arg=$arg
+ arg=$args[1]
+ shift args
+ if (( $#in_alias )); then
+ (( in_alias[1]-- ))
+ # Remove leading 0 entries
+ in_alias=($in_alias[$in_alias[(i)<1->],-1])
+ if (( $#in_alias == 0 )); then
+ seen_alias=()
+ # start_pos and end_pos are of the alias (previous $arg) here
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos $alias_style
+ else
+ # We can't unset keys that contain special characters (] \ and some others).
+ # More details: https://www.zsh.org/workers/43269
+ (){
+ local alias_name
+ for alias_name in ${(k)seen_alias[(R)<$#in_alias->]}; do
+ seen_alias=("${(@kv)seen_alias[(I)^$alias_name]}")
+ done
+ }
+ fi
+ fi
+ if (( in_param )); then
+ (( in_param-- ))
+ if (( in_param == 0 )); then
+ # start_pos and end_pos are of the '$foo' word (previous $arg) here
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos $param_style
+ param_style=""
+ fi
+ fi
+
+ # Initialize this_word and next_word.
+ if (( in_redirection == 0 )); then
+ this_word=$next_word
+ next_word=':regular:'
+ elif (( !in_param )); then
+ # Stall $next_word.
+ (( --in_redirection ))
+ fi
+
+ # Initialize per-"simple command" [zshmisc(1)] variables:
+ #
+ # $style how to highlight $arg
+ # $in_array_assignment boolean flag for "between '(' and ')' of array assignment"
+ # $highlight_glob boolean flag for "'noglob' is in effect"
+ # $saw_assignment boolean flag for "was preceded by an assignment"
+ #
+ style=unknown-token
+ if [[ $this_word == *':start:'* ]]; then
+ in_array_assignment=false
+ if [[ $arg == 'noglob' ]]; then
+ highlight_glob=false
+ fi
+ fi
+
+ if (( $#in_alias == 0 && in_param == 0 )); then
+ # Compute the new $start_pos and $end_pos, skipping over whitespace in $buf.
+ [[ "$proc_buf" = (#b)(#s)(''([ $'\t']|[\\]$'\n')#)(?|)* ]]
+ # The first, outer parenthesis
+ integer offset="${#match[1]}"
+ (( start_pos = end_pos + offset ))
+ (( end_pos = start_pos + $#arg ))
+
+ # The zsh lexer considers ';' and newline to be the same token, so
+ # ${(z)} converts all newlines to semicolons. Convert them back here to
+ # make later processing simpler.
+ [[ $arg == ';' && ${match[3]} == $'\n' ]] && arg=$'\n'
+
+ # Compute the new $proc_buf. We advance it
+ # (chop off characters from the beginning)
+ # beyond what end_pos points to, by skipping
+ # as many characters as end_pos was advanced.
+ #
+ # end_pos was advanced by $offset (via start_pos)
+ # and by $#arg. Note the `start_pos=$end_pos`
+ # below.
+ #
+ # As for the [,len]. We could use [,len-start_pos+offset]
+ # here, but to make it easier on eyes, we use len and
+ # rely on the fact that Zsh simply handles that. The
+ # length of proc_buf is len-start_pos+offset because
+ # we're chopping it to match current start_pos, so its
+ # length matches the previous value of start_pos.
+ #
+ # Why [,-1] is slower than [,length] isn't clear.
+ proc_buf="${proc_buf[offset + $#arg + 1,len]}"
+ fi
+
+ # Handle the INTERACTIVE_COMMENTS option.
+ #
+ # We use the (Z+c+) flag so the entire comment is presented as one token in $arg.
+ if [[ $zsyh_user_options[interactivecomments] == on && $arg[1] == $histchars[3] ]]; then
+ if [[ $this_word == *(':regular:'|':start:')* ]]; then
+ style=comment
+ else
+ style=unknown-token # prematurely terminated
+ fi
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos $style
+ # Stall this arg
+ in_redirection=1
+ continue
+ fi
+
+ if [[ $this_word == *':start:'* ]] && ! (( in_redirection )); then
+ # Expand aliases.
+ # An alias is ineligible for expansion while it's being expanded (see #652/#653).
+ _zsh_highlight_main__type "$arg" "$(( ! ${+seen_alias[$arg]} ))"
+ local res="$REPLY"
+ if [[ $res == "alias" ]]; then
+ # Mark insane aliases as unknown-token (cf. #263).
+ if [[ $arg == ?*=* ]]; then
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos unknown-token
+ continue
+ fi
+ seen_alias[$arg]=$#in_alias
+ _zsh_highlight_main__resolve_alias $arg
+ local -a alias_args
+ # Elision is desired in case alias x=''
+ if [[ $zsyh_user_options[interactivecomments] == on ]]; then
+ alias_args=(${(zZ+c+)REPLY})
+ else
+ alias_args=(${(z)REPLY})
+ fi
+ args=( $alias_args $args )
+ if (( $#in_alias == 0 )); then
+ alias_style=alias
+ else
+ # Transfer the count of this arg to the new element about to be appended.
+ (( in_alias[1]-- ))
+ fi
+ # Add one because we will in_alias[1]-- on the next loop iteration so
+ # this iteration should be considered in in_alias as well
+ in_alias=( $(($#alias_args + 1)) $in_alias )
+ (( in_redirection++ )) # Stall this arg
+ continue
+ else
+ _zsh_highlight_main_highlighter_expand_path $arg
+ _zsh_highlight_main__type "$REPLY" 0
+ res="$REPLY"
+ fi
+ fi
+
+ # Analyse the current word.
+ if _zsh_highlight_main__is_redirection $arg ; then
+ if (( in_redirection == 1 )); then
+ # Two consecutive redirection operators is an error.
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos unknown-token
+ else
+ in_redirection=2
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos redirection
+ fi
+ continue
+ elif [[ $arg == '{'${~parameter_name_pattern}'}' ]] && _zsh_highlight_main__is_redirection $args[1]; then
+ # named file descriptor: {foo}>&2
+ in_redirection=3
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos named-fd
+ continue
+ fi
+
+ # Expand parameters.
+ if (( ! in_param )) && _zsh_highlight_main_highlighter__try_expand_parameter "$arg"; then
+ # That's not entirely correct --- if the parameter's value happens to be a reserved
+ # word, the parameter expansion will be highlighted as a reserved word --- but that
+ # incorrectness is outweighed by the usability improvement of permitting the use of
+ # parameters that refer to commands, functions, and builtins.
+ () {
+ local -a words; words=( "${reply[@]}" )
+ if (( $#words == 0 )) && (( ! in_redirection )); then
+ # Parameter elision is happening
+ (( ++in_redirection ))
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos comment
+ continue
+ else
+ (( in_param = 1 + $#words ))
+ args=( $words $args )
+ arg=$args[1]
+ _zsh_highlight_main__type "$arg" 0
+ res=$REPLY
+ fi
+ }
+ fi
+
+ # Parse the sudo command line
+ if (( ! in_redirection )); then
+ if [[ $this_word == *':sudo_opt:'* ]]; then
+ if [[ -n $flags_with_argument ]] &&
+ {
+ # Trenary
+ if [[ -n $flags_sans_argument ]]
+ then [[ $arg == '-'[$flags_sans_argument]#[$flags_with_argument] ]]
+ else [[ $arg == '-'[$flags_with_argument] ]]
+ fi
+ } then
+ # Flag that requires an argument
+ this_word=${this_word//:start:/}
+ next_word=':sudo_arg:'
+ elif [[ -n $flags_with_argument ]] &&
+ {
+ # Trenary
+ if [[ -n $flags_sans_argument ]]
+ then [[ $arg == '-'[$flags_sans_argument]#[$flags_with_argument]* ]]
+ else [[ $arg == '-'[$flags_with_argument]* ]]
+ fi
+ } then
+ # Argument attached in the same word
+ this_word=${this_word//:start:/}
+ next_word+=':start:'
+ next_word+=':sudo_opt:'
+ elif [[ -n $flags_sans_argument ]] &&
+ [[ $arg == '-'[$flags_sans_argument]# ]]; then
+ # Flag that requires no argument
+ this_word=':sudo_opt:'
+ next_word+=':start:'
+ next_word+=':sudo_opt:'
+ elif [[ -n $flags_solo ]] &&
+ {
+ # Trenary
+ if [[ -n $flags_sans_argument ]]
+ then [[ $arg == '-'[$flags_sans_argument]#[$flags_solo]* ]]
+ else [[ $arg == '-'[$flags_solo]* ]]
+ fi
+ } then
+ # Solo flags
+ this_word=':sudo_opt:'
+ next_word=':regular:' # no :start:, nor :sudo_opt: since we don't know whether the solo flag takes an argument or not
+ elif [[ $arg == '-'* ]]; then
+ # Unknown flag. We don't know whether it takes an argument or not,
+ # so modify $next_word as we do for flags that require no argument.
+ # With that behaviour, if the flag in fact takes no argument we'll
+ # highlight the inner command word correctly, and if it does take an
+ # argument we'll highlight the command word correctly if the argument
+ # was given in the same shell word as the flag (as in '-uphy1729' or
+ # '--user=phy1729' without spaces).
+ this_word=':sudo_opt:'
+ next_word+=':start:'
+ next_word+=':sudo_opt:'
+ else
+ # Not an option flag; nothing to do. (If the command line is
+ # syntactically valid, ${this_word//:sudo_opt:/} should be
+ # non-empty now.)
+ this_word=${this_word//:sudo_opt:/}
+ fi
+ elif [[ $this_word == *':sudo_arg:'* ]]; then
+ next_word+=':sudo_opt:'
+ next_word+=':start:'
+ fi
+ fi
+
+ # The Great Fork: is this a command word? Is this a non-command word?
+ if [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR:#"$arg"} ]] &&
+ [[ $braces_stack != *T* || $arg != ('||'|'&&') ]]; then
+
+ # First, determine the style of the command separator itself.
+ if _zsh_highlight_main__stack_pop T || _zsh_highlight_main__stack_pop Q; then
+ # Missing closing square bracket(s)
+ style=unknown-token
+ elif $in_array_assignment; then
+ case $arg in
+ # Literal newlines are just fine.
+ ($'\n') style=commandseparator;;
+ # Semicolons are parsed the same way as literal newlines. Nevertheless,
+ # highlight them as errors since they're probably unintended. Compare
+ # issue #691.
+ (';') style=unknown-token;;
+ # Other command separators aren't allowed.
+ (*) style=unknown-token;;
+ esac
+ elif [[ $this_word == *':regular:'* ]]; then
+ style=commandseparator
+ elif [[ $this_word == *':start:'* ]] && [[ $arg == $'\n' ]]; then
+ style=commandseparator
+ elif [[ $this_word == *':start:'* ]] && [[ $arg == ';' ]] && (( $#in_alias )); then
+ style=commandseparator
+ else
+ # Empty commands (semicolon follows nothing) are valid syntax.
+ # However, in interactive use they are likely to be erroneous;
+ # therefore, we highlight them as errors.
+ #
+ # Alias definitions are exempted from this check to allow multiline aliases
+ # with explicit (redundant) semicolons: «alias foo=$'bar;\nbaz'» (issue #677).
+ #
+ # See also #691 about possibly changing the style used here.
+ style=unknown-token
+ fi
+
+ # Second, determine the style of next_word.
+ if [[ $arg == $'\n' ]] && $in_array_assignment; then
+ # literal newline inside an array assignment
+ next_word=':regular:'
+ elif [[ $arg == ';' ]] && $in_array_assignment; then
+ # literal semicolon inside an array assignment
+ next_word=':regular:'
+ else
+ next_word=':start:'
+ highlight_glob=true
+ saw_assignment=false
+ (){
+ local alias_name
+ for alias_name in ${(k)seen_alias[(R)<$#in_alias->]}; do
+ # We can't unset keys that contain special characters (] \ and some others).
+ # More details: https://www.zsh.org/workers/43269
+ seen_alias=("${(@kv)seen_alias[(I)^$alias_name]}")
+ done
+ }
+ if [[ $arg != '|' && $arg != '|&' ]]; then
+ next_word+=':start_of_pipeline:'
+ fi
+ fi
+
+ elif ! (( in_redirection)) && [[ $this_word == *':always:'* && $arg == 'always' ]]; then
+ # try-always construct
+ style=reserved-word # de facto a reserved word, although not de jure
+ highlight_glob=true
+ saw_assignment=false
+ next_word=':start::start_of_pipeline:' # only left brace is allowed, apparently
+ elif ! (( in_redirection)) && [[ $this_word == *':start:'* ]]; then # $arg is the command word
+ if (( ${+precommand_options[$arg]} )) && _zsh_highlight_main__is_runnable $arg; then
+ style=precommand
+ () {
+ set -- "${(@s.:.)precommand_options[$arg]}"
+ flags_with_argument=$1
+ flags_sans_argument=$2
+ flags_solo=$3
+ }
+ next_word=${next_word//:regular:/}
+ next_word+=':sudo_opt:'
+ next_word+=':start:'
+ if [[ $arg == 'exec' || $arg == 'env' ]]; then
+ # To allow "exec 2>&1;" and "env | grep" where there's no command word
+ next_word+=':regular:'
+ fi
+ else
+ case $res in
+ (reserved) # reserved word
+ style=reserved-word
+ # Match braces and handle special cases.
+ case $arg in
+ (time|nocorrect)
+ next_word=${next_word//:regular:/}
+ next_word+=':start:'
+ ;;
+ ($'\x7b')
+ braces_stack='Y'"$braces_stack"
+ ;;
+ ($'\x7d')
+ # We're at command word, so no need to check $right_brace_is_recognised_everywhere
+ _zsh_highlight_main__stack_pop 'Y' reserved-word
+ if [[ $style == reserved-word ]]; then
+ next_word+=':always:'
+ fi
+ ;;
+ ($'\x5b\x5b')
+ braces_stack='T'"$braces_stack"
+ ;;
+ ('do')
+ braces_stack='D'"$braces_stack"
+ ;;
+ ('done')
+ _zsh_highlight_main__stack_pop 'D' reserved-word
+ ;;
+ ('if')
+ braces_stack=':?'"$braces_stack"
+ ;;
+ ('then')
+ _zsh_highlight_main__stack_pop ':' reserved-word
+ ;;
+ ('elif')
+ if [[ ${braces_stack[1]} == '?' ]]; then
+ braces_stack=':'"$braces_stack"
+ else
+ style=unknown-token
+ fi
+ ;;
+ ('else')
+ if [[ ${braces_stack[1]} == '?' ]]; then
+ :
+ else
+ style=unknown-token
+ fi
+ ;;
+ ('fi')
+ _zsh_highlight_main__stack_pop '?'
+ ;;
+ ('foreach')
+ braces_stack='$'"$braces_stack"
+ ;;
+ ('end')
+ _zsh_highlight_main__stack_pop '$' reserved-word
+ ;;
+ ('repeat')
+ # skip the repeat-count word
+ in_redirection=2
+ # The redirection mechanism assumes $this_word describes the word
+ # following the redirection. Make it so.
+ #
+ # That word can be a command word with shortloops (`repeat 2 ls`)
+ # or a command separator (`repeat 2; ls` or `repeat 2; do ls; done`).
+ #
+ # The repeat-count word will be handled like a redirection target.
+ this_word=':start::regular:'
+ ;;
+ ('!')
+ if [[ $this_word != *':start_of_pipeline:'* ]]; then
+ style=unknown-token
+ else
+ # '!' reserved word at start of pipeline; style already set above
+ fi
+ ;;
+ esac
+ if $saw_assignment && [[ $style != unknown-token ]]; then
+ style=unknown-token
+ fi
+ ;;
+ ('suffix alias')
+ style=suffix-alias
+ ;;
+ ('global alias')
+ style=global-alias
+ ;;
+ (alias) :;;
+ (builtin) style=builtin
+ [[ $arg == $'\x5b' ]] && braces_stack='Q'"$braces_stack"
+ ;;
+ (function) style=function;;
+ (command) style=command;;
+ (hashed) style=hashed-command;;
+ (none) if (( ! in_param )) && _zsh_highlight_main_highlighter_check_assign; then
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos assign
+ local i=$(( arg[(i)=] + 1 ))
+ saw_assignment=true
+ if [[ $arg[i] == '(' ]]; then
+ in_array_assignment=true
+ _zsh_highlight_main_add_region_highlight start_pos+i-1 start_pos+i reserved-word
+ else
+ # assignment to a scalar parameter.
+ # (For array assignments, the command doesn't start until the ")" token.)
+ #
+ # Discard :start_of_pipeline:, if present, as '!' is not valid
+ # after assignments.
+ next_word+=':start:'
+ if (( i <= $#arg )); then
+ () {
+ local highlight_glob=false
+ [[ $zsyh_user_options[globassign] == on ]] && highlight_glob=true
+ _zsh_highlight_main_highlighter_highlight_argument $i
+ }
+ fi
+ fi
+ continue
+ elif (( ! in_param )) &&
+ [[ $arg[0,1] = $histchars[0,1] ]] && (( $#arg[0,2] == 2 )); then
+ style=history-expansion
+ elif (( ! in_param )) &&
+ [[ $arg[0,1] == $histchars[2,2] ]]; then
+ style=history-expansion
+ elif (( ! in_param )) &&
+ ! $saw_assignment &&
+ [[ $arg[1,2] == '((' ]]; then
+ # Arithmetic evaluation.
+ #
+ # Note: prior to zsh-5.1.1-52-g4bed2cf (workers/36669), the ${(z)...}
+ # splitter would only output the '((' token if the matching '))' had
+ # been typed. Therefore, under those versions of zsh, BUFFER="(( 42"
+ # would be highlighted as an error until the matching "))" are typed.
+ #
+ # We highlight just the opening parentheses, as a reserved word; this
+ # is how [[ ... ]] is highlighted, too.
+ _zsh_highlight_main_add_region_highlight $start_pos $((start_pos + 2)) reserved-word
+ if [[ $arg[-2,-1] == '))' ]]; then
+ _zsh_highlight_main_add_region_highlight $((end_pos - 2)) $end_pos reserved-word
+ fi
+ continue
+ elif (( ! in_param )) &&
+ [[ $arg == '()' ]]; then
+ # anonymous function
+ style=reserved-word
+ elif (( ! in_param )) &&
+ ! $saw_assignment &&
+ [[ $arg == $'\x28' ]]; then
+ # subshell
+ style=reserved-word
+ braces_stack='R'"$braces_stack"
+ elif (( ! in_param )) &&
+ [[ $arg == $'\x29' ]]; then
+ # end of subshell or command substitution
+ if _zsh_highlight_main__stack_pop 'S'; then
+ REPLY=$start_pos
+ reply=($list_highlights)
+ return 0
+ fi
+ _zsh_highlight_main__stack_pop 'R' reserved-word
+ else
+ if _zsh_highlight_main_highlighter_check_path $arg 1; then
+ style=$REPLY
+ else
+ style=unknown-token
+ fi
+ fi
+ ;;
+ (*) _zsh_highlight_main_add_region_highlight $start_pos $end_pos arg0_$res
+ continue
+ ;;
+ esac
+ fi
+ if [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_CONTROL_FLOW:#"$arg"} ]]; then
+ next_word=':start::start_of_pipeline:'
+ fi
+ elif _zsh_highlight_main__is_global_alias "$arg"; then # $arg is a global alias that isn't in command position
+ style=global-alias
+ else # $arg is a non-command word
+ case $arg in
+ ($'\x29')
+ # subshell or end of array assignment
+ if $in_array_assignment; then
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos assign
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos reserved-word
+ in_array_assignment=false
+ next_word+=':start:'
+ continue
+ elif (( in_redirection )); then
+ style=unknown-token
+ else
+ if _zsh_highlight_main__stack_pop 'S'; then
+ REPLY=$start_pos
+ reply=($list_highlights)
+ return 0
+ fi
+ _zsh_highlight_main__stack_pop 'R' reserved-word
+ fi
+ ;;
+ ($'\x28\x29')
+ # possibly a function definition
+ if (( in_redirection )) || $in_array_assignment; then
+ style=unknown-token
+ else
+ if [[ $zsyh_user_options[multifuncdef] == on ]] || false # TODO: or if the previous word was a command word
+ then
+ next_word+=':start::start_of_pipeline:'
+ fi
+ style=reserved-word
+ fi
+ ;;
+ (*) if false; then
+ elif [[ $arg = $'\x7d' ]] && $right_brace_is_recognised_everywhere; then
+ # Parsing rule: {
+ #
+ # Additionally, `tt(})' is recognized in any position if neither the
+ # tt(IGNORE_BRACES) option nor the tt(IGNORE_CLOSE_BRACES) option is set.
+ if (( in_redirection )) || $in_array_assignment; then
+ style=unknown-token
+ else
+ _zsh_highlight_main__stack_pop 'Y' reserved-word
+ if [[ $style == reserved-word ]]; then
+ next_word+=':always:'
+ fi
+ fi
+ elif [[ $arg[0,1] = $histchars[0,1] ]] && (( $#arg[0,2] == 2 )); then
+ style=history-expansion
+ elif [[ $arg == $'\x5d\x5d' ]] && _zsh_highlight_main__stack_pop 'T' reserved-word; then
+ :
+ elif [[ $arg == $'\x5d' ]] && _zsh_highlight_main__stack_pop 'Q' builtin; then
+ :
+ else
+ _zsh_highlight_main_highlighter_highlight_argument 1 $(( 1 != in_redirection ))
+ continue
+ fi
+ ;;
+ esac
+ fi
+ _zsh_highlight_main_add_region_highlight $start_pos $end_pos $style
+ done
+ (( $#in_alias )) && in_alias=() _zsh_highlight_main_add_region_highlight $start_pos $end_pos $alias_style
+ (( in_param == 1 )) && in_param=0 _zsh_highlight_main_add_region_highlight $start_pos $end_pos $param_style
+ [[ "$proc_buf" = (#b)(#s)(([[:space:]]|\\$'\n')#) ]]
+ REPLY=$(( end_pos + ${#match[1]} - 1 ))
+ reply=($list_highlights)
+ return $(( $#braces_stack > 0 ))
+}
+
+# Check if $arg is variable assignment
+_zsh_highlight_main_highlighter_check_assign()
+{
+ setopt localoptions extended_glob
+ [[ $arg == [[:alpha:]_][[:alnum:]_]#(|\[*\])(|[+])=* ]] ||
+ [[ $arg == [0-9]##(|[+])=* ]]
+}
+
+_zsh_highlight_main_highlighter_highlight_path_separators()
+{
+ local pos style_pathsep
+ style_pathsep=$1_pathseparator
+ reply=()
+ [[ -z "$ZSH_HIGHLIGHT_STYLES[$style_pathsep]" || "$ZSH_HIGHLIGHT_STYLES[$1]" == "$ZSH_HIGHLIGHT_STYLES[$style_pathsep]" ]] && return 0
+ for (( pos = start_pos; $pos <= end_pos; pos++ )) ; do
+ if [[ $BUFFER[pos] == / ]]; then
+ reply+=($((pos - 1)) $pos $style_pathsep)
+ fi
+ done
+}
+
+# Check if $1 is a path.
+# If yes, return 0 and in $REPLY the style to use.
+# Else, return non-zero (and the contents of $REPLY is undefined).
+#
+# $2 should be non-zero iff we're in command position.
+_zsh_highlight_main_highlighter_check_path()
+{
+ _zsh_highlight_main_highlighter_expand_path "$1"
+ local expanded_path="$REPLY" tmp_path
+ integer in_command_position=$2
+
+ if [[ $zsyh_user_options[autocd] == on ]]; then
+ integer autocd=1
+ else
+ integer autocd=0
+ fi
+
+ if (( in_command_position )); then
+ # ### Currently, this value is never returned: either it's overwritten
+ # ### below, or the return code is non-zero
+ REPLY=arg0
+ else
+ REPLY=path
+ fi
+
+ if [[ ${1[1]} == '=' && $1 == ??* && ${1[2]} != $'\x28' && $zsyh_user_options[equals] == 'on' && $expanded_path[1] != '/' ]]; then
+ REPLY=unknown-token # will error out if executed
+ return 0
+ fi
+
+ [[ -z $expanded_path ]] && return 1
+
+ # Check if this is a blacklisted path
+ if [[ $expanded_path[1] == / ]]; then
+ tmp_path=$expanded_path
+ else
+ tmp_path=$PWD/$expanded_path
+ fi
+ tmp_path=$tmp_path:a
+
+ while [[ $tmp_path != / ]]; do
+ [[ -n ${(M)ZSH_HIGHLIGHT_DIRS_BLACKLIST:#$tmp_path} ]] && return 1
+ tmp_path=$tmp_path:h
+ done
+
+ if (( in_command_position )); then
+ if [[ -x $expanded_path ]]; then
+ if (( autocd )); then
+ if [[ -d $expanded_path ]]; then
+ REPLY=autodirectory
+ fi
+ return 0
+ elif [[ ! -d $expanded_path ]]; then
+ # ### This seems unreachable for the current callers
+ return 0
+ fi
+ fi
+ else
+ if [[ -L $expanded_path || -e $expanded_path ]]; then
+ return 0
+ fi
+ fi
+
+ # Search the path in CDPATH
+ if [[ $expanded_path != /* ]] && (( autocd || ! in_command_position )); then
+ # TODO: When we've dropped support for pre-5.0.6 zsh, use the *(Y1) glob qualifier here.
+ local cdpath_dir
+ for cdpath_dir in $cdpath ; do
+ if [[ -d "$cdpath_dir/$expanded_path" && -x "$cdpath_dir/$expanded_path" ]]; then
+ if (( in_command_position && autocd )); then
+ REPLY=autodirectory
+ fi
+ return 0
+ fi
+ done
+ fi
+
+ # If dirname($1) doesn't exist, neither does $1.
+ [[ ! -d ${expanded_path:h} ]] && return 1
+
+ # If this word ends the buffer, check if it's the prefix of a valid path.
+ if (( has_end && (len == end_pos) )) &&
+ (( ! $#in_alias )) &&
+ [[ $WIDGET != zle-line-finish ]]; then
+ # TODO: When we've dropped support for pre-5.0.6 zsh, use the *(Y1) glob qualifier here.
+ local -a tmp
+ if (( in_command_position )); then
+ # We include directories even when autocd is enabled, because those
+ # directories might contain executable files: e.g., BUFFER="/bi" en route
+ # to typing "/bin/sh".
+ tmp=( ${expanded_path}*(N-*,N-/) )
+ else
+ tmp=( ${expanded_path}*(N) )
+ fi
+ (( ${+tmp[1]} )) && REPLY=path_prefix && return 0
+ fi
+
+ # It's not a path.
+ return 1
+}
+
+# Highlight an argument and possibly special chars in quotes starting at $1 in $arg
+# This command will at least highlight $1 to end_pos with the default style
+# If $2 is set to 0, the argument cannot be highlighted as an option.
+#
+# This function currently assumes it's never called for the command word.
+_zsh_highlight_main_highlighter_highlight_argument()
+{
+ local base_style=default i=$1 option_eligible=${2:-1} path_eligible=1 ret start style
+ local -a highlights
+
+ local -a match mbegin mend
+ local MATCH; integer MBEGIN MEND
+
+ case "$arg[i]" in
+ '%')
+ if [[ $arg[i+1] == '?' ]]; then
+ (( i += 2 ))
+ fi
+ ;;
+ '-')
+ if (( option_eligible )); then
+ if [[ $arg[i+1] == - ]]; then
+ base_style=double-hyphen-option
+ else
+ base_style=single-hyphen-option
+ fi
+ path_eligible=0
+ fi
+ ;;
+ '=')
+ if [[ $arg[i+1] == $'\x28' ]]; then
+ (( i += 2 ))
+ _zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,-1]
+ ret=$?
+ (( i += REPLY ))
+ highlights+=(
+ $(( start_pos + $1 - 1 )) $(( start_pos + i )) process-substitution
+ $(( start_pos + $1 - 1 )) $(( start_pos + $1 + 1 )) process-substitution-delimiter
+ $reply
+ )
+ if (( ret == 0 )); then
+ highlights+=($(( start_pos + i - 1 )) $(( start_pos + i )) process-substitution-delimiter)
+ fi
+ fi
+ esac
+
+ # This loop is a hot path. Keep it fast!
+ (( --i ))
+ while (( ++i <= $#arg )); do
+ i=${arg[(ib.i.)[\\\'\"\`\$\<\>\*\?]]}
+ case "$arg[$i]" in
+ "") break;;
+ "\\") (( i += 1 )); continue;;
+ "'")
+ _zsh_highlight_main_highlighter_highlight_single_quote $i
+ (( i = REPLY ))
+ highlights+=($reply)
+ ;;
+ '"')
+ _zsh_highlight_main_highlighter_highlight_double_quote $i
+ (( i = REPLY ))
+ highlights+=($reply)
+ ;;
+ '`')
+ _zsh_highlight_main_highlighter_highlight_backtick $i
+ (( i = REPLY ))
+ highlights+=($reply)
+ ;;
+ '$')
+ if [[ $arg[i+1] != "'" ]]; then
+ path_eligible=0
+ fi
+ if [[ $arg[i+1] == "'" ]]; then
+ _zsh_highlight_main_highlighter_highlight_dollar_quote $i
+ (( i = REPLY ))
+ highlights+=($reply)
+ continue
+ elif [[ $arg[i+1] == $'\x28' ]]; then
+ if [[ $arg[i+2] == $'\x28' ]] && _zsh_highlight_main_highlighter_highlight_arithmetic $i; then
+ # Arithmetic expansion
+ (( i = REPLY ))
+ highlights+=($reply)
+ continue
+ fi
+ start=$i
+ (( i += 2 ))
+ _zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,-1]
+ ret=$?
+ (( i += REPLY ))
+ highlights+=(
+ $(( start_pos + start - 1)) $(( start_pos + i )) command-substitution-unquoted
+ $(( start_pos + start - 1)) $(( start_pos + start + 1)) command-substitution-delimiter-unquoted
+ $reply
+ )
+ if (( ret == 0 )); then
+ highlights+=($(( start_pos + i - 1)) $(( start_pos + i )) command-substitution-delimiter-unquoted)
+ fi
+ continue
+ fi
+ while [[ $arg[i+1] == [=~#+'^'] ]]; do
+ (( i += 1 ))
+ done
+ if [[ $arg[i+1] == [*@#?$!-] ]]; then
+ (( i += 1 ))
+ fi;;
+ [\<\>])
+ if [[ $arg[i+1] == $'\x28' ]]; then # \x28 = open paren
+ start=$i
+ (( i += 2 ))
+ _zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,-1]
+ ret=$?
+ (( i += REPLY ))
+ highlights+=(
+ $(( start_pos + start - 1)) $(( start_pos + i )) process-substitution
+ $(( start_pos + start - 1)) $(( start_pos + start + 1 )) process-substitution-delimiter
+ $reply
+ )
+ if (( ret == 0 )); then
+ highlights+=($(( start_pos + i - 1)) $(( start_pos + i )) process-substitution-delimiter)
+ fi
+ continue
+ fi
+ ;|
+ *)
+ if $highlight_glob &&
+ [[ $zsyh_user_options[multios] == on || $in_redirection -eq 0 ]] &&
+ [[ ${arg[$i]} =~ ^[*?] || ${arg:$i-1} =~ ^\<[0-9]*-[0-9]*\> ]]; then
+ highlights+=($(( start_pos + i - 1 )) $(( start_pos + i + $#MATCH - 1)) globbing)
+ (( i += $#MATCH - 1 ))
+ path_eligible=0
+ else
+ continue
+ fi
+ ;;
+ esac
+ done
+
+ if (( path_eligible )); then
+ if (( in_redirection )) && [[ $last_arg == *['<>']['&'] && $arg[$1,-1] == (<0->|p|-) ]]; then
+ if [[ $arg[$1,-1] == (p|-) ]]; then
+ base_style=redirection
+ else
+ base_style=numeric-fd
+ fi
+ # This function is currently never called for the command word, so $2 is hard-coded as 0.
+ elif _zsh_highlight_main_highlighter_check_path $arg[$1,-1] 0; then
+ base_style=$REPLY
+ _zsh_highlight_main_highlighter_highlight_path_separators $base_style
+ highlights+=($reply)
+ fi
+ fi
+
+ highlights=($(( start_pos + $1 - 1 )) $end_pos $base_style $highlights)
+ _zsh_highlight_main_add_many_region_highlights $highlights
+}
+
+# Quote Helper Functions
+#
+# $arg is expected to be set to the current argument
+# $start_pos is expected to be set to the start of $arg in $BUFFER
+# $1 is the index in $arg which starts the quote
+# $REPLY is returned as the end of quote index in $arg
+# $reply is returned as an array of region_highlight additions
+
+# Highlight single-quoted strings
+_zsh_highlight_main_highlighter_highlight_single_quote()
+{
+ local arg1=$1 i q=\' style
+ i=$arg[(ib:arg1+1:)$q]
+ reply=()
+
+ if [[ $zsyh_user_options[rcquotes] == on ]]; then
+ while [[ $arg[i+1] == "'" ]]; do
+ reply+=($(( start_pos + i - 1 )) $(( start_pos + i + 1 )) rc-quote)
+ (( i++ ))
+ i=$arg[(ib:i+1:)$q]
+ done
+ fi
+
+ if [[ $arg[i] == "'" ]]; then
+ style=single-quoted-argument
+ else
+ # If unclosed, i points past the end
+ (( i-- ))
+ style=single-quoted-argument-unclosed
+ fi
+ reply=($(( start_pos + arg1 - 1 )) $(( start_pos + i )) $style $reply)
+ REPLY=$i
+}
+
+# Highlight special chars inside double-quoted strings
+_zsh_highlight_main_highlighter_highlight_double_quote()
+{
+ local -a breaks match mbegin mend saved_reply
+ local MATCH; integer last_break=$(( start_pos + $1 - 1 )) MBEGIN MEND
+ local i j k ret style
+ reply=()
+
+ for (( i = $1 + 1 ; i <= $#arg ; i += 1 )) ; do
+ (( j = i + start_pos - 1 ))
+ (( k = j + 1 ))
+ case "$arg[$i]" in
+ ('"') break;;
+ ('`') saved_reply=($reply)
+ _zsh_highlight_main_highlighter_highlight_backtick $i
+ (( i = REPLY ))
+ reply=($saved_reply $reply)
+ continue
+ ;;
+ ('$') style=dollar-double-quoted-argument
+ # Look for an alphanumeric parameter name.
+ if [[ ${arg:$i} =~ ^([A-Za-z_][A-Za-z0-9_]*|[0-9]+) ]] ; then
+ (( k += $#MATCH )) # highlight the parameter name
+ (( i += $#MATCH )) # skip past it
+ elif [[ ${arg:$i} =~ ^[{]([A-Za-z_][A-Za-z0-9_]*|[0-9]+)[}] ]] ; then
+ (( k += $#MATCH )) # highlight the parameter name and braces
+ (( i += $#MATCH )) # skip past it
+ elif [[ $arg[i+1] == '$' ]]; then
+ # $$ - pid
+ (( k += 1 )) # highlight both dollar signs
+ (( i += 1 )) # don't consider the second one as introducing another parameter expansion
+ elif [[ $arg[i+1] == [-#*@?] ]]; then
+ # $#, $*, $@, $?, $- - like $$ above
+ (( k += 1 )) # highlight both dollar signs
+ (( i += 1 )) # don't consider the second one as introducing another parameter expansion
+ elif [[ $arg[i+1] == $'\x28' ]]; then
+ saved_reply=($reply)
+ if [[ $arg[i+2] == $'\x28' ]] && _zsh_highlight_main_highlighter_highlight_arithmetic $i; then
+ # Arithmetic expansion
+ (( i = REPLY ))
+ reply=($saved_reply $reply)
+ continue
+ fi
+
+ breaks+=( $last_break $(( start_pos + i - 1 )) )
+ (( i += 2 ))
+ _zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,-1]
+ ret=$?
+ (( i += REPLY ))
+ last_break=$(( start_pos + i ))
+ reply=(
+ $saved_reply
+ $j $(( start_pos + i )) command-substitution-quoted
+ $j $(( j + 2 )) command-substitution-delimiter-quoted
+ $reply
+ )
+ if (( ret == 0 )); then
+ reply+=($(( start_pos + i - 1 )) $(( start_pos + i )) command-substitution-delimiter-quoted)
+ fi
+ continue
+ else
+ continue
+ fi
+ ;;
+ "\\") style=back-double-quoted-argument
+ if [[ \\\`\"\$${histchars[1]} == *$arg[$i+1]* ]]; then
+ (( k += 1 )) # Color following char too.
+ (( i += 1 )) # Skip parsing the escaped char.
+ else
+ continue
+ fi
+ ;;
+ ($histchars[1]) # ! - may be a history expansion
+ if [[ $arg[i+1] != ('='|$'\x28'|$'\x7b'|[[:blank:]]) ]]; then
+ style=history-expansion
+ else
+ continue
+ fi
+ ;;
+ *) continue ;;
+
+ esac
+ reply+=($j $k $style)
+ done
+
+ if [[ $arg[i] == '"' ]]; then
+ style=double-quoted-argument
+ else
+ # If unclosed, i points past the end
+ (( i-- ))
+ style=double-quoted-argument-unclosed
+ fi
+ (( last_break != start_pos + i )) && breaks+=( $last_break $(( start_pos + i )) )
+ saved_reply=($reply)
+ reply=()
+ for 1 2 in $breaks; do
+ (( $1 != $2 )) && reply+=($1 $2 $style)
+ done
+ reply+=($saved_reply)
+ REPLY=$i
+}
+
+# Highlight special chars inside dollar-quoted strings
+_zsh_highlight_main_highlighter_highlight_dollar_quote()
+{
+ local -a match mbegin mend
+ local MATCH; integer MBEGIN MEND
+ local i j k style
+ local AA
+ integer c
+ reply=()
+
+ for (( i = $1 + 2 ; i <= $#arg ; i += 1 )) ; do
+ (( j = i + start_pos - 1 ))
+ (( k = j + 1 ))
+ case "$arg[$i]" in
+ "'") break;;
+ "\\") style=back-dollar-quoted-argument
+ for (( c = i + 1 ; c <= $#arg ; c += 1 )); do
+ [[ "$arg[$c]" != ([0-9xXuUa-fA-F]) ]] && break
+ done
+ AA=$arg[$i+1,$c-1]
+ # Matching for HEX and OCT values like \0xA6, \xA6 or \012
+ if [[ "$AA" =~ "^(x|X)[0-9a-fA-F]{1,2}"
+ || "$AA" =~ "^[0-7]{1,3}"
+ || "$AA" =~ "^u[0-9a-fA-F]{1,4}"
+ || "$AA" =~ "^U[0-9a-fA-F]{1,8}"
+ ]]; then
+ (( k += $#MATCH ))
+ (( i += $#MATCH ))
+ else
+ if (( $#arg > $i+1 )) && [[ $arg[$i+1] == [xXuU] ]]; then
+ # \x not followed by hex digits is probably an error
+ style=unknown-token
+ fi
+ (( k += 1 )) # Color following char too.
+ (( i += 1 )) # Skip parsing the escaped char.
+ fi
+ ;;
+ *) continue ;;
+
+ esac
+ reply+=($j $k $style)
+ done
+
+ if [[ $arg[i] == "'" ]]; then
+ style=dollar-quoted-argument
+ else
+ # If unclosed, i points past the end
+ (( i-- ))
+ style=dollar-quoted-argument-unclosed
+ fi
+ reply=($(( start_pos + $1 - 1 )) $(( start_pos + i )) $style $reply)
+ REPLY=$i
+}
+
+# Highlight backtick substitutions
+_zsh_highlight_main_highlighter_highlight_backtick()
+{
+ # buf is the contents of the backticks with a layer of backslashes removed.
+ # last is the index of arg for the start of the string to be copied into buf.
+ # It is either one past the beginning backtick or one past the last backslash.
+ # offset is a count of consumed \ (the delta between buf and arg).
+ # offsets is an array indexed by buf offset of when the delta between buf and arg changes.
+ # It is sparse, so search backwards to the last value
+ local buf highlight style=back-quoted-argument-unclosed style_end
+ local -i arg1=$1 end_ i=$1 last offset=0 start subshell_has_end=0
+ local -a highlight_zone highlights offsets
+ reply=()
+
+ last=$(( arg1 + 1 ))
+ # Remove one layer of backslashes and find the end
+ while i=$arg[(ib:i+1:)[\\\\\`]]; do # find the next \ or `
+ if (( i > $#arg )); then
+ buf=$buf$arg[last,i]
+ offsets[i-arg1-offset]='' # So we never index past the end
+ (( i-- ))
+ subshell_has_end=$(( has_end && (start_pos + i == len) ))
+ break
+ fi
+
+ if [[ $arg[i] == '\' ]]; then
+ (( i++ ))
+ # POSIX XCU 2.6.3
+ if [[ $arg[i] == ('$'|'`'|'\') ]]; then
+ buf=$buf$arg[last,i-2]
+ (( offset++ ))
+ # offsets is relative to buf, so adjust by -arg1
+ offsets[i-arg1-offset]=$offset
+ else
+ buf=$buf$arg[last,i-1]
+ fi
+ else # it's an unquoted ` and this is the end
+ style=back-quoted-argument
+ style_end=back-quoted-argument-delimiter
+ buf=$buf$arg[last,i-1]
+ offsets[i-arg1-offset]='' # So we never index past the end
+ break
+ fi
+ last=$i
+ done
+
+ _zsh_highlight_main_highlighter_highlight_list 0 '' $subshell_has_end $buf
+
+ # Munge the reply to account for removed backslashes
+ for start end_ highlight in $reply; do
+ start=$(( start_pos + arg1 + start + offsets[(Rb:start:)?*] ))
+ end_=$(( start_pos + arg1 + end_ + offsets[(Rb:end_:)?*] ))
+ highlights+=($start $end_ $highlight)
+ if [[ $highlight == back-quoted-argument-unclosed && $style == back-quoted-argument ]]; then
+ # An inner backtick command substitution is unclosed, but this level is closed
+ style_end=unknown-token
+ fi
+ done
+
+ reply=(
+ $(( start_pos + arg1 - 1 )) $(( start_pos + i )) $style
+ $(( start_pos + arg1 - 1 )) $(( start_pos + arg1 )) back-quoted-argument-delimiter
+ $highlights
+ )
+ if (( $#style_end )); then
+ reply+=($(( start_pos + i - 1)) $(( start_pos + i )) $style_end)
+ fi
+ REPLY=$i
+}
+
+# Highlight special chars inside arithmetic expansions
+_zsh_highlight_main_highlighter_highlight_arithmetic()
+{
+ local -a saved_reply
+ local style
+ integer i j k paren_depth ret
+ reply=()
+
+ for (( i = $1 + 3 ; i <= end_pos - start_pos ; i += 1 )) ; do
+ (( j = i + start_pos - 1 ))
+ (( k = j + 1 ))
+ case "$arg[$i]" in
+ [\'\"\\@{}])
+ style=unknown-token
+ ;;
+ '(')
+ (( paren_depth++ ))
+ continue
+ ;;
+ ')')
+ if (( paren_depth )); then
+ (( paren_depth-- ))
+ continue
+ fi
+ [[ $arg[i+1] == ')' ]] && { (( i++ )); break; }
+ # Special case ) at the end of the buffer to avoid flashing command substitution for a character
+ (( has_end && (len == k) )) && break
+ # This is a single paren and there are no open parens, so this isn't an arithmetic expansion
+ return 1
+ ;;
+ '`')
+ saved_reply=($reply)
+ _zsh_highlight_main_highlighter_highlight_backtick $i
+ (( i = REPLY ))
+ reply=($saved_reply $reply)
+ continue
+ ;;
+ '$' )
+ if [[ $arg[i+1] == $'\x28' ]]; then
+ saved_reply=($reply)
+ if [[ $arg[i+2] == $'\x28' ]] && _zsh_highlight_main_highlighter_highlight_arithmetic $i; then
+ # Arithmetic expansion
+ (( i = REPLY ))
+ reply=($saved_reply $reply)
+ continue
+ fi
+
+ (( i += 2 ))
+ _zsh_highlight_main_highlighter_highlight_list $(( start_pos + i - 1 )) S $has_end $arg[i,end_pos]
+ ret=$?
+ (( i += REPLY ))
+ reply=(
+ $saved_reply
+ $j $(( start_pos + i )) command-substitution-quoted
+ $j $(( j + 2 )) command-substitution-delimiter-quoted
+ $reply
+ )
+ if (( ret == 0 )); then
+ reply+=($(( start_pos + i - 1 )) $(( start_pos + i )) command-substitution-delimiter)
+ fi
+ continue
+ else
+ continue
+ fi
+ ;;
+ ($histchars[1]) # ! - may be a history expansion
+ if [[ $arg[i+1] != ('='|$'\x28'|$'\x7b'|[[:blank:]]) ]]; then
+ style=history-expansion
+ else
+ continue
+ fi
+ ;;
+ *)
+ continue
+ ;;
+
+ esac
+ reply+=($j $k $style)
+ done
+
+ if [[ $arg[i] != ')' ]]; then
+ # If unclosed, i points past the end
+ (( i-- ))
+ fi
+ style=arithmetic-expansion
+ reply=($(( start_pos + $1 - 1)) $(( start_pos + i )) arithmetic-expansion $reply)
+ REPLY=$i
+}
+
+
+# Called with a single positional argument.
+# Perform filename expansion (tilde expansion) on the argument and set $REPLY to the expanded value.
+#
+# Does not perform filename generation (globbing).
+_zsh_highlight_main_highlighter_expand_path()
+{
+ (( $# == 1 )) || print -r -- >&2 "zsh-syntax-highlighting: BUG: _zsh_highlight_main_highlighter_expand_path: called without argument"
+
+ # The $~1 syntax normally performs filename generation, but not when it's on the right-hand side of ${x:=y}.
+ setopt localoptions nonomatch
+ unset REPLY
+ : ${REPLY:=${(Q)${~1}}}
+}
+
+# -------------------------------------------------------------------------------------------------
+# Main highlighter initialization
+# -------------------------------------------------------------------------------------------------
+
+_zsh_highlight_main__precmd_hook() {
+ # Unset the WARN_NESTED_VAR option, taking care not to error if the option
+ # doesn't exist (zsh older than zsh-5.3.1-test-2).
+ setopt localoptions
+ if eval '[[ -o warnnestedvar ]]' 2>/dev/null; then
+ unsetopt warnnestedvar
+ fi
+
+ _zsh_highlight_main__command_type_cache=()
+}
+
+autoload -Uz add-zsh-hook
+if add-zsh-hook precmd _zsh_highlight_main__precmd_hook 2>/dev/null; then
+ # Initialize command type cache
+ typeset -gA _zsh_highlight_main__command_type_cache
+else
+ print -r -- >&2 'zsh-syntax-highlighting: Failed to load add-zsh-hook. Some speed optimizations will not be used.'
+ # Make sure the cache is unset
+ unset _zsh_highlight_main__command_type_cache
+fi
+typeset -ga ZSH_HIGHLIGHT_DIRS_BLACKLIST
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position1.zsh
new file mode 100644
index 00000000..cfc12a5f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position1.zsh
@@ -0,0 +1,35 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'/'
+
+expected_region_highlight=(
+ '1 1 path_prefix' # /
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position1b.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position1b.zsh
new file mode 100644
index 00000000..88fe60c9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position1b.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt autocd
+BUFFER=$'/'
+
+expected_region_highlight=(
+ '1 1 autodirectory' # /
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position2.zsh
new file mode 100644
index 00000000..5033d2c4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position2.zsh
@@ -0,0 +1,35 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'/bi'
+
+expected_region_highlight=(
+ '1 3 path_prefix' # /bi
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position3.zsh
new file mode 100644
index 00000000..415e3167
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position3.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'/bin; /bin'
+
+expected_region_highlight=(
+ '1 4 unknown-token' # /bin (in middle)
+ '5 5 commandseparator' # ;
+ '7 10 path_prefix' # /bin (at end)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position3b.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position3b.zsh
new file mode 100644
index 00000000..0e65c98a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position3b.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt autocd
+BUFFER=$'/bin; /bin'
+
+expected_region_highlight=(
+ '1 4 autodirectory' # /bin (in middle)
+ '5 5 commandseparator' # ;
+ '7 10 autodirectory' # /bin (at end)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position4.zsh
new file mode 100644
index 00000000..9e935bf1
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position4.zsh
@@ -0,0 +1,35 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'/bin/s'
+
+expected_region_highlight=(
+ '1 6 path_prefix' # /bin/s
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position5.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position5.zsh
new file mode 100644
index 00000000..e428b1a0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/abspath-in-command-position5.zsh
@@ -0,0 +1,35 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'/bin/sh'
+
+expected_region_highlight=(
+ '1 7 command' # /bin/sh
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-assignment1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-assignment1.zsh
new file mode 100644
index 00000000..0c101c8e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-assignment1.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Issue #263 (more-pathological case): aliases[x=y]=z works; the ${(z)} splitter considers
+# that a single word; but it's not looked up as an alias. Hence, highlight it as an error.
+aliases[x=y]='lorem ipsum dolor sit amet'
+BUFFER='x=y ls'
+
+expected_region_highlight=(
+ "1 3 unknown-token" # x=y
+ "5 6 default" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-basic.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-basic.zsh
new file mode 100644
index 00000000..7af8b7cd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-basic.zsh
@@ -0,0 +1,35 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias foo="echo hello world"
+BUFFER="foo"
+
+expected_region_highlight+=(
+ "1 3 alias" # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-brackets.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-brackets.zsh
new file mode 100644
index 00000000..ede6c9a9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-brackets.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2021 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Have to use cat here as it must be a command that exists.
+# Otherwise, the test would fail with the first token being recognized
+# as an "unknown-token".
+alias ]=cat
+
+BUFFER='] /'
+
+expected_region_highlight=(
+ '1 1 alias' # ]
+ '3 3 path' # /
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-command-substitution.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-command-substitution.zsh
new file mode 100644
index 00000000..a7b77dfa
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-command-substitution.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Alias must be at least 4 characters to test the regression
+# cf. 139ea2b189819c43cc251825981c116959b15cc3
+alias foobar='echo "$(echo foobar)"'
+BUFFER='foobar'
+
+expected_region_highlight=(
+ "1 6 alias" # foobar
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-comment1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-comment1.zsh
new file mode 100644
index 00000000..bae7ef6f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-comment1.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# see alias-comment2.zsh and comment-followed.zsh
+setopt interactivecomments
+alias x=$'# foo\npwd'
+BUFFER='x'
+
+expected_region_highlight=(
+ '1 1 alias' # x
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-comment2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-comment2.zsh
new file mode 100644
index 00000000..5a498229
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-comment2.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# see alias-comment1.zsh
+setopt NO_interactivecomments
+alias x=$'# foo\npwd'
+BUFFER='x'
+
+expected_region_highlight=(
+ '1 1 unknown-token' # x (#)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-complex.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-complex.zsh
new file mode 100644
index 00000000..5ad7c0a9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-complex.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias x='echo && ls; >'
+
+BUFFER='x file echo'
+
+expected_region_highlight=(
+ '1 1 alias' # x
+ '3 6 default' # file
+ '8 11 builtin' # echo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-empty.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-empty.zsh
new file mode 100644
index 00000000..535fccc9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-empty.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias x=''
+
+BUFFER='x echo foo'
+
+expected_region_highlight=(
+ '1 1 alias' # x
+ '3 6 builtin' # echo
+ '8 10 default' # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-eponymous1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-eponymous1.zsh
new file mode 100644
index 00000000..2642e14f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-eponymous1.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias ls='command ls'
+
+BUFFER='ls'
+
+expected_region_highlight=(
+ "1 2 alias" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-eponymous2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-eponymous2.zsh
new file mode 100644
index 00000000..dcd85653
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-eponymous2.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias ls=tmp tmp='command ls'
+
+BUFFER='ls'
+
+expected_region_highlight=(
+ "1 2 alias" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-in-cmdsubst.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-in-cmdsubst.zsh
new file mode 100644
index 00000000..b3cf777a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-in-cmdsubst.zsh
@@ -0,0 +1,43 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias p='print -r --'
+
+BUFFER=$'s=$(p foo)'
+
+expected_region_highlight=(
+ '1 10 assign' # s=$(p foo)
+ '3 10 default' # $(p foo)
+ '3 10 command-substitution-unquoted' # $(p foo)
+ '3 4 command-substitution-delimiter-unquoted' # $(
+ '5 5 alias' # p
+ '7 9 default' # foo
+ '10 10 command-substitution-delimiter-unquoted' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-loop.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-loop.zsh
new file mode 100644
index 00000000..83992dbf
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-loop.zsh
@@ -0,0 +1,44 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+function b() {} # beware of ALIAS_FUNC_DEF
+alias a=b b=c c=b
+
+BUFFER='a foo; :'
+
+expected_region_highlight=(
+ # An alias is ineligible for expansion whilst it's being expanded.
+ # Therefore, the "b" in the expansion of the alias "c" is not considered
+ # as an alias.
+ '1 1 alias' # a
+ '3 5 default' # foo
+ '6 6 commandseparator' # ;
+ '8 8 builtin' # :
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-loop2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-loop2.zsh
new file mode 100644
index 00000000..29e04ace
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-loop2.zsh
@@ -0,0 +1,35 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias ls="ls"
+BUFFER="ls"
+
+expected_region_highlight+=(
+ "1 2 alias" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-nested-precommand.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-nested-precommand.zsh
new file mode 100644
index 00000000..6d4172bc
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-nested-precommand.zsh
@@ -0,0 +1,43 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=b b=sudo
+sudo(){}
+
+BUFFER='a -u phy1729 echo; :'
+
+expected_region_highlight=(
+ '1 1 alias' # a
+ '3 4 single-hyphen-option' # -u
+ '6 12 default' # phy1729
+ '14 17 builtin' # echo
+ '18 18 commandseparator' # ;
+ '20 20 builtin' # :
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-nested.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-nested.zsh
new file mode 100644
index 00000000..b24b4967
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-nested.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=b b=:
+
+BUFFER='a foo; :'
+
+expected_region_highlight=(
+ '1 1 alias' # a
+ '3 5 default' # foo
+ '6 6 commandseparator' # ;
+ '8 8 builtin' # :
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-parameter.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-parameter.zsh
new file mode 100644
index 00000000..21bc6b32
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-parameter.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias '$foo'='echo alias'
+local foo; foo=(echo param)
+
+BUFFER='$foo'
+
+expected_region_highlight=(
+ '1 4 alias' # $foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument1.zsh
new file mode 100644
index 00000000..2d1f35c6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument1.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# See also param-precommand-option-argument1.zsh
+alias sudo_u='sudo -u'
+sudo(){}
+
+BUFFER='sudo_u phy1729 echo foo'
+
+expected_region_highlight=(
+ '1 6 alias' # sudo_u
+ '8 14 default' # phy1729
+ '17 19 command "issue #540"' # echo (not builtin)
+ '21 23 default' # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument2.zsh
new file mode 100644
index 00000000..fbc6eec7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument2.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias sudo_b='sudo -b'
+alias sudo_b_u='sudo_b -u'
+sudo(){}
+
+BUFFER='sudo_b_u phy1729 echo foo'
+
+expected_region_highlight=(
+ '1 8 alias' # sudo_b_u
+ '10 16 default' # phy1729
+ '18 21 command "issue #540"' # echo (not builtin)
+ '23 25 default' # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument3.zsh
new file mode 100644
index 00000000..373f12b6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument3.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# See also param-precommand-option-argument3.zsh
+alias sudo_u='sudo -u'
+sudo(){}
+
+BUFFER='sudo_u phy1729 ls foo'
+
+expected_region_highlight=(
+ '1 6 alias' # sudo_u
+ '8 14 default' # phy1729
+ '16 17 command' # ls
+ '19 21 default' # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument4.zsh
new file mode 100644
index 00000000..d47dccb8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-precommand-option-argument4.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias sudo_b='sudo -b'
+alias sudo_b_u='sudo_b -u'
+sudo(){}
+
+BUFFER='sudo_b_u phy1729 ls foo'
+
+expected_region_highlight=(
+ '1 8 alias' # sudo_b_u
+ '10 16 default' # phy1729
+ '18 19 command' # ls
+ '21 23 default' # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-quoted.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-quoted.zsh
new file mode 100644
index 00000000..e42e2f0a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-quoted.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) YYYY zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=: ls='ls -l'
+BUFFER='"a" foo; \ls'
+
+expected_region_highlight=(
+ '1 3 unknown-token' # "a"
+ '5 7 default' # foo
+ '8 8 commandseparator' # ;
+ '10 12 command' # \ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-redirect.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-redirect.zsh
new file mode 100644
index 00000000..acc3dcbe
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-redirect.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias x=\>
+BUFFER='x foo echo bar'
+
+expected_region_highlight=(
+ '1 1 alias' # x
+ '3 5 default' # foo
+ '7 10 builtin' # echo
+ '12 14 default' # bar
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse1.zsh
new file mode 100644
index 00000000..1fd61a0b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse1.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=: b='a | a'
+
+BUFFER='b | b'
+
+expected_region_highlight=(
+ '1 1 alias' # b
+ '3 3 commandseparator' # |
+ '5 5 alias' # b
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse2.zsh
new file mode 100644
index 00000000..37251fb9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse2.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=: b='a && a'
+
+BUFFER='b && b'
+
+expected_region_highlight=(
+ '1 1 alias' # b
+ '3 4 commandseparator' # &&
+ '6 6 alias' # b
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse3.zsh
new file mode 100644
index 00000000..5d7150a1
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse3.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=: b='a; a'
+
+BUFFER='b; b'
+
+expected_region_highlight=(
+ '1 1 alias' # b
+ '2 2 commandseparator' # ;
+ '4 4 alias' # b
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse4.zsh
new file mode 100644
index 00000000..7ad7038c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse4.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=: b='a $(a)'
+
+BUFFER='b $(b)'
+
+expected_region_highlight=(
+ '1 1 alias' # b
+ '3 6 default' # $(b)
+ '3 6 command-substitution-unquoted' # $(b)
+ '3 4 command-substitution-delimiter-unquoted' # $(
+ '5 5 alias' # b
+ '6 6 command-substitution-delimiter-unquoted' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse5.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse5.zsh
new file mode 100644
index 00000000..881401b2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-reuse5.zsh
@@ -0,0 +1,43 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=: b='a < <(a)'
+
+BUFFER='b < <(b)'
+
+expected_region_highlight=(
+ '1 1 alias' # b
+ '3 3 redirection' # <
+ '5 8 default' # <(b)
+ '5 8 process-substitution' # <(b)
+ '5 6 process-substitution-delimiter' # <(
+ '7 7 alias' # b
+ '8 8 process-substitution-delimiter' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-self.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-self.zsh
new file mode 100644
index 00000000..c6f12b1a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-self.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias echo='echo foo'
+
+BUFFER='echo bar'
+
+expected_region_highlight=(
+ '1 4 alias' # echo
+ '6 8 default' # bar
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-self2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-self2.zsh
new file mode 100644
index 00000000..fd6ae03f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-self2.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias cat='cat | cat'
+
+BUFFER='cat'
+
+expected_region_highlight=(
+ '1 3 alias' # cat
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-to-dir.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-to-dir.zsh
new file mode 100644
index 00000000..30390d42
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-to-dir.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias x=/
+BUFFER=$'x'
+
+expected_region_highlight=(
+ '1 1 unknown-token' # x (/)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-to-dir1b.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-to-dir1b.zsh
new file mode 100644
index 00000000..62ec5213
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-to-dir1b.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt autocd
+alias x=/
+BUFFER=$'x'
+
+expected_region_highlight=(
+ '1 1 alias' # x
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-unknown-token1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-unknown-token1.zsh
new file mode 100644
index 00000000..9c996bfe
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-unknown-token1.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=b b=foo
+
+BUFFER='a '
+
+expected_region_highlight=(
+ '1 1 unknown-token' # a
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-unknown-token2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-unknown-token2.zsh
new file mode 100644
index 00000000..ab9facd6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias-unknown-token2.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a='() { ls "$@" ; foo }'
+
+BUFFER='a '
+
+expected_region_highlight=(
+ '1 1 unknown-token' # a
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias.zsh
new file mode 100644
index 00000000..4cafa804
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/alias.zsh
@@ -0,0 +1,53 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias alias1="ls"
+alias -s alias2="echo"
+function alias1() {} # to check that it's highlighted as an alias, not as a function
+
+BUFFER='x.alias2; alias1; alias2'
+
+# Set expected_region_highlight as a function of zsh version.
+#
+# Highlight of suffix alias requires zsh-5.1.1 or newer; see issue #126,
+# and commit 36403 to zsh itself. Therefore, check if the requisite zsh
+# functionality is present, and skip verifying suffix-alias highlighting
+# if it isn't.
+expected_region_highlight=()
+if zmodload -e zsh/parameter || [[ "$(type -w x.alias2)" == *suffix* ]]; then
+ expected_region_highlight+=(
+ "1 8 suffix-alias" # x.alias2
+ )
+fi
+expected_region_highlight+=(
+ "9 9 commandseparator" # ;
+ "11 16 alias" # alias1
+ "17 17 commandseparator" # ;
+ "19 24 unknown-token" # alias2
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always1.zsh
new file mode 100644
index 00000000..ae40a72f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always1.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='{ ls } always { pwd }'
+
+expected_region_highlight=(
+ '1 1 reserved-word' # {
+ '3 4 command' # ls
+ '6 6 reserved-word' # }
+ '8 13 reserved-word' # always
+ '15 15 reserved-word' # {
+ '17 19 builtin' # pwd
+ '21 21 reserved-word' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always2.zsh
new file mode 100644
index 00000000..991137c2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always2.zsh
@@ -0,0 +1,43 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'{\nls\n} always { pwd }'
+
+expected_region_highlight=(
+ '1 1 reserved-word' # {
+ '2 2 commandseparator' # \n
+ '3 4 command' # ls
+ '5 5 commandseparator' # \n
+ '6 6 reserved-word' # }
+ '8 13 reserved-word' # always
+ '15 15 reserved-word' # {
+ '17 19 builtin' # pwd
+ '21 21 reserved-word' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always3.zsh
new file mode 100644
index 00000000..d41beeb5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/always3.zsh
@@ -0,0 +1,43 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt ignorebraces
+BUFFER='echo { foo } always { bar }'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 6 default' # {
+ '8 10 default' # foo
+ '12 12 default' # }
+ '14 19 default' # always
+ '21 21 default' # {
+ '23 25 default' # bar
+ '27 27 default' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/anonymous-function.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/anonymous-function.zsh
new file mode 100644
index 00000000..9d67fb1d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/anonymous-function.zsh
@@ -0,0 +1,44 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='() echo hello; () { echo world } "argument"'
+
+expected_region_highlight=(
+ "1 2 reserved-word" # ()
+ "4 7 builtin" # echo
+ "9 13 default" # hello
+ "14 14 commandseparator" # ;
+ "16 17 reserved-word" # ()
+ "19 19 reserved-word" # {
+ "21 24 builtin" # echo
+ "26 30 default" # world
+ "32 32 reserved-word" # }
+ "34 43 default" # "argument"
+ "34 43 double-quoted-argument" # "argument"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arg0-colon.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arg0-colon.zsh
new file mode 100644
index 00000000..8955bd28
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arg0-colon.zsh
@@ -0,0 +1,35 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=''\''x: /'
+
+expected_region_highlight=(
+ '1 5 unknown-token' # \'x: /
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith-cmdsubst-mess.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith-cmdsubst-mess.zsh
new file mode 100644
index 00000000..82268ac1
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith-cmdsubst-mess.zsh
@@ -0,0 +1,46 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $((ls); (ls))'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 15 default' # $((ls); (ls))
+ '3 15 command-substitution-unquoted' # $((ls); (ls))
+ '3 4 command-substitution-delimiter-unquoted' # $(
+ '5 5 reserved-word' # (
+ '6 7 command' # ls
+ '8 8 reserved-word' # )
+ '9 9 commandseparator' # ;
+ '11 11 reserved-word' # (
+ '12 13 command' # ls
+ '14 14 reserved-word' # )
+ '15 15 command-substitution-delimiter-unquoted' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith1.zsh
new file mode 100644
index 00000000..0462f738
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith1.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(( 6 * 9 ))'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 14 default' # $(( 6 * 9 ))
+ '3 14 arithmetic-expansion' # $(( 6 * 9 ))
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith2.zsh
new file mode 100644
index 00000000..af981d7c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arith2.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': "$(( 6 * 9 ))"'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 16 default' # "$(( 6 * 9 ))"
+ '3 16 double-quoted-argument' # "$(( 6 * 9 ))"
+ '4 15 arithmetic-expansion' # $(( 6 * 9 ))
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-command-substitution.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-command-substitution.zsh
new file mode 100644
index 00000000..07db0fb2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-command-substitution.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(( $(echo 2) + 2 ))'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 22 default' # $(( $(echo 2) + 2 ))
+ '3 22 arithmetic-expansion' # $(( $(echo 2) + 2 ))
+ '7 15 command-substitution-quoted' # $(echo 2)
+ '7 8 command-substitution-delimiter-quoted' # $(
+ '9 12 builtin' # echo
+ '14 14 default' # 2
+ '15 15 command-substitution-delimiter' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-doubled-parens.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-doubled-parens.zsh
new file mode 100644
index 00000000..d582d67c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-doubled-parens.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(( ((42)) ))'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 15 default' # $(( ((42)) ))
+ '3 15 arithmetic-expansion' # $(( ((42)) ))
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-empty.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-empty.zsh
new file mode 100644
index 00000000..bd759966
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-empty.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': "foo"$(())"bar"'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 17 default' # "foo"$(())"bar"
+ '3 7 double-quoted-argument' # "foo"
+ '8 12 arithmetic-expansion' # $(())
+ '13 17 double-quoted-argument' # "bar"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-evaluation.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-evaluation.zsh
new file mode 100644
index 00000000..e0eb6e75
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-evaluation.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Must be at command word, since the word following 'if' isn't currently considered
+# a command word (issue #207).
+#
+# An opening '((' without matching '))' is highlighted correctly under zsh-5.1.1-52-g4bed2cf
+# or newer, only (issue #188).
+BUFFER='(( x == 42 ))'
+
+expected_region_highlight=(
+ "1 2 reserved-word" # ((
+ "12 13 reserved-word" # ))
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-hist-expn.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-hist-expn.zsh
new file mode 100644
index 00000000..79af7233
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-hist-expn.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(( \!\! ))'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 11 default' # $(( !! ))
+ '3 11 arithmetic-expansion' # $(( !! ))
+ '7 8 history-expansion "issue #713"' # !!
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-invalid-chars.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-invalid-chars.zsh
new file mode 100644
index 00000000..9ace4383
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-invalid-chars.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(( 0 * 1\'\'000 ))'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 19 default' # $(( 0 * 1\'\'000 ))
+ '3 19 arithmetic-expansion' # $(( 0 * 1\'\'000 ))
+ '12 12 unknown-token' # \'
+ '13 13 unknown-token' # \'
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-multiplication.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-multiplication.zsh
new file mode 100644
index 00000000..65df0c9f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-multiplication.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': foo*$(( 42 * 1729 ))*bar'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 26 default' # foo*$(( 42 * 1729 ))*bar
+ '6 6 globbing' # *
+ '7 22 arithmetic-expansion' # $(( 42 * 1729 ))
+ '23 23 globbing' # *
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-nested.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-nested.zsh
new file mode 100644
index 00000000..d734cd34
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-nested.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(( $(( 1 + 2 )) * 3 ))'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 25 default' # $(( $(( 1 + 2 )) * 3 ))
+ '3 25 arithmetic-expansion' # $(( $(( 1 + 2 )) * 3 ))
+ '7 18 arithmetic-expansion' # $(( 1 + 2 ))
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-quoted.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-quoted.zsh
new file mode 100644
index 00000000..917ddf78
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-quoted.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': "$(( 1 + 1 ))"'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 16 default' # "$(( 1 + 1 ))"
+ '3 16 double-quoted-argument' # "$(( 1 + 1 ))"
+ '4 15 arithmetic-expansion' # $(( 1 + 1 ))
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-unclosed.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-unclosed.zsh
new file mode 100644
index 00000000..aa4eac7a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-unclosed.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(( 1'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 7 default' # $(( 1
+ '3 7 arithmetic-expansion' # $(( 1
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-unfinished.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-unfinished.zsh
new file mode 100644
index 00000000..916c3dad
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/arithmetic-unfinished.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(( 1729 )'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 12 default' # $(( 1729 )
+ '3 12 arithmetic-expansion' # $(( 1729 )
+)
+
+if [[ ${(z):-'$('} == '$( ' ]]; then # ignore zsh 5.0.8 bug
+ expected_region_highlight[2]='3 13 default' # $(( 1729 )
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep1.zsh
new file mode 100644
index 00000000..2fd55c03
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep1.zsh
@@ -0,0 +1,45 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'a=( foo | bar )'
+bar(){}
+
+expected_region_highlight=(
+ '1 3 assign' # a=(
+ '3 3 reserved-word' # (
+ '5 7 default' # foo
+ '9 9 unknown-token' # |
+ # zsh reports a parse error at this point. Nevertheless, we test how we
+ # highlight the remainder of $BUFFER. Currently we recover by treating the pipe
+ # as a command separator. That's not the only reasonable behaviour, though; if
+ # we change the behaviour, we should adjust the following expectations accordingly.
+ '11 13 function' # bar
+ '15 15 unknown-token' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep2.zsh
new file mode 100644
index 00000000..0bda6761
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep2.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'a=( foo ; bar )'
+
+expected_region_highlight=(
+ '1 3 assign' # a=(
+ '3 3 reserved-word' # (
+ '5 7 default' # foo
+ '9 9 unknown-token' # ; (not commandseparator; see highlighter source code)
+ '11 13 default' # bar
+ '15 15 assign' # )
+ '15 15 reserved-word' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep3.zsh
new file mode 100644
index 00000000..b4b3687c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/array-cmdsep3.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'a=( foo \n bar )'
+
+expected_region_highlight=(
+ '1 3 assign' # a=(
+ '3 3 reserved-word' # (
+ '5 7 default' # foo
+ '9 9 commandseparator' # \n
+ '11 13 default' # bar
+ '15 15 assign' # )
+ '15 15 reserved-word' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-append.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-append.zsh
new file mode 100644
index 00000000..feb68e53
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-append.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='a+=(lorem ipsum)'
+
+expected_region_highlight=(
+ "1 4 assign" # a+=(
+ "4 4 reserved-word" # (
+ "5 9 default" # lorem
+ "11 15 default" # ipsum
+ "16 16 assign" # )
+ "16 16 reserved-word" # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-argv.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-argv.zsh
new file mode 100644
index 00000000..ec5acc24
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-argv.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+touch foo
+BUFFER='42=foo 43+=bar'
+
+expected_region_highlight=(
+ "1 6 assign" # 42=foo
+ "4 6 path" # foo
+ "8 14 assign" # 43+=bar
+ "12 14 default" # bar
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array.zsh
new file mode 100644
index 00000000..ef0a6669
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array.zsh
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='(A=(hello world))'
+
+expected_region_highlight=(
+ "1 1 reserved-word" # (
+ "2 4 assign" # A=(
+ "4 4 reserved-word" # (
+ "5 9 default" # hello
+ "11 15 default" # world
+ "16 16 assign" # )
+ "16 16 reserved-word" # )
+ "17 17 reserved-word" # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array2.zsh
new file mode 100644
index 00000000..2d487211
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array2.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='A=(hello world) ls'
+
+expected_region_highlight=(
+ "1 3 assign" # A=(
+ "3 3 reserved-word" # (
+ "4 8 default" # hello
+ "10 14 default" # world
+ "15 15 assign" # )
+ "15 15 reserved-word" # )
+ "17 18 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array3.zsh
new file mode 100644
index 00000000..5eb645e6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-array3.zsh
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='A=(hello world) b=42'
+
+expected_region_highlight=(
+ "1 3 assign" # A=(
+ "3 3 reserved-word" # (
+ "4 8 default" # hello
+ "10 14 default" # world
+ "15 15 assign" # )
+ "15 15 reserved-word" # )
+ "17 20 assign" # b=42
+ "19 20 default" # 42
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-invalid-command.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-invalid-command.zsh
new file mode 100644
index 00000000..557327e8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-invalid-command.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'x=y nosuchcommand'
+
+expected_region_highlight=(
+ '1 3 assign' # x=y
+ '3 3 default' # y
+ '5 17 unknown-token' # nosuchcommand
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-not-array.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-not-array.zsh
new file mode 100644
index 00000000..651ab80a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-not-array.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='a=foo( bar ) :'
+
+expected_region_highlight=(
+ '1 12 assign' # a=foo( bar )
+ '3 12 default' # foo( bar )
+ '14 14 builtin' # :
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-not-array2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-not-array2.zsh
new file mode 100644
index 00000000..dfda106e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-not-array2.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='a=foo\( :'
+
+expected_region_highlight=(
+ '1 7 assign' # a=foo\(
+ '3 7 default' # foo\(
+ '9 9 builtin' # :
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-quoted-cmdsubst.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-quoted-cmdsubst.zsh
new file mode 100644
index 00000000..d4a62dfa
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-quoted-cmdsubst.zsh
@@ -0,0 +1,45 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'x="$(ls x y z)"'
+
+expected_region_highlight=(
+ '1 15 assign' # x="$(ls x y z)"
+ '3 15 default' # "$(ls x y z)"
+ '3 3 double-quoted-argument' # "
+ '15 15 double-quoted-argument' # "
+ '4 14 command-substitution-quoted' # $(ls x y z)
+ '4 5 command-substitution-delimiter-quoted' # $(
+ '6 7 command' # ls
+ '9 9 default' # x
+ '11 11 default' # y
+ '13 13 default' # z
+ '14 14 command-substitution-delimiter-quoted' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-semicolon.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-semicolon.zsh
new file mode 100644
index 00000000..f748c94e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-semicolon.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='A=1; echo hello world'
+
+expected_region_highlight=(
+ "1 3 assign" # A=1
+ "3 3 default" # 1
+ "4 4 commandseparator" # ;
+ "6 9 builtin" # echo
+ "11 15 default" # hello
+ "17 21 default" # world
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-subshell.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-subshell.zsh
new file mode 100644
index 00000000..20228893
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-subshell.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='(A=1)'
+
+expected_region_highlight=(
+ "1 1 reserved-word" # (
+ "2 4 assign" # A=1
+ "4 4 default" # 1
+ "5 5 reserved-word" # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-value-quote1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-value-quote1.zsh
new file mode 100644
index 00000000..b6d04fe0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-value-quote1.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'s="foo\'bar"'
+
+expected_region_highlight=(
+ '1 11 assign' # s="foo'bar"
+ '3 11 default' # "foo'bar"
+ '3 11 double-quoted-argument' # "foo'bar"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-value-quote2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-value-quote2.zsh
new file mode 100644
index 00000000..3c5f93b4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign-value-quote2.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'s="foo \'\' bar"'
+
+expected_region_highlight=(
+ '1 14 assign' # s="foo '' bar"
+ '3 14 default' # "foo '' bar"
+ '3 14 double-quoted-argument' # "foo '' bar"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign.zsh
new file mode 100644
index 00000000..c6e8532d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assign.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='A=1 b=("foo" bar)'
+
+expected_region_highlight=(
+ "1 3 assign" # A=1
+ "3 3 default" # 1
+ "5 7 assign" # b=(
+ "7 7 reserved-word" # (
+ "8 12 default" # "foo"
+ "8 12 double-quoted-argument" # "foo"
+ "14 16 default" # bar
+ "17 17 assign" # )
+ "17 17 reserved-word" # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword1.zsh
new file mode 100644
index 00000000..b271d4aa
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword1.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'foo=bar { :; }'
+
+expected_region_highlight=(
+ '1 7 assign' # foo=bar
+ '5 7 default' # bar
+ '9 9 unknown-token' # {
+ '11 11 builtin' # :
+ '12 12 commandseparator' # ;
+ '14 14 reserved-word' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword2.zsh
new file mode 100644
index 00000000..247e41eb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword2.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'foo=bar ( :; )'
+
+expected_region_highlight=(
+ '1 7 assign' # foo=bar
+ '5 7 default' # bar
+ '9 9 unknown-token' # (
+ '11 11 builtin' # :
+ '12 12 commandseparator' # ;
+ '14 14 unknown-token' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword3.zsh
new file mode 100644
index 00000000..52041895
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword3.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'foo=bar (( foo ))'
+
+expected_region_highlight=(
+ '1 7 assign' # foo=bar
+ '5 7 default' # bar
+ '9 17 unknown-token' # (( foo ))
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword4.zsh
new file mode 100644
index 00000000..cc3d5231
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword4.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'foo=bar [[ -n foo ]]'
+
+expected_region_highlight=(
+ '1 7 assign' # foo=bar
+ '5 7 default' # bar
+ '9 10 unknown-token' # [[
+ '12 13 single-hyphen-option' # -n
+ '15 17 default' # foo
+ '19 20 reserved-word' # ]]
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword5.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword5.zsh
new file mode 100644
index 00000000..33f1ed14
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-before-resword5.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'foo=bar \! :'
+
+expected_region_highlight=(
+ '1 7 assign' # foo=bar
+ '5 7 default' # bar
+ '9 9 unknown-token' # \!
+ '11 11 builtin' # :
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-quoted.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-quoted.zsh
new file mode 100644
index 00000000..18638adb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/assignment-quoted.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'1="foo"'
+
+expected_region_highlight=(
+ '1 7 assign' # 1="foo"
+ '3 7 default' # "foo"
+ '3 7 double-quoted-argument' # "foo"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/back-quoted-argument.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/back-quoted-argument.zsh
new file mode 100644
index 00000000..d504a2c7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/back-quoted-argument.zsh
@@ -0,0 +1,58 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo `echo \`42\`` "is `echo equal` to" `echo 6 times 9'
+
+expected_region_highlight=(
+ "1 4 builtin" # echo
+ "6 18 default" # `echo \`42\``
+ "6 18 back-quoted-argument" # `echo \`42\``
+ "6 6 back-quoted-argument-delimiter" # `
+ "7 10 builtin" # echo
+ "12 17 default" # \`42\`
+ "12 17 back-quoted-argument" # \`42\`
+ "12 13 back-quoted-argument-delimiter" # \`
+ "14 15 unknown-token" # 42
+ "16 17 back-quoted-argument-delimiter" # \`
+ "18 18 back-quoted-argument-delimiter" # `
+ "20 39 default" # "is `echo equal` to"
+ "20 39 double-quoted-argument" # "is `echo equal` to"
+ "24 35 back-quoted-argument" # `echo equal`
+ "24 24 back-quoted-argument-delimiter" # `
+ "25 28 builtin" # echo
+ "30 34 default" # equal
+ "35 35 back-quoted-argument-delimiter" # `
+ "41 55 default" # `echo 6 times 9
+ "41 55 back-quoted-argument-unclosed" # `echo 6 times 9
+ "41 41 back-quoted-argument-delimiter" # `
+ "42 45 builtin" # echo
+ "47 47 default" # 6
+ "49 53 default" # times
+ "55 55 default" # 9
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/back-quoted-open.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/back-quoted-open.zsh
new file mode 100644
index 00000000..f188d811
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/back-quoted-open.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+touch foo
+BUFFER=$': `ls fo'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 8 default' # `ls fo
+ '3 8 back-quoted-argument-unclosed' # `ls fo
+ '3 3 back-quoted-argument-delimiter' # `
+ '4 5 command' # ls
+ '7 8 path_prefix' # fo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-continuation.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-continuation.zsh
new file mode 100644
index 00000000..ebcf2e17
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-continuation.zsh
@@ -0,0 +1,35 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+PREBUFFER=$'echo \\\n'
+BUFFER='noglob'
+
+expected_region_highlight=(
+ "1 6 default" # 'noglob' highlighted as a string, not as a precomand
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-continuation2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-continuation2.zsh
new file mode 100644
index 00000000..9e2ca623
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-continuation2.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'echo foo\\\nbar"baz"'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 18 default "issue #705"' # foo\\\nbar"baz"
+ '14 18 double-quoted-argument "issue #705"' # "baz"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-space.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-space.zsh
new file mode 100644
index 00000000..0d8a63c1
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash-space.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'echo \\ \'foo\' ; ls'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 12 default' # \ \'foo\'
+ '8 12 single-quoted-argument' # 'foo'
+ '14 14 commandseparator' # ;
+ '16 17 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash.zsh
new file mode 100644
index 00000000..ea0977f6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/backslash.zsh
@@ -0,0 +1,34 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'\\'
+
+expected_region_highlight=(
+ '1 1 unknown-token' # \\
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-assign-array.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-assign-array.zsh
new file mode 100644
index 00000000..a54cf2d0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-assign-array.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'foo=(bar abaz) \! ls'
+
+expected_region_highlight=(
+ '1 5 assign' # foo=(
+ '5 5 reserved-word' # (
+ '6 8 default' # bar
+ '10 13 default' # abaz
+ '14 14 assign' # )
+ '14 14 reserved-word' # )
+ '16 16 unknown-token' # \!
+ '18 19 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-assign-scalar.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-assign-scalar.zsh
new file mode 100644
index 00000000..e9190500
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-assign-scalar.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'foo=bar \! ls'
+
+expected_region_highlight=(
+ '1 7 assign' # foo=bar
+ '5 7 default' # bar
+ '9 9 unknown-token' # \!
+ '11 12 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-pipeline.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-pipeline.zsh
new file mode 100644
index 00000000..fef25f10
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/bang-pipeline.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'\! ls | \! ls'
+
+expected_region_highlight=(
+ '1 1 reserved-word' # \!
+ '3 4 command' # ls
+ '6 6 commandseparator' # |
+ '8 8 unknown-token' # \!
+ '10 11 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/block-assignment-no-command.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/block-assignment-no-command.zsh
new file mode 100644
index 00000000..ec52c987
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/block-assignment-no-command.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2022 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'{ a=42 }'
+
+expected_region_highlight=(
+ '1 1 reserved-word' # {
+ '3 6 assign' # a=42
+ '5 6 default' # 42
+ '8 8 reserved word "issue #854"' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/braces1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/braces1.zsh
new file mode 100644
index 00000000..3c5b1f0f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/braces1.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'() { echo }\n}'
+# no special setopts
+
+expected_region_highlight=(
+ '1 2 reserved-word' # ()
+ '4 4 reserved-word' # {
+ '6 9 builtin' # echo
+ '11 11 reserved-word' # }
+ '12 12 commandseparator' # \n
+ '13 13 unknown-token' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/braces2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/braces2.zsh
new file mode 100644
index 00000000..a3ea7c95
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/braces2.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'() { echo }\n}'
+setopt ignorebraces
+
+expected_region_highlight=(
+ '1 2 reserved-word' # ()
+ '4 4 reserved-word' # {
+ '6 9 builtin' # echo
+ '11 11 default' # }
+ '12 12 commandseparator' # \n
+ '13 13 reserved-word' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-matching1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-matching1.zsh
new file mode 100644
index 00000000..7cc6de54
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-matching1.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='[[ -n foo ]]'
+
+expected_region_highlight=(
+ '1 2 reserved-word' # [[
+ '4 5 single-hyphen-option' # -n
+ '7 9 default' # foo
+ '11 12 reserved-word' # ]]
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-matching2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-matching2.zsh
new file mode 100644
index 00000000..19c7f0d7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-matching2.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='[ -n foo ]'
+
+expected_region_highlight=(
+ '1 1 builtin' # [
+ '3 4 single-hyphen-option' # -n
+ '6 8 default' # foo
+ '10 10 builtin' # ]
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch1.zsh
new file mode 100644
index 00000000..5e6e80f2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch1.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='() { echo foo )'
+
+expected_region_highlight=(
+ '1 2 reserved-word' # ()
+ '4 4 reserved-word' # {
+ '6 9 builtin' # echo
+ '11 13 default' # foo
+ '15 15 unknown-token' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch10-if-negative.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch10-if-negative.zsh
new file mode 100644
index 00000000..9d0b53c6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch10-if-negative.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='elif true; then echo two; fi'
+
+expected_region_highlight=(
+ '1 4 unknown-token' # elif
+ '6 9 builtin' # true
+ '10 10 commandseparator' # ;
+ '12 15 unknown-token' # then
+ '17 20 builtin' # echo
+ '22 24 default' # two
+ '25 25 commandseparator' # ;
+ '27 28 unknown-token' # fi
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch2.zsh
new file mode 100644
index 00000000..2d98ac21
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch2.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='() ( echo foo }'
+
+expected_region_highlight=(
+ '1 2 reserved-word' # ()
+ '4 4 reserved-word' # (
+ '6 9 builtin' # echo
+ '11 13 default' # foo
+ '15 15 unknown-token' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch3.zsh
new file mode 100644
index 00000000..e33040a8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch3.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo )'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 6 unknown-token' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch4.zsh
new file mode 100644
index 00000000..a9b15dcd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch4.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo }'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 6 unknown-token' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch5.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch5.zsh
new file mode 100644
index 00000000..21e8bb2b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch5.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo { }'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 6 default' # {
+ '8 8 unknown-token' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch6.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch6.zsh
new file mode 100644
index 00000000..9df83883
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch6.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='(repeat 1; do)'
+
+expected_region_highlight=(
+ '1 1 reserved-word' # (
+ '2 7 reserved-word' # repeat
+ '9 9 default' # 1
+ '10 10 commandseparator' # ;
+ '12 13 reserved-word' # do
+ '14 14 unknown-token' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch7.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch7.zsh
new file mode 100644
index 00000000..1caa936c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch7.zsh
@@ -0,0 +1,45 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2012 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='for n in *; do echo $n; end'
+
+expected_region_highlight=(
+ '1 3 reserved-word' # for
+ '5 5 default' # n
+ '7 8 default' # in
+ '10 10 default' # *
+ '10 10 globbing' # *
+ '11 11 commandseparator' # ;
+ '13 14 reserved-word' # do
+ '16 19 builtin' # echo
+ '21 22 default' # $n
+ '23 23 commandseparator' # ;
+ '25 27 unknown-token' # end
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch8-if-positive.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch8-if-positive.zsh
new file mode 100644
index 00000000..d6838f00
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch8-if-positive.zsh
@@ -0,0 +1,53 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='if false; then echo one; elif true; then echo two; else echo three; fi'
+
+expected_region_highlight=(
+ '1 2 reserved-word' # if
+ '4 8 builtin' # false
+ '9 9 commandseparator' # ;
+ '11 14 reserved-word' # then
+ '16 19 builtin' # echo
+ '21 23 default' # one
+ '24 24 commandseparator' # ;
+ '26 29 reserved-word' # elif
+ '31 34 builtin' # true
+ '35 35 commandseparator' # ;
+ '37 40 reserved-word' # then
+ '42 45 builtin' # echo
+ '47 49 default' # two
+ '50 50 commandseparator' # ;
+ '52 55 reserved-word' # else
+ '57 60 builtin' # echo
+ '62 66 default' # three
+ '67 67 commandseparator' # ;
+ '69 70 reserved-word' # fi
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch8.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch8.zsh
new file mode 100644
index 00000000..07a42e36
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch8.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='(ls&)'
+
+expected_region_highlight=(
+ '1 1 reserved-word' # (
+ '2 3 command' # ls
+ '4 4 commandseparator' # &
+ '5 5 reserved-word' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch9-if-positive.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch9-if-positive.zsh
new file mode 100644
index 00000000..87c1ba79
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-mismatch9-if-positive.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='if false; then echo one; fi'
+
+expected_region_highlight=(
+ '1 2 reserved-word' # if
+ '4 8 builtin' # false
+ '9 9 commandseparator' # ;
+ '11 14 reserved-word' # then
+ '16 19 builtin' # echo
+ '21 23 default' # one
+ '24 24 commandseparator' # ;
+ '26 27 reserved-word' # fi
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-premature-termination.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-premature-termination.zsh
new file mode 100644
index 00000000..fa813da9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/brackets-premature-termination.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='[[ -n foo; echo ]]'
+
+expected_region_highlight=(
+ '1 2 reserved-word' # [[
+ '4 5 single-hyphen-option' # -n
+ '7 9 default' # foo
+ '10 10 unknown-token' # ;
+ '12 15 builtin' # echo
+ '17 18 default' # ]]
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cdpath-abspath.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cdpath-abspath.zsh
new file mode 100644
index 00000000..64707b2f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cdpath-abspath.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+cdpath=( $PWD )
+mkdir foo foo/bar
+
+BUFFER="/foo"
+
+expected_region_highlight=(
+ '1 4 unknown-token' # x (/)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cmdpos-elision-partial.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cmdpos-elision-partial.zsh
new file mode 100644
index 00000000..6eda0d74
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cmdpos-elision-partial.zsh
@@ -0,0 +1,44 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Test elision of some, but not all of the words
+# See issue #667 for the case of eliding all words
+local -a x; x=(sudo "")
+
+sudo(){}
+BUFFER=$'$x -u phy1729 ls'
+
+expected_region_highlight=(
+ '1 2 precommand' # $x
+ # The "" is elided. If it weren't elided, the «ls» would be highlighted as an ordinary argument.
+ '4 5 single-hyphen-option' # -u
+ '7 13 default' # phy1729
+ '15 16 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-adjacent.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-adjacent.zsh
new file mode 100644
index 00000000..3d5c0b9e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-adjacent.zsh
@@ -0,0 +1,45 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo "$(echo)$(echo)'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 20 default' # "$(echo)$(echo)
+ '6 6 double-quoted-argument-unclosed' # "
+ '7 13 command-substitution-quoted' # $(echo)
+ '7 8 command-substitution-delimiter-quoted' # $(
+ '9 12 builtin' # echo
+ '13 13 command-substitution-delimiter-quoted' # )
+ '14 20 command-substitution-quoted' # $(echo)
+ '14 15 command-substitution-delimiter-quoted' # $(
+ '16 19 builtin' # echo
+ '20 20 command-substitution-delimiter-quoted' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-in-assignment.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-in-assignment.zsh
new file mode 100644
index 00000000..fafda49c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-in-assignment.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'foo=$(echo bar) :'
+
+expected_region_highlight=(
+ '1 15 assign' # foo=$(echo bar)
+ '5 15 default' # $(echo bar)
+ '5 15 command-substitution-unquoted' # $(echo bar)
+ '5 6 command-substitution-delimiter-unquoted' # $(
+ '7 10 builtin' # echo
+ '12 14 default' # bar
+ '15 15 command-substitution-delimiter-unquoted' # )
+ '17 17 builtin' # :
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-unclosed.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-unclosed.zsh
new file mode 100644
index 00000000..3229dfcf
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/command-substitution-unclosed.zsh
@@ -0,0 +1,45 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': foo$(echo bar'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 15 default' # foo$(echo bar
+ '6 15 command-substitution-unquoted' # $(echo bar
+ '6 7 command-substitution-delimiter-unquoted' # $(
+ '8 11 builtin' # echo
+ '13 15 default' # bar
+)
+
+if [[ ${(z):-'$('} == '$( ' ]]; then # ignore zsh 5.0.8 bug
+ expected_region_highlight[2]='3 16 default' # foo$(echo bar
+ expected_region_highlight[3]='6 16 command-substitution-unquoted' # $(echo bar
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/commandseparator.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/commandseparator.zsh
new file mode 100644
index 00000000..f504847c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/commandseparator.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=':; pwd &! ls'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "2 2 commandseparator" # ;
+ "4 6 builtin" # pwd
+ "8 9 commandseparator" # &!
+ "11 12 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-followed.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-followed.zsh
new file mode 100644
index 00000000..044f2830
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-followed.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# see alias-comment1.zsh
+setopt interactivecomments
+BUFFER=$'# foo\ntrue'
+
+expected_region_highlight=(
+ '1 5 comment' # # foo
+ '6 6 commandseparator' # \n
+ '7 10 builtin' # true
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-leading.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-leading.zsh
new file mode 100644
index 00000000..b4c99105
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-leading.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt interactive_comments
+
+BUFFER='# echo foo'
+
+expected_region_highlight=(
+ "1 10 comment" # # echo foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-off.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-off.zsh
new file mode 100644
index 00000000..0381bdb0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comment-off.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsetopt interactive_comments
+
+BUFFER='# echo foo'
+
+expected_region_highlight=(
+ "1 1 unknown-token" # #
+ "3 6 default" # " echo foo"
+ "8 10 default" # " echo foo"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comments.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comments.zsh
new file mode 100644
index 00000000..f3cc57e4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/comments.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt interactive_comments
+
+BUFFER='echo "foo #bar" #baz # quux'
+
+expected_region_highlight=(
+ "1 4 builtin" # echo
+ "6 15 default" # "foo #bar"
+ "6 15 double-quoted-argument" # "foo #bar"
+ "17 27 comment" # #baz # quux
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/commmand-parameter.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/commmand-parameter.zsh
new file mode 100644
index 00000000..48d20ba8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/commmand-parameter.zsh
@@ -0,0 +1,45 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+local x=/usr/bin/env
+local y=sudo
+local -a z; z=(zsh -f)
+sudo(){}
+
+BUFFER='$x "argument"; $y; $z'
+
+expected_region_highlight=(
+ "1 2 command" # $x
+ "4 13 default" # "argument"
+ "4 13 double-quoted-argument" # "argument"
+ "14 14 commandseparator" # ;
+ "16 17 precommand" # $y (sudo)
+ "18 18 unknown-token" # ;
+ "20 21 command" # $z - 'zsh' being the command
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow.zsh
new file mode 100644
index 00000000..a610bdc3
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow.zsh
@@ -0,0 +1,57 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='while if echo Hello; then ls /; else ls; fi; do stat "x"; done; repeat 10 ls'
+
+expected_region_highlight+=(
+ "1 5 reserved-word" # while
+ "7 8 reserved-word" # if
+ "10 13 builtin" # echo
+ "15 19 default" # Hello
+ "20 20 commandseparator" # ;
+ "22 25 reserved-word" # then
+ "27 28 command" # ls
+ "30 30 path" # /
+ "31 31 commandseparator" # ;
+ "33 36 reserved-word" # else
+ "38 39 command" # ls
+ "40 40 commandseparator" # ;
+ "42 43 reserved-word" # fi
+ "44 44 commandseparator" # ;
+ "46 47 reserved-word" # do
+ "49 52 command" # stat
+ "54 56 default" # "x"
+ "54 56 double-quoted-argument" # "x"
+ "57 57 commandseparator" # ;
+ "59 62 reserved-word" # done
+ "63 63 commandseparator" # ;
+ "65 70 reserved-word" # repeat
+ "72 73 default" # 10
+ "75 76 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow2.zsh
new file mode 100644
index 00000000..acf99e1d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow2.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='repeat 42; do ls; done'
+
+expected_region_highlight+=(
+ "1 6 reserved-word" # repeat
+ "8 9 default" # 42
+ "10 10 commandseparator" # ;
+ "12 13 reserved-word" # do
+ "15 16 command" # ls
+ "17 17 commandseparator" # ;
+ "19 22 reserved-word" # done
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow3.zsh
new file mode 100644
index 00000000..58f507f9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/control-flow3.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='repeat 42; ls; pwd'
+
+expected_region_highlight+=(
+ "1 6 reserved-word" # repeat
+ "8 9 default" # 42
+ "10 10 commandseparator" # ;
+ "12 13 command" # ls
+ "14 14 commandseparator" # ;
+ "16 18 builtin" # pwd
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cthulhu.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cthulhu.zsh
new file mode 100644
index 00000000..c8119a84
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/cthulhu.zsh
@@ -0,0 +1,70 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# 0000000 0 01111111111222222 222233333 3 333344 4 4 444444555555555 5 6 6666 6 6 6667777777777888 8 8 88888999 9 9999 9 9 00 00 0000001111
+# 1234567 8 90123456789012345 678901234 5 678901 2 3 456789012345678 9 0 1234 5 6 7890123456789012 3 4 56789012 3 4567 8 9 01 23 4567890123
+BUFFER=$'echo Ph\\\'ng`echo lui "mg"\\`echo lw\\\'nafh \\\\\\`echo Cthu"lhu\\\\\\` R\\\\\'ly$(echo eh wag\\\\\\`echo h\\\'nag\\\\\\`\'l\' fht)agn`'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 113 default' # Ph\'ng`echo lui "mg"\`echo lw\'nafh \\\`echo Cthu"lhu\\\` R\\'ly$(echo eh wag\\\`echo h\'nag\\\`'l' fht)agn`
+ '12 113 back-quoted-argument' # `echo lui "mg"\`echo lw\'nafh \\\`echo Cthu"lhu\\\` R\\'ly$(echo eh wag\\\`echo h\'nag\\\`'l' fht)agn`
+ '12 12 back-quoted-argument-delimiter' # `
+ '13 16 builtin' # echo
+ '18 20 default' # lui
+ '22 112 default' # "mg"\`echo lw\'nafh \\\`echo Cthu"lhu\\\` R\\'ly$(echo eh wag\\\`echo h\'nag\\\`'l' fht)agn
+ '22 25 double-quoted-argument' # "mg"
+ '26 112 back-quoted-argument-unclosed' # \`echo lw\'nafh \\\`echo Cthu"lhu\\\` R\\'ly$(echo eh wag\\\`echo h\'nag\\\`'l' fht)agn
+ '26 27 back-quoted-argument-delimiter' # \`
+ '28 31 builtin' # echo
+ '33 40 default' # lw\'nafh
+ '42 62 default' # \\\`echo Cthu"lhu\\\`
+ '42 62 back-quoted-argument' # \\\`echo Cthu"lhu\\\`
+ '42 45 back-quoted-argument-delimiter' # \\\`
+ '46 49 builtin' # echo
+ '51 58 default' # Cthu"lhu
+ '55 58 double-quoted-argument-unclosed' # "lhu
+ '59 62 back-quoted-argument-delimiter' # \\\`
+ '64 112 default' # R\\'ly$(echo eh wag\\\`echo h\'nag\\\`'l' fht)agn
+ '70 109 command-substitution-unquoted' # $(echo eh wag\\\`echo h\'nag\\\`'l' fht)
+ '70 71 command-substitution-delimiter-unquoted' # $(
+ '72 75 builtin' # echo
+ '77 78 default' # eh
+ '80 104 default' # wag\\\`echo h\'nag\\\`'l'
+ '83 101 back-quoted-argument' # \\\`echo h\'nag\\\`
+ '83 86 back-quoted-argument-delimiter' # \\\`
+ '87 90 builtin' # echo
+ '92 97 default' # h\'nag
+ '98 101 back-quoted-argument-delimiter' # \\\`
+ '102 104 single-quoted-argument' # 'l'
+ '106 108 default' # fht
+ '109 109 command-substitution-delimiter-unquoted' # )
+ '113 113 unknown-token' # `
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dinbrack1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dinbrack1.zsh
new file mode 100644
index 00000000..e2279d6b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dinbrack1.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'[[ foo && bar || baz ]]'
+
+expected_region_highlight=(
+ '1 2 reserved-word' # [[
+ '4 6 default' # foo
+ '8 9 default' # &&
+ '11 13 default' # bar
+ '15 16 default' # ||
+ '18 20 default' # baz
+ '22 23 reserved-word' # ]]
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dirs_blacklist.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dirs_blacklist.zsh
new file mode 100644
index 00000000..2d0222f0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dirs_blacklist.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+mkdir foo
+touch foo/bar
+BUFFER=": foo/bar $PWD/foo foo/b"
+ZSH_HIGHLIGHT_DIRS_BLACKLIST=($PWD/foo $PWD/bar)
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 9 default' # foo/bar
+ "11 $(( 14 + $#PWD )) default" # $PWD/foo
+ "$(( 16 + $#PWD )) $(( 20 + $#PWD )) default" # foo/b
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-dollar.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-dollar.zsh
new file mode 100644
index 00000000..e3f387ce
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-dollar.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': "$$ $$foo"'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 12 default' # "$$ $$foo"
+ '3 12 double-quoted-argument' # "$$ $$foo"
+ '4 5 dollar-double-quoted-argument' # $$
+ '7 8 dollar-double-quoted-argument' # $$
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-noise.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-noise.zsh
new file mode 100644
index 00000000..9bb11bd8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-noise.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': "$- $# $* $@ $?"'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 18 default' # "$- $# $* $@ $?"
+ '3 18 double-quoted-argument' # "$- $# $* $@ $?"
+ '4 5 dollar-double-quoted-argument' # $-
+ '7 8 dollar-double-quoted-argument' # $#
+ '10 11 dollar-double-quoted-argument' # $*
+ '13 14 dollar-double-quoted-argument' # $@
+ '16 17 dollar-double-quoted-argument' # $?
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-paren.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-paren.zsh
new file mode 100644
index 00000000..2bbcef18
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-paren.zsh
@@ -0,0 +1,49 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': "$(:)" "foo$(:)bar'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 8 default' # "$(:)"
+ '3 3 double-quoted-argument' # "$(:)"
+ '8 8 double-quoted-argument' # "$(:)"
+ '4 7 command-substitution-quoted' # $(:)
+ '4 5 command-substitution-delimiter-quoted' # $(
+ '6 6 builtin' # :
+ '7 7 command-substitution-delimiter-quoted' # )
+ '10 20 default' # "foo$(:)bar
+ '10 13 double-quoted-argument-unclosed' # "foo
+ '18 20 double-quoted-argument-unclosed' # bar
+ '14 17 command-substitution-quoted' # $(:)
+ '14 15 command-substitution-delimiter-quoted' # $(
+ '16 16 builtin' # :
+ '17 17 command-substitution-delimiter-quoted' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted.zsh
new file mode 100644
index 00000000..081a365b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=": \$'*' 'foo'"
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 6 default" # $'*'
+ "3 6 dollar-quoted-argument" # $'*' - not a glob
+ "8 12 default" # 'foo'
+ "8 12 single-quoted-argument" # 'foo'
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted2.zsh
new file mode 100644
index 00000000..ed7428bd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted2.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=": \$'foo\xbar\udeadbeef\uzzzz'"
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 29 default" # $'foo\xbar\udeadbeef\uzzzz'
+ "3 29 dollar-quoted-argument" # $'foo\xbar\udeadbeef\uzzzz'
+ "8 11 back-dollar-quoted-argument" # \xba
+ "13 18 back-dollar-quoted-argument" # \dead
+ "23 24 unknown-token" # \u
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted3.zsh
new file mode 100644
index 00000000..365f3519
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/dollar-quoted3.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Similar to double-quoted2.zsh
+# This test checks that the '1' gets highlighted correctly. Do not append to the BUFFER.
+BUFFER=": \$'\xa1"
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 8 default" # $'\xa1
+ "3 8 dollar-quoted-argument-unclosed" # $'\xa1
+ "5 8 back-dollar-quoted-argument" # \xa1
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-hyphen-option.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-hyphen-option.zsh
new file mode 100644
index 00000000..e5cacd37
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-hyphen-option.zsh
@@ -0,0 +1,35 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='hello --world'
+
+expected_region_highlight=(
+ "1 5 unknown-token" # hello
+ "7 13 double-hyphen-option" # --world
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted.zsh
new file mode 100644
index 00000000..0a4336ca
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': "foo$bar:\`:\":\$:'
+BUFFER+=\\\\:\"
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 24 default" # "foo$bar:\`:\":\$:\\:"
+ "3 24 double-quoted-argument" # "foo$bar:\`:\":\$:\\:"
+ "7 10 dollar-double-quoted-argument" # $bar
+ "12 13 back-double-quoted-argument" # \`
+ "15 16 back-double-quoted-argument" # \$
+ "18 19 back-double-quoted-argument" # \"
+ "21 22 back-double-quoted-argument" # \\
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted2.zsh
new file mode 100644
index 00000000..c400e543
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted2.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Similar to dollar-quoted3.zsh
+# This test checks that the 'r' gets highlighted correctly. Do not append to the BUFFER.
+BUFFER=': "foo$bar'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 10 default" # "foo$bar
+ "3 10 double-quoted-argument-unclosed" # "foo$bar
+ "7 10 dollar-double-quoted-argument" # $bar
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted3.zsh
new file mode 100644
index 00000000..86e3ced6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted3.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': "$" "$42foo"'
+BUFFER+=\ \"\\\'\\x\"
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 5 default" # "$"
+ "3 5 double-quoted-argument" # "$"
+ "7 14 default" # "$42foo"
+ "7 14 double-quoted-argument" # "$42foo"
+ "8 10 dollar-double-quoted-argument" # $42
+ "16 21 default" # "\'\x"
+ "16 21 double-quoted-argument" # "\'\x" - \' and \x are not escape sequences
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted4.zsh
new file mode 100644
index 00000000..c59d5d8e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/double-quoted4.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': "${foo}bar"'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 13 default" # "${foo}bar"
+ "3 13 double-quoted-argument" # "${foo}bar"
+ "4 9 dollar-double-quoted-argument" # ${foo}
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command-newline.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command-newline.zsh
new file mode 100644
index 00000000..4b7b35c6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command-newline.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Newline after semicolon isn't unknown-token
+BUFFER=$':;\n:'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '2 2 commandseparator' # ;
+ '3 3 commandseparator' # \n
+ '4 4 builtin' # :
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command.zsh
new file mode 100644
index 00000000..5831464d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo; ;'
+
+expected_region_highlight=(
+ "1 4 builtin" # echo
+ "5 5 commandseparator" # ;
+ "7 7 unknown-token" # ;
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command2.zsh
new file mode 100644
index 00000000..dcb4e6f7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-command2.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Same test data and expectations as empty-command.zsh; the only difference is:
+touch ';'
+
+BUFFER='echo; ;'
+
+expected_region_highlight=(
+ "1 4 builtin" # echo
+ "5 5 commandseparator" # ;
+ "7 7 unknown-token" # ;
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-line.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-line.zsh
new file mode 100644
index 00000000..a4d6685b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/empty-line.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'\\\n; ls'
+
+expected_region_highlight=(
+ '3 3 unknown-token' # ;
+ '5 6 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals1.zsh
new file mode 100644
index 00000000..77f46e8d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals1.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': =ls'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 5 path' # =ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals2.zsh
new file mode 100644
index 00000000..bd59ff75
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals2.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsetopt equals
+
+BUFFER=$': =nosuchcommand'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 16 default' # =nosuchcommand
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals3.zsh
new file mode 100644
index 00000000..8c107890
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals3.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': =nosuchcommand'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 16 unknown-token' # =nosuchcommand
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals4.zsh
new file mode 100644
index 00000000..28bc2148
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/equals4.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': ='
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 3 default' # =
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/escaped-single-quote.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/escaped-single-quote.zsh
new file mode 100644
index 00000000..4b2fe4bc
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/escaped-single-quote.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': \'foo\'\\\'\'bar\'' # <<<: 'foo'\''bar'>>>
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 14 default' # 'foo'\''bar'
+ '3 7 single-quoted-argument' # 'foo'
+ '10 14 single-quoted-argument' # 'bar'
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/exec-redirection1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/exec-redirection1.zsh
new file mode 100644
index 00000000..78a0c623
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/exec-redirection1.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='exec {foo}>&/tmp ls'
+
+expected_region_highlight=(
+ "1 4 precommand" # exec
+ "6 10 named-fd" # {foo}
+ "11 12 redirection" # >&
+ "13 16 path" # /tmp
+ "18 19 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/fd-target-not-filename.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/fd-target-not-filename.zsh
new file mode 100644
index 00000000..5c3cd089
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/fd-target-not-filename.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+touch 2
+
+BUFFER=$'echo foo>&2'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 8 default' # foo
+ '9 10 redirection' # >&
+ '11 11 numeric-fd' # 2 (not path)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-altsyntax.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-altsyntax.zsh
new file mode 100644
index 00000000..0f9a8339
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-altsyntax.zsh
@@ -0,0 +1,45 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Define named and anonymous function using the alternative syntax
+BUFFER=$'function f { pwd }; function { pwd }'
+
+expected_region_highlight=(
+ '1 8 reserved-word' # function
+ '10 10 default' # f
+ '12 12 reserved-word "issue #237"' # {
+ '14 16 command "issue #237"' # pwd
+ '18 18 reserved-word "issue #237"' # }
+ '19 19 commandseparator' # ;
+ '21 28 reserved-word' # function
+ '30 30 reserved-word "issue #237"' # {
+ '32 34 command "issue #237"' # pwd
+ '36 36 reserved-word "issue #237"' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-named1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-named1.zsh
new file mode 100644
index 00000000..c962ddbb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-named1.zsh
@@ -0,0 +1,44 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='f() pwd; f() { balanced braces }'
+
+expected_region_highlight=(
+ '1 1 TBD "issue #223"' # f
+ '2 3 reserved-word' # ()
+ '5 7 builtin' # pwd
+ '8 8 commandseparator' # ;
+ '10 10 TBD "issue #223"' # f
+ '11 12 reserved-word' # ()
+ '14 14 reserved-word' # {
+ '16 23 unknown-token' # balanced
+ '25 30 default' # braces
+ '32 32 reserved-word' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-named2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-named2.zsh
new file mode 100644
index 00000000..e12fce6a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function-named2.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='f g h () pwd'
+
+expected_region_highlight=(
+ '1 1 TBD "issue #223"' # f
+ '3 3 TBD "issue #223"' # g
+ '5 5 TBD "issue #223"' # h
+ '7 8 reserved-word' # ()
+ '10 12 builtin' # pwd
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function.zsh
new file mode 100644
index 00000000..b1be8539
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/function.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+cd() {
+ builtin cd "$@"
+}
+ls() {
+ command ls "$@"
+}
+BUFFER='cd;ls'
+
+expected_region_highlight=(
+ "1 2 function" # cd
+ "3 3 commandseparator" # ;
+ "4 5 function" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/glob.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/glob.zsh
new file mode 100644
index 00000000..2ff1022e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/glob.zsh
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': foo* bar? *baz qux\?'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 6 default" # foo*
+ "6 6 globbing" # *
+ "8 11 default" # bar?
+ "11 11 globbing" # ?
+ "13 16 default" # *baz
+ "13 13 globbing" # *
+ "18 22 default" # qux\?
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/global-alias1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/global-alias1.zsh
new file mode 100644
index 00000000..0022de3c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/global-alias1.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias -g foo=bar
+
+BUFFER=$'foo foo'
+
+expected_region_highlight=(
+ '1 3 global-alias' # foo
+ '5 7 global-alias' # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/globs-with-quoting.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/globs-with-quoting.zsh
new file mode 100644
index 00000000..d7d74bc4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/globs-with-quoting.zsh
@@ -0,0 +1,43 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': "foo"*\'bar\'?"baz?"<17-29>"qu*ux"'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 34 default' # "foo"*'bar'?"baz?"<17-29>"qu*ux"
+ '3 7 double-quoted-argument' # "foo"
+ '8 8 globbing' # *
+ '9 13 single-quoted-argument' # 'bar'
+ '14 14 globbing' # ?
+ '15 20 double-quoted-argument' # "baz?"
+ '21 27 globbing' # <17-29>
+ '28 34 double-quoted-argument' # "qu*ux"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/hashed-command.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/hashed-command.zsh
new file mode 100644
index 00000000..2983ef8d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/hashed-command.zsh
@@ -0,0 +1,35 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+hash zsh_syntax_highlighting_hash=/doesnotexist
+BUFFER='zsh_syntax_highlighting_hash'
+
+expected_region_highlight=(
+ "1 28 hashed-command 'zsh/parameter cannot distinguish between hashed and command'"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-escaped.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-escaped.zsh
new file mode 100644
index 00000000..7807cc06
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-escaped.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo "Hello\!"'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 14 default' # "Hello\!"
+ '6 14 double-quoted-argument' # "Hello\!"
+ '12 13 back-double-quoted-argument' # \!
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-followed.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-followed.zsh
new file mode 100644
index 00000000..6421ceda
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-followed.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': !!= "!!="'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 4 history-expansion "issue #713"' # !!
+ '7 11 default' # "!!="
+ '7 11 double-quoted-argument' # "!!="
+ '8 9 history-expansion "issue #713' # !!
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-no.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-no.zsh
new file mode 100644
index 00000000..e082dbcf
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-no.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo "foo != bar !{baz}"'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 24 default' # "foo != bar !{baz}"
+ '6 24 double-quoted-argument' # "foo != bar !{baz}" - no history expansions
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-unescaped.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-unescaped.zsh
new file mode 100644
index 00000000..cfe6a11d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-unescaped.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo "Hello!"'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 13 default' # "Hello!"
+ '6 13 double-quoted-argument' # "Hello!"
+ '12 12 history-expansion' # !
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-yes.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-yes.zsh
new file mode 100644
index 00000000..e963c3b9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-double-quoted-yes.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo "foo !bar"'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 15 default' # "foo !bar"
+ '6 15 double-quoted-argument' # "foo !bar"
+ '11 11 history-expansion' # !
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-expansion.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-expansion.zsh
new file mode 100644
index 00000000..05e20fc1
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-expansion.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='!foo bar !baz ! ; !'
+
+expected_region_highlight=(
+ "1 4 history-expansion" # !foo
+ "6 8 default" # bar
+ "10 13 history-expansion" # !baz
+ "15 15 default" # !
+ "17 17 commandseparator" # ;
+ "19 19 reserved-word" # !
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-expansion2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-expansion2.zsh
new file mode 100644
index 00000000..386d0df9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/history-expansion2.zsh
@@ -0,0 +1,34 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='^foo^bar'
+
+expected_region_highlight=(
+ "1 8 history-expansion" # ^foo^bar
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/inheritance.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/inheritance.zsh
new file mode 100644
index 00000000..e851ca3e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/inheritance.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+_zsh_highlight_add_highlight()
+{
+ region_highlight+=("$1 $2 ${(j.,.)argv[3,-1]}")
+}
+
+BUFFER='type'
+
+expected_region_highlight=(
+ '1 4 builtin,arg0' # type
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/jobsubst-isnt-glob.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/jobsubst-isnt-glob.zsh
new file mode 100644
index 00000000..3a7e325a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/jobsubst-isnt-glob.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018.9958 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': %? %?foo'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 4 default' # %?
+ '6 10 default' # %?foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/jobsubst-isnt-glob2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/jobsubst-isnt-glob2.zsh
new file mode 100644
index 00000000..51930bfb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/jobsubst-isnt-glob2.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': foo%?bar'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 10 default' # foo%?bar
+ '7 7 globbing' # ?
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/loop-newline.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/loop-newline.zsh
new file mode 100644
index 00000000..d39ee112
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/loop-newline.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'for i in \\\n; do done'
+
+expected_region_highlight=(
+ '1 3 reserved-word' # for
+ '5 5 default' # i
+ '7 8 default' # in
+ '12 12 commandseparator' # ;
+ '14 15 reserved-word' # do
+ '17 20 reserved-word' # done
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/meta-no-eval1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/meta-no-eval1.zsh
new file mode 100644
index 00000000..bb040777
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/meta-no-eval1.zsh
@@ -0,0 +1,49 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(kill -9 $$) ${:-$(kill -9 $$)}'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 15 default' # $(kill -9 $$)
+ '3 15 command-substitution-unquoted' # $(kill -9 $$)
+ '3 4 command-substitution-delimiter-unquoted' # $(
+ '5 8 builtin' # kill
+ '10 11 single-hyphen-option' # -9
+ '13 14 default' # $$
+ '15 15 command-substitution-delimiter-unquoted' # )
+ '17 34 default' # ${:-$(kill -9 $$)}
+ '21 33 command-substitution-unquoted' # $(kill -9 $$)
+ '21 22 command-substitution-delimiter-unquoted' # $(
+ '23 26 builtin' # kill
+ '28 29 single-hyphen-option' # -9
+ '31 32 default' # $$
+ '33 33 command-substitution-delimiter-unquoted' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/meta-no-eval2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/meta-no-eval2.zsh
new file mode 100644
index 00000000..61ef0892
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/meta-no-eval2.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# We aren't testing how this is highlighted; we're testing that it's not
+# evaluated. If it gets evaluated, the test suite will die.
+BUFFER=$': /(e*exit 42*)'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 15 default' # /(e*exit 42*)
+ '6 6 globbing' # *
+ '14 14 globbing' # *
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-array-assignment1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-array-assignment1.zsh
new file mode 100644
index 00000000..8906cfde
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-array-assignment1.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'foo=(\nbar) env'
+
+expected_region_highlight=(
+ '1 5 assign' # foo=(
+ '5 5 reserved-word' # (
+ '6 6 commandseparator' # \n
+ '7 9 default' # bar
+ '10 10 assign' # )
+ '10 10 reserved-word' # )
+ '12 14 precommand' # env
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-string.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-string.zsh
new file mode 100644
index 00000000..0127b4bf
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-string.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+PREBUFFER=$'echo "foo1\n'
+BUFFER='foo2" ./'
+
+expected_region_highlight=(
+ "1 5 default" # 'foo2"'
+ "1 5 double-quoted-argument" # 'foo2"'
+ "7 8 path" # './'
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-string2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-string2.zsh
new file mode 100644
index 00000000..3a90dce8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiline-string2.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'echo \'foo1\n'
+
+expected_region_highlight=(
+ "1 4 builtin" # echo
+ "6 11 default" # 'foo1\n
+ "6 11 single-quoted-argument-unclosed" # 'foo1\n
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multios-negates-globbing.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multios-negates-globbing.zsh
new file mode 100644
index 00000000..7ece6708
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multios-negates-globbing.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+unsetopt multios
+
+BUFFER=$'cat < *'
+
+expected_region_highlight=(
+ '1 3 command' # cat
+ '5 5 redirection' # <
+ '7 7 default' # * - not globbing
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multios-negates-globbing2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multios-negates-globbing2.zsh
new file mode 100644
index 00000000..b6db983d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multios-negates-globbing2.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'cat < *'
+
+expected_region_highlight=(
+ '1 3 command' # cat
+ '5 5 redirection' # <
+ '7 7 default' # *
+ '7 7 globbing' # *
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiple-quotes.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiple-quotes.zsh
new file mode 100644
index 00000000..dabf70c8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiple-quotes.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': \'foo\'bar"baz$quux/foo\\\\bar"baz$\'quux\\nfoo\\001bar\'baz'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 54 default" # 'foo'bar"baz$quux/foo\\bar"baz$'quux\nfoo\001'baz
+ "3 7 single-quoted-argument" # 'foo'
+ "11 29 double-quoted-argument" #"baz
+ "15 19 dollar-double-quoted-argument" # $quux
+ "24 25 back-double-quoted-argument" # \\
+ "33 51 dollar-quoted-argument" # $'quux\nfoo\001bar'
+ "39 40 back-dollar-quoted-argument" # \n
+ "44 47 back-dollar-quoted-argument" # \001
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiple-redirections.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiple-redirections.zsh
new file mode 100644
index 00000000..778e7129
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/multiple-redirections.zsh
@@ -0,0 +1,46 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='ps aux | grep java | sort | uniq | tail | head'
+
+expected_region_highlight=(
+ "1 2 command" # ps
+ "4 6 default" # aux
+ "8 8 commandseparator" # |
+ "10 13 command" # grep
+ "15 18 default" # java
+ "20 20 commandseparator" # |
+ "22 25 command" # sort
+ "27 27 commandseparator" # |
+ "29 32 command" # uniq
+ "34 34 commandseparator" # |
+ "36 39 command" # tail
+ "41 41 commandseparator" # |
+ "43 46 command" # head
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob-alias.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob-alias.zsh
new file mode 100644
index 00000000..2f96445e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob-alias.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias x=command
+BUFFER='x ls'
+
+expected_region_highlight=(
+ "1 1 alias" # x
+ "3 4 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob-always.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob-always.zsh
new file mode 100644
index 00000000..6d550489
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob-always.zsh
@@ -0,0 +1,45 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'{ noglob echo * } always { echo * }'
+
+expected_region_highlight=(
+ '1 1 reserved-word' # {
+ '3 8 precommand' # noglob
+ '10 13 builtin' # echo
+ '15 15 default' # *
+ '17 17 reserved-word' # }
+ '19 24 reserved-word' # always
+ '26 26 reserved-word' # {
+ '28 31 builtin' # echo
+ '33 33 default' # *
+ '33 33 globbing' # *
+ '35 35 reserved-word' # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob1.zsh
new file mode 100644
index 00000000..1857db0c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob1.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=':; noglob echo *'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "2 2 commandseparator" # ;
+ "4 9 precommand" # noglob
+ "11 14 builtin" # echo
+ "16 16 default" # *
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob2.zsh
new file mode 100644
index 00000000..3b4fcd76
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob2.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='noglob echo *; echo *'
+
+expected_region_highlight=(
+ "1 6 precommand" # noglob
+ "8 11 builtin" # echo
+ "13 13 default" # *
+ "14 14 commandseparator" # ;
+ "16 19 builtin" # echo
+ "21 21 default" # *
+ "21 21 globbing" # *
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob3.zsh
new file mode 100644
index 00000000..c404aaac
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob3.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+touch \*
+
+BUFFER='noglob echo *'
+
+expected_region_highlight=(
+ "1 6 precommand" # noglob
+ "8 11 builtin" # echo
+ "13 13 path" # *
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob4.zsh
new file mode 100644
index 00000000..cc7065f5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/noglob4.zsh
@@ -0,0 +1,45 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'noglob cat <(print -r -- *)'
+
+expected_region_highlight=(
+ '1 6 precommand' # noglob
+ '8 10 command' # cat
+ '12 27 default' # <(print -r -- *)
+ '12 27 process-substitution' # <(print -r -- *)
+ '12 13 process-substitution-delimiter' # <(
+ '14 18 builtin' # print
+ '20 21 single-hyphen-option' # -r
+ '23 24 double-hyphen-option' # --
+ '26 26 default' # *
+ '26 26 globbing' # *
+ '27 27 process-substitution-delimiter' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/null-exec.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/null-exec.zsh
new file mode 100644
index 00000000..be1e3064
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/null-exec.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'exec >/dev/null;'
+
+expected_region_highlight=(
+ '1 4 precommand' # exec
+ '6 6 redirection' # >
+ '7 15 path' # /dev/null
+ '16 16 commandseparator' # ;
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/null-exec2-printenv.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/null-exec2-printenv.zsh
new file mode 100644
index 00000000..59a2cef7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/null-exec2-printenv.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2021 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'env | grep $needle'
+
+expected_region_highlight=(
+ '1 3 precommand' # env
+ '5 5 commandseparator' # |
+ '7 10 command' # grep
+ '12 18 default' # $needle
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/number_range-glob.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/number_range-glob.zsh
new file mode 100644
index 00000000..c8409510
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/number_range-glob.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='print <-> x<->y <foo2-3>'
+
+expected_region_highlight=(
+ '1 5 builtin' # print
+ '7 9 default' # <->
+ '7 9 globbing' # <->
+ '11 15 default' # x<->y
+ '12 14 globbing' # <->
+ '17 17 redirection' # <
+ '18 23 default' # foo2-3 (the filename)
+ '24 24 redirection' # >
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/off-by-one.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/off-by-one.zsh
new file mode 100644
index 00000000..872143af
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/off-by-one.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+alias a=:
+f() {}
+
+BUFFER='a;f;'
+
+expected_region_highlight=(
+ "1 1 alias" # a
+ "2 2 commandseparator" # ;
+ "3 3 function" # f
+ "4 4 commandseparator" # ;
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/opt-shwordsplit1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/opt-shwordsplit1.zsh
new file mode 100644
index 00000000..4a7689be
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/opt-shwordsplit1.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt shwordsplit
+local EDITOR='ed -s'
+
+ed() { command ed "$@" }
+
+BUFFER=$'$EDITOR'
+
+expected_region_highlight=(
+ '1 7 function' # $EDITOR
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/optimized-cmdsubst-input.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/optimized-cmdsubst-input.zsh
new file mode 100644
index 00000000..ca55ef83
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/optimized-cmdsubst-input.zsh
@@ -0,0 +1,43 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# See getoutput() and getoutputfile() in zsh's C source code.
+
+BUFFER=$': $(<*)'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 7 default' # $(<*)
+ '3 7 command-substitution-unquoted' # $(<*)
+ '3 4 command-substitution-delimiter-unquoted' # $(
+ '5 5 redirection' # <
+ '6 6 default' # * - not globbing!
+ '7 7 command-substitution-delimiter-unquoted' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-dollar-quote-isnt-filename.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-dollar-quote-isnt-filename.zsh
new file mode 100644
index 00000000..897a02e6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-dollar-quote-isnt-filename.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': -$\'n\''
+
+touch ./-n
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 7 single-hyphen-option' # -$'n'
+ '4 7 dollar-quoted-argument' # $'n'
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-path_dirs.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-path_dirs.zsh
new file mode 100644
index 00000000..0300c7e5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-path_dirs.zsh
@@ -0,0 +1,44 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+if [[ $OSTYPE == msys ]]; then
+ skip_test='Cannot chmod +x in msys2'
+else
+ setopt PATH_DIRS
+ mkdir -p foo/bar
+ touch foo/bar/testing-issue-228
+ chmod +x foo/bar/testing-issue-228
+ path+=( "$PWD"/foo )
+
+ BUFFER='bar/testing-issue-228'
+
+ expected_region_highlight=(
+ "1 21 command" # bar/testing-issue-228
+ )
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-with-quotes.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-with-quotes.zsh
new file mode 100644
index 00000000..6286f034
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/option-with-quotes.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': --user="phy1729"'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 18 double-hyphen-option' # --user="phy1729"
+ '10 18 double-quoted-argument' # "phy1729"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/order-path-after-dollar.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/order-path-after-dollar.zsh
new file mode 100644
index 00000000..773c1838
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/order-path-after-dollar.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+touch '$foo'
+BUFFER=': $foo \$foo'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 6 default' # $foo - if we add a "unquoted parameter expansion" style then this expectation should change
+ '8 12 path' # \$foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/order-path-before-globbing.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/order-path-before-globbing.zsh
new file mode 100644
index 00000000..8456b181
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/order-path-before-globbing.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+touch '*'
+BUFFER=': * \*'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 3 default' # *
+ '3 3 globbing' # *
+ '5 6 path' # \*
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-positional-in-array-append.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-positional-in-array-append.zsh
new file mode 100644
index 00000000..bd39e021
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-positional-in-array-append.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# This used to be an infinite loop.
+
+BUFFER=$'l+=( $1'
+
+expected_region_highlight=(
+ '1 4 assign' # l+=(
+ '4 4 reserved-word' # (
+ '6 7 default' # $1
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-precommand-option-argument1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-precommand-option-argument1.zsh
new file mode 100644
index 00000000..84cf03ac
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-precommand-option-argument1.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# See also alias-precommand-option-argument1.zsh
+local -a sudo_u; sudo_u=(sudo -u)
+sudo(){}
+
+BUFFER='$sudo_u phy1729 echo foo'
+
+expected_region_highlight=(
+ '1 7 precommand' # $sudo_u
+ '9 15 default' # phy1729
+ '18 20 command "issue #540"' # echo (not builtin)
+ '22 24 default' # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-precommand-option-argument3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-precommand-option-argument3.zsh
new file mode 100644
index 00000000..9a8dde28
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/param-precommand-option-argument3.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# See also alias-precommand-option-argument3.zsh
+local -a sudo_u; sudo_u=(sudo -u)
+sudo(){}
+
+BUFFER='$sudo_u phy1729 ls foo'
+
+expected_region_highlight=(
+ '1 7 precommand' # sudo_u
+ '9 15 default' # phy1729
+ '17 18 command' # ls
+ '20 22 default' # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-elision-command-word.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-elision-command-word.zsh
new file mode 100644
index 00000000..25f649a2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-elision-command-word.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='$x ls'
+
+expected_region_highlight=(
+ '1 2 comment' # $x
+ '4 5 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-shwordsplit.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-shwordsplit.zsh
new file mode 100644
index 00000000..0bf6f4c0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-shwordsplit.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2021 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt sh_word_split
+local foo='echo foo'
+
+BUFFER='$foo'
+
+expected_region_highlight=(
+ '1 4 builtin' # $foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-untokenized1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-untokenized1.zsh
new file mode 100644
index 00000000..8b8b5e4c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-untokenized1.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+local x="()"
+
+BUFFER=$'$x ls'
+
+expected_region_highlight=(
+ '1 2 unknown-token' # $x
+ '4 5 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-untokenized2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-untokenized2.zsh
new file mode 100644
index 00000000..d23a1f21
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-expansion-untokenized2.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+local x="^foo^bar"
+
+BUFFER=$'$x ls'
+
+expected_region_highlight=(
+ '1 2 unknown-token' # $x
+ '4 5 default' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-star.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-star.zsh
new file mode 100644
index 00000000..2311be07
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-star.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='() { : $* }'
+
+# This tests that $* isn't highlighted as a glob.
+# If we ever add a "unquoted parameter" style, the expectation may change.
+expected_region_highlight=(
+ "1 2 reserved-word" # ()
+ "4 4 reserved-word" # {
+ "6 6 builtin" # :
+ "8 9 default" # $*
+ "11 11 reserved-word" # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-to-global-alias.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-to-global-alias.zsh
new file mode 100644
index 00000000..cd2283bf
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-to-global-alias.zsh
@@ -0,0 +1,42 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+if type x >/dev/null; then
+ skip_test="Test is written on the assumption that 'x' is not a valid command name, but that assumption does not hold"
+ return 0
+fi
+alias -g x=y
+local s=x
+
+BUFFER=$'$s'
+
+expected_region_highlight=(
+ '1 2 unknown-token' # $s
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-value-contains-command-position1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-value-contains-command-position1.zsh
new file mode 100644
index 00000000..05ea1bfa
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-value-contains-command-position1.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+local foobar='x=$(ls)'
+
+BUFFER=$'$foobar'
+
+expected_region_highlight=(
+ # Used to highlight the "ba" as 'command' because the 'ls' showed through; issues #670 and #674
+ '1 7 unknown-token' # $foobar (not an assignment)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-value-contains-command-position2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-value-contains-command-position2.zsh
new file mode 100644
index 00000000..5042e899
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/parameter-value-contains-command-position2.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+local y='x=$(ls)'
+
+BUFFER=$'$y'
+
+expected_region_highlight=(
+ # Used to trigger a "BUG" message on stderr - issues #670 and #674
+ '1 2 unknown-token' # $y (not an assignment)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/pasted-quotes.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/pasted-quotes.zsh
new file mode 100644
index 00000000..f37f21b3
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/pasted-quotes.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2013 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': \'foo\'bar"baz"'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 15 default' # \'foo\'bar"baz"
+ '3 7 single-quoted-argument' # \'foo\'
+ '11 15 double-quoted-argument' # "baz"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-broken-symlink.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-broken-symlink.zsh
new file mode 100644
index 00000000..baebee36
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-broken-symlink.zsh
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+if [[ $OSTYPE == msys ]]; then
+ skip_test='Cannot create symlinks in msys2'
+else
+ ln -s /nonexistent broken-symlink
+ BUFFER=': broken-symlink'
+ CURSOR=5 # to make path_prefix ineligible
+
+ expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 16 path" # broken-symlink
+ )
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word.zsh
new file mode 100644
index 00000000..99055da9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word.zsh
@@ -0,0 +1,45 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+if [[ $OSTYPE == msys ]]; then
+ skip_test='Cannot chmod +x in msys2' # cargo culted from option-path_dirs.zsh
+else
+ mkdir kappa
+ touch kappa.exe
+ chmod +x kappa.exe
+ cd kappa
+
+ BUFFER='$PWD.exe; ${PWD}.exe'
+
+ expected_region_highlight=(
+ "1 8 unknown-token" # $PWD.exe - not eval'd; issue #328
+ "9 9 commandseparator" # ;
+ "11 20 unknown-token" # ${PWD}.exe
+ )
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word2.zsh
new file mode 100644
index 00000000..f404d5d0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word2.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+local lambda="''"
+touch \$lambda
+BUFFER=': \$lambda'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 10 path" # \$lambda
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word3.zsh
new file mode 100644
index 00000000..ec981b1e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word3.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# «/usr» at this point would be highlighted as path_prefix; so should
+# a parameter that expands to an equivalent string be highlighted.
+#
+# More complicated parameter substitutions aren't eval'd; issue #328.
+BUFFER='$PWD; ${PWD}'
+
+expected_region_highlight=(
+ "1 4 unknown-token" # $PWD (without AUTO_CD)
+ "5 5 commandseparator" # ;
+ "7 12 path_prefix" # ${PWD}
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word3b.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word3b.zsh
new file mode 100644
index 00000000..72a2f7c4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word3b.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt autocd
+BUFFER=$'$PWD; ${PWD}'
+
+expected_region_highlight=(
+ '1 4 autodirectory' # $PWD
+ '5 5 commandseparator' # ;
+ '7 12 autodirectory' # ${PWD}
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word4.zsh
new file mode 100644
index 00000000..e29182cc
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-dollared-word4.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# This tests for a regression during development of issue #328: an interim version
+# of that branch failed that test with "Bail out! output on stderr".
+BUFFER='${'
+
+expected_region_highlight=(
+ "1 2 unknown-token" # ${
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-mixed-quoting.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-mixed-quoting.zsh
new file mode 100644
index 00000000..cbd0b38e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-mixed-quoting.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+touch foo
+
+BUFFER=$': \'f\'oo'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 7 path' # \'f\'oo
+ '3 5 single-quoted-argument' # \'f\'
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-separators.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-separators.zsh
new file mode 100644
index 00000000..52749b79
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-separators.zsh
@@ -0,0 +1,53 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# ZSH_HIGHLIGHT_STYLES is empty in tests. The path-separator code however compares its values.
+# Make sure the relevant ones are set to something.
+ZSH_HIGHLIGHT_STYLES[path_pathseparator]=set
+ZSH_HIGHLIGHT_STYLES[path_prefix_pathseparator]=set
+
+mkdir A
+touch A/mu
+BUFFER='ls /bin/ / A/mu A/m'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 8 path" # /bin/
+ "4 4 path_pathseparator" # /
+ "8 8 path_pathseparator" # /
+
+ "10 10 path" # /
+ "10 10 path_pathseparator" # /
+
+ "12 15 path" # A/mu
+ "13 13 path_pathseparator" # /
+
+ "17 19 path_prefix" # A/m
+ "18 18 path_prefix_pathseparator" # /
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-separators2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-separators2.zsh
new file mode 100644
index 00000000..bc885a06
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-separators2.zsh
@@ -0,0 +1,40 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# ZSH_HIGHLIGHT_STYLES is empty in tests. The path-separator code however compares its values.
+# For this test, make sure both these styles are set and identical:
+ZSH_HIGHLIGHT_STYLES[path]=value
+ZSH_HIGHLIGHT_STYLES[path_pathseparator]=value
+
+BUFFER='ls /bin/'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 8 path" # /bin/
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-space.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-space.zsh
new file mode 100644
index 00000000..87cc22f9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-space.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+mkdir A
+touch "A/mu with spaces"
+BUFFER='ls A/mu\ with\ spaces'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 21 path" # A/mu\ with\ spaces
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home.zsh
new file mode 100644
index 00000000..8b1c6805
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+HOME="."
+BUFFER='ls ~'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 4 path" # ~
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home2.zsh
new file mode 100644
index 00000000..3f7b8200
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home2.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+HOME="/nonexistent"
+BUFFER='ls ~'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 4 default" # ~
+)
+
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home3.zsh
new file mode 100644
index 00000000..5c076e88
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-home3.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+HOME="."
+BUFFER='ls \~'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 5 default" # \~
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-named.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-named.zsh
new file mode 100644
index 00000000..335b3fdf
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path-tilde-named.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+mkdir mydir
+touch mydir/path-tilde-named.test
+hash -d D=mydir
+
+BUFFER='ls ~D/path-tilde-named.test'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 27 path" # ~D/path-tilde-named.test
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path.zsh
new file mode 100644
index 00000000..d387eff3
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+mkdir A
+touch A/mu
+BUFFER='ls A/mu'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 7 path" # A/mu
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix.zsh
new file mode 100644
index 00000000..3303bfb4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Assumes that '/bin/sh' exists and '/bin/s' does not exist.
+# Related to path_prefix2.zsh
+
+BUFFER='ls /bin/s'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 9 path_prefix" # /bin/s
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix2.zsh
new file mode 100644
index 00000000..4f40f7e9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix2.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Assumes that '/bin/sh' exists and '/bin/s' does not exist.
+# Related to path_prefix.zsh
+
+BUFFER='ls /bin/s'
+WIDGET=zle-line-finish
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 9 default" # /bin/s
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix3.zsh
new file mode 100644
index 00000000..9f34f943
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/path_prefix3.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Assumes that '/bin/sh' exists and '/bin/s' does not exist.
+# Related to path_prefix.zsh
+
+PREBUFFER=$'ls \\\n'
+BUFFER='/bin/s'
+
+expected_region_highlight=(
+ '1 6 path_prefix' # /bin/s
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/plain-file-in-command-position.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/plain-file-in-command-position.zsh
new file mode 100644
index 00000000..141fface
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/plain-file-in-command-position.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+touch foo
+chmod -x foo
+BUFFER=$'./foo; ./foo'
+
+expected_region_highlight=(
+ '1 5 unknown-token' # ./foo (in middle)
+ '6 6 commandseparator' # ;
+ '8 12 unknown-token' # ./foo (at end)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-killing1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-killing1.zsh
new file mode 100644
index 00000000..75983460
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-killing1.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+hash sudo=false
+touch foo
+
+BUFFER='sudo -e ./foo'
+
+expected_region_highlight=(
+ '1 4 precommand' # sudo
+ '6 7 single-hyphen-option' # -e
+ '9 13 path' # ./foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-killing2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-killing2.zsh
new file mode 100644
index 00000000..bc6fc866
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-killing2.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+hash sudo=false
+
+BUFFER='sudo -e /does/not/exist'
+
+expected_region_highlight=(
+ '1 4 precommand' # sudo
+ '6 7 single-hyphen-option' # -e
+ '9 23 default' # /does/not/exist
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-then-assignment.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-then-assignment.zsh
new file mode 100644
index 00000000..f0bb75ff
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-then-assignment.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'nice x=y ls'
+
+expected_region_highlight=(
+ '1 4 precommand' # nice
+ '6 8 unknown-token "issue #641.5"' # x=y
+ '10 11 default "issue #641.5 (fallout)"' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type1.zsh
new file mode 100644
index 00000000..4ce817c2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type1.zsh
@@ -0,0 +1,61 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Test the behaviour of a builtin that exists as a command as well.
+# The spaces in $BUFFER are to align precommand-type*.zsh test files.
+BUFFER=$'test ; builtin test ; builtin command test ; nice test '
+
+# Our expectations assumes that a 'test' external command exists (in addition
+# to the 'test' builtin). Let's verify that, using the EQUALS option (which
+# is on by default). If there's no 'test' command, the expansion will fail,
+# diagnose a message on stdout, and the harness will detect a failure.
+#
+# This seems to work on all platforms, insofar as no one ever reported a bug
+# about their system not having a 'test' binary in PATH. That said, if someone
+# ever does see this test fail for this reason, we should explicitly create
+# a 'test' executable in cwd and 'rehash'.
+: =test
+
+expected_region_highlight=(
+ '1 4 builtin' # test
+ '7 7 commandseparator' # ;
+
+ '9 15 precommand' # builtin
+ '17 20 builtin' # test
+ '23 23 commandseparator' # ;
+
+ '25 31 precommand' # builtin
+ '33 39 precommand' # command
+ '41 44 command "issue #608"' # test
+ '47 47 commandseparator' # ;
+
+ '49 52 precommand' # nice
+ '54 57 command "issue #608"' # test
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type2.zsh
new file mode 100644
index 00000000..bf75f4b5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type2.zsh
@@ -0,0 +1,55 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Test the behaviour of a builtin that does not exist as a command.
+# The spaces in $BUFFER are to align precommand-type*.zsh test files.
+BUFFER=$'zstyle; builtin zstyle; builtin command zstyle; nice zstyle'
+
+# Verify that no $^path/zstyle(N) binary exists.
+if (disable zstyle; type zstyle >/dev/null); then
+ echo >&2 "precommand-type2: error: 'zstyle' exists not only as a builtin"
+fi
+
+expected_region_highlight=(
+ '1 6 builtin' # zstyle
+ '7 7 commandseparator' # ;
+
+ '9 15 precommand' # builtin
+ '17 22 builtin' # zstyle
+ '23 23 commandseparator' # ;
+
+ '25 31 precommand' # builtin
+ '33 39 precommand' # command
+ '41 46 unknown-token "issue #608"' # zstyle
+ '47 47 commandseparator' # ;
+
+ '49 52 precommand' # nice
+ '54 59 unknown-token "issue #608"' # zstyle
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type3.zsh
new file mode 100644
index 00000000..7fc7e4c5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-type3.zsh
@@ -0,0 +1,55 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Test an external command that does not exist as a builtin.
+# The spaces in $BUFFER are to align precommand-type*.zsh test files.
+BUFFER=$'ls ; builtin ls ; builtin command ls ; nice ls '
+
+# Verify that the 'ls' command isn't shadowed.
+if [[ $(type -w ls) != "ls: command" ]]; then
+ echo >&2 "precommand-type3: error: the 'ls' command is shadowed (or possibly missing altogether)"
+fi
+
+expected_region_highlight=(
+ '1 2 command' # ls
+ '7 7 commandseparator' # ;
+
+ '9 15 precommand' # builtin
+ '17 18 unknown-token "issue #608"' # ls
+ '23 23 commandseparator' # ;
+
+ '25 31 precommand' # builtin
+ '33 39 precommand' # command
+ '41 42 command' # ls
+ '47 47 commandseparator' # ;
+
+ '49 52 precommand' # nice
+ '54 55 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-uninstalled.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-uninstalled.zsh
new file mode 100644
index 00000000..03c8a75a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-uninstalled.zsh
@@ -0,0 +1,44 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Simulate sudo not being installed.
+#
+# The 'hash' step is because, if sudo _really_ isn't installed, 'unhash sudo'
+# would error out and break the test.
+hash sudo=/usr/bin/env && unhash sudo
+
+local PATH
+
+BUFFER=$'sudo ls'
+
+expected_region_highlight=(
+ '1 4 unknown-token' # sudo
+ '6 7 default' # ls - not 'command', since sudo isn't installed
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-unknown-option.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-unknown-option.zsh
new file mode 100644
index 00000000..6baf9ff5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand-unknown-option.zsh
@@ -0,0 +1,43 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+sudo(){}
+
+BUFFER='sudo -ux ls; sudo -x ls'
+
+expected_region_highlight=(
+ '1 4 precommand' # sudo
+ '6 8 single-hyphen-option' # -ux
+ '10 11 command' # ls
+ '12 12 commandseparator' # ;
+ '14 17 precommand' # sudo
+ '19 20 single-hyphen-option' # -x
+ '22 23 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand.zsh
new file mode 100644
index 00000000..a03b3317
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': command zzzzzz'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 9 default" # not precommand
+ "11 16 default" # not unknown-token (since 'zzzzzz' is not a command)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand2.zsh
new file mode 100644
index 00000000..75dceabe
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand2.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='command -v ls'
+
+expected_region_highlight=(
+ "1 7 precommand" # command
+ "9 10 single-hyphen-option" # -v
+ "12 13 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand3.zsh
new file mode 100644
index 00000000..f8b0c780
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand3.zsh
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='nice -n10 ls; nice -n 10 ls'
+
+expected_region_highlight=(
+ "1 4 precommand" # nice
+ "6 9 single-hyphen-option" # -n10
+ "11 12 command" # ls
+ "13 13 commandseparator" # ;
+ "15 18 precommand" # nice
+ "20 21 single-hyphen-option" # -n
+ "23 24 default" # 10
+ "26 27 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand4.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand4.zsh
new file mode 100644
index 00000000..b9e6119d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/precommand4.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+doas(){}
+BUFFER=$'doas -nu phy1729 ls'
+
+expected_region_highlight=(
+ '1 4 precommand' # doas
+ '6 8 single-hyphen-option' # -nu
+ '10 16 default' # phy1729
+ '18 19 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/prefix-redirection.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/prefix-redirection.zsh
new file mode 100644
index 00000000..a0f0ed5a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/prefix-redirection.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='>/tmp >/tmp command echo >/tmp foo'
+
+expected_region_highlight=(
+ "1 1 redirection" # >
+ "2 5 path" # /tmp
+ "7 7 redirection" # >
+ "8 11 path" # /tmp
+ "13 19 precommand" # command
+ "21 24 builtin" # echo
+ "26 26 redirection" # >
+ "27 30 path" # /tmp
+ "32 34 default" # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution-after-redirection.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution-after-redirection.zsh
new file mode 100644
index 00000000..2d58016f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution-after-redirection.zsh
@@ -0,0 +1,46 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017, 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'< <(pwd) > >(nl)'
+
+expected_region_highlight=(
+ '1 1 redirection' # <
+ '3 8 default' # <(pwd)
+ '3 8 process-substitution' # <(pwd)
+ '3 4 process-substitution-delimiter' # <(
+ '5 7 builtin' # pwd
+ '8 8 process-substitution-delimiter' # )
+ '10 10 redirection' # >
+ '12 16 default' # >(nl)
+ '12 16 process-substitution' # >(nl)
+ '12 13 process-substitution-delimiter' # >(
+ '14 15 command' # nl
+ '16 16 process-substitution-delimiter' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution-redirection-isnt-globbing.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution-redirection-isnt-globbing.zsh
new file mode 100644
index 00000000..f8dbd6ba
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution-redirection-isnt-globbing.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': =(<foo)'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 9 default' # =(<foo)
+ '3 9 process-substitution' # =(<foo)
+ '3 4 process-substitution-delimiter' # =(
+ '5 5 redirection' # <foo
+ '6 8 default' # foo
+ '9 9 process-substitution-delimiter' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution.zsh
new file mode 100644
index 00000000..26600347
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution.zsh
@@ -0,0 +1,43 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': --foo=<(echo bar) "<(:)"'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 19 double-hyphen-option' # --foo=<(echo bar)
+ '9 19 process-substitution' # <(echo bar)
+ '9 10 process-substitution-delimiter' # <(
+ '11 14 builtin' # echo
+ '16 18 default' # bar
+ '19 19 process-substitution-delimiter' # )
+ '21 26 default' # "<(:)"
+ '21 26 double-quoted-argument' # "<(:)"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution2.zsh
new file mode 100644
index 00000000..cc550902
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/process-substitution2.zsh
@@ -0,0 +1,51 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo =(:) a=(:) =(echo foo'
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 9 default' # =(:)
+ '6 9 process-substitution' # =(:)
+ '6 7 process-substitution-delimiter' # =(
+ '8 8 builtin' # :
+ '9 9 process-substitution-delimiter' # )
+ '11 15 default' # a=(:)
+ '17 26 default' # =(echo foo
+ '17 26 process-substitution' # =(echo foo
+ '17 18 process-substitution-delimiter' # =(
+ '19 22 builtin' # echo
+ '24 26 default' # foo
+)
+
+if [[ ${(z):-'$('} == '$( ' ]]; then # ignore zsh 5.0.8 bug
+ expected_region_highlight[8]='17 27 default' # =(echo foo
+ expected_region_highlight[9]='17 27 process-substitution' # =(echo foo
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/quoted-command-substitution-empty.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/quoted-command-substitution-empty.zsh
new file mode 100644
index 00000000..daf3738b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/quoted-command-substitution-empty.zsh
@@ -0,0 +1,44 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='echo "foo$( '
+
+expected_region_highlight=(
+ '1 4 builtin' # echo
+ '6 12 default' # "foo$(
+ '6 9 double-quoted-argument-unclosed' # "foo
+ '10 12 command-substitution-quoted' # $(
+ '10 11 command-substitution-delimiter-quoted' # $(
+)
+
+if [[ ${(z):-'$('} == '$( ' ]]; then # ignore zsh 5.0.8 bug
+ expected_region_highlight[2]='6 13 default' # "foo$(
+ expected_region_highlight[4]='10 13 command-substitution-quoted' # $(
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/quoted-redirection-in-command-word.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/quoted-redirection-in-command-word.zsh
new file mode 100644
index 00000000..b1a79e10
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/quoted-redirection-in-command-word.zsh
@@ -0,0 +1,37 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'">" foo ls'
+
+expected_region_highlight=(
+ '1 3 unknown-token' # ">" - not "redirection"
+ '5 7 default' # foo
+ '9 10 default' # ls - not "command"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/rc-quotes.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/rc-quotes.zsh
new file mode 100644
index 00000000..8cd427ae
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/rc-quotes.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt RC_QUOTES
+
+BUFFER=": 'foo''bar'baz"
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 15 default" # 'foo''bar'baz
+ "3 12 single-quoted-argument" # 'foo''bar'
+ "7 8 rc-quote" # ''
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-comment.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-comment.zsh
new file mode 100644
index 00000000..a019100c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-comment.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+setopt interactive_comments
+
+BUFFER=': <<#foo'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 4 redirection" # <<
+ "5 8 comment" # #foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-from-param.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-from-param.zsh
new file mode 100644
index 00000000..42ae6380
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-from-param.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+touch file
+local fn=$PWD/file
+
+BUFFER=$'<$fn cat'
+
+expected_region_highlight=(
+ '1 1 redirection' # <
+ '2 4 path' # $fn
+ '6 8 command' # cat
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-in-cmdsubst.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-in-cmdsubst.zsh
new file mode 100644
index 00000000..ed5eaef8
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-in-cmdsubst.zsh
@@ -0,0 +1,41 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': $(<foo)'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 9 default' # $(<foo)
+ '3 9 command-substitution-unquoted' # $(<foo)
+ '3 4 command-substitution-delimiter-unquoted' # $(
+ '5 5 redirection' # <
+ '6 8 default' # foo
+ '9 9 command-substitution-delimiter-unquoted' # )
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-inhibits-elision.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-inhibits-elision.zsh
new file mode 100644
index 00000000..c0ca2674
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-inhibits-elision.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'<$foo cat cat'
+
+expected_region_highlight=(
+ '1 1 redirection' # <
+ '2 5 default' # $foo
+ '7 9 command' # cat
+ '11 13 default' # cat
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-is-not-option.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-is-not-option.zsh
new file mode 100644
index 00000000..671f21e7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-is-not-option.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$': > -x >> --yy'
+
+expected_region_highlight=(
+ '1 1 builtin' # :
+ '3 3 redirection' # >
+ '5 6 default' # -x
+ '8 9 redirection' # >>
+ '11 14 default' # --yy
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-special-cases.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-special-cases.zsh
new file mode 100644
index 00000000..733cf6bd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection-special-cases.zsh
@@ -0,0 +1,44 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# See xpandredir() in the zsh source.
+
+BUFFER=$'cat <&p; exec {myfd}>&-'
+
+expected_region_highlight=(
+ '1 3 command' # cat
+ '5 6 redirection' # <&
+ '7 7 redirection' # p
+ '8 8 commandseparator' # ;
+ '10 13 precommand' # exec
+ '15 20 named-fd' # {myfd}
+ '21 22 redirection' # >&
+ '23 23 redirection' # -
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection.zsh
new file mode 100644
index 00000000..6a25971a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Redirection before and after the command word are implemented differently; test both.
+BUFFER='<<<foo echo >>&!bar'
+
+expected_region_highlight=(
+ "1 3 redirection" # <<<
+ "4 6 default" # foo
+ "8 11 builtin" # echo
+ "13 16 redirection" # >>&!
+ "17 19 default" # bar
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection2.zsh
new file mode 100644
index 00000000..d44c8e7a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection2.zsh
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='ls >(wc) | nl'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+ "4 8 default" # >(wc)
+ "4 8 process-substitution" # >(wc)
+ "4 5 process-substitution-delimiter" # >(
+ "6 7 command" # wc
+ "8 8 process-substitution-delimiter" # )
+ "10 10 commandseparator" # |
+ "12 13 command" # nl
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection3.zsh
new file mode 100644
index 00000000..bf062cfb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/redirection3.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=': >>>; : <>\<<<<EOF'
+
+expected_region_highlight=(
+ "1 1 builtin" # :
+ "3 4 redirection" # >>
+ "5 5 unknown-token" # >
+ "6 6 commandseparator" # ;
+ "8 8 builtin" # :
+ "10 11 redirection" # <>
+ "12 13 default" # \<
+ "14 16 redirection" # <<<
+ "17 19 default" # EOF
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/reserved-word.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/reserved-word.zsh
new file mode 100644
index 00000000..aca3796d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/reserved-word.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='repeat "1" do done'
+
+expected_region_highlight=(
+ "1 6 reserved-word" # repeat
+ "8 10 default" # "1"
+ "8 10 double-quoted-argument" # "1"
+ "12 13 reserved-word" # do
+ "15 18 reserved-word" # done
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/simple-command.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/simple-command.zsh
new file mode 100644
index 00000000..8bb41fd0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/simple-command.zsh
@@ -0,0 +1,34 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='ls'
+
+expected_region_highlight=(
+ "1 2 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/simple-redirection.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/simple-redirection.zsh
new file mode 100644
index 00000000..e8c25e55
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/simple-redirection.zsh
@@ -0,0 +1,38 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='ps aux | grep java'
+
+expected_region_highlight=(
+ "1 2 command" # ps
+ "4 6 default" # aux
+ "8 8 commandseparator" # |
+ "10 13 command" # grep
+ "15 18 default" # java
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/subshell.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/subshell.zsh
new file mode 100644
index 00000000..c068013e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/subshell.zsh
@@ -0,0 +1,51 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='tar cf - * | (cd /target; tar xfp -) | { cat }'
+
+expected_region_highlight=(
+ "1 3 command" # tar
+ "5 6 default" # cf
+ "8 8 single-hyphen-option" # -
+ "10 10 default" # *
+ "10 10 globbing" # *
+ "12 12 commandseparator" # |
+ "14 14 reserved-word" # (
+ "15 16 builtin" # cd
+ "18 24 default" # /target
+ "25 25 commandseparator" # ;
+ "27 29 command" # tar
+ "31 33 default" # xfp
+ "35 35 single-hyphen-option" # -
+ "36 36 reserved-word" # )
+ "38 38 commandseparator" # |
+ "40 40 reserved-word" # {
+ "42 44 command" # cat
+ "46 46 reserved-word" # }
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-command.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-command.zsh
new file mode 100644
index 00000000..941349a0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-command.zsh
@@ -0,0 +1,54 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+sudo(){}
+
+# Tests three codepaths:
+# * -i (no argument)
+# * -C3 (pasted argument)
+# * -u otheruser (non-pasted argument)
+BUFFER='sudo -C3 -u otheruser -i ls /; sudo ; sudo -u ; sudo notacommand'
+
+expected_region_highlight=(
+ "1 4 precommand" # sudo
+ "6 8 single-hyphen-option" # -C3
+ "10 11 single-hyphen-option" # -u
+ "13 21 default" # otheruser
+ "23 24 single-hyphen-option" # -i
+ "26 27 command" # ls
+ "29 29 path" # /
+ "30 30 commandseparator" # ;
+ "32 35 precommand" # sudo
+ "37 37 unknown-token" # ;, error because empty command
+ "39 42 precommand" # sudo
+ "44 45 single-hyphen-option" # -u
+ "47 47 unknown-token" # ;, error because incomplete command
+ "49 52 precommand" # sudo
+ "54 64 unknown-token" # notacommand - doesn't falls back to "not a command word" codepath
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-comment.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-comment.zsh
new file mode 100644
index 00000000..74cd905a
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-comment.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+sudo(){}
+
+setopt interactive_comments
+BUFFER='sudo -u # comment'
+
+expected_region_highlight=(
+ "1 4 precommand" # sudo
+ "6 7 single-hyphen-option" # -u
+ "9 17 unknown-token" # "# comment" - error because argument missed
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-longopt.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-longopt.zsh
new file mode 100644
index 00000000..ef768bfb
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-longopt.zsh
@@ -0,0 +1,38 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+hash sudo='false'
+BUFFER='sudo --askpass ls'
+
+expected_region_highlight=(
+ '1 4 precommand' # sudo
+ '6 14 double-hyphen-option' # --askpass
+ '16 17 command' # ls (we don't know whether --askpass takes an argument)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection.zsh
new file mode 100644
index 00000000..c675d7d2
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection.zsh
@@ -0,0 +1,48 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+sudo(){}
+
+BUFFER='sudo -u >/tmp otheruser ls; sudo ls; sudo -i ls'
+
+expected_region_highlight=(
+ "1 4 precommand" # sudo
+ "6 7 single-hyphen-option" # -u
+ "9 9 redirection" # >
+ "10 13 path" # /tmp
+ "15 23 default" # otheruser
+ "25 26 command" # ls
+ "27 27 commandseparator" # ;
+ "29 32 precommand" # sudo
+ "34 35 command" # ls
+ "36 36 commandseparator" # ;
+ "38 41 precommand" # sudo
+ "43 44 single-hyphen-option" # -i
+ "46 47 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection2.zsh
new file mode 100644
index 00000000..23ada53c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection2.zsh
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+sudo(){}
+
+BUFFER='sudo >/tmp -u otheruser ls'
+
+expected_region_highlight=(
+ "1 4 precommand" # sudo
+ "6 6 redirection" # >
+ "7 10 path" # /tmp
+ "12 13 single-hyphen-option" # -u
+ "15 23 default" # otheruser
+ "25 26 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection3.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection3.zsh
new file mode 100644
index 00000000..80e55b55
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/sudo-redirection3.zsh
@@ -0,0 +1,41 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+sudo(){}
+
+BUFFER='sudo 2>./. -u otheruser ls'
+
+expected_region_highlight=(
+ "1 4 precommand" # sudo
+ "6 7 redirection" # 2>
+ "8 10 path" # ./. # a 3-character path, for alignment with sudo-redirection2.zsh
+ "12 13 single-hyphen-option" # -u
+ "15 23 default" # otheruser
+ "25 26 command" # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/tilde-command-word.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/tilde-command-word.zsh
new file mode 100644
index 00000000..67c996c9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/tilde-command-word.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+hash -d D=/usr/bin
+
+BUFFER='~D/env foo'
+
+expected_region_highlight=(
+ "1 6 command" # ~D/env [= /usr/bin/env
+ "8 10 default" # foo
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/time-and-nocorrect1.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/time-and-nocorrect1.zsh
new file mode 100644
index 00000000..fb398edf
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/time-and-nocorrect1.zsh
@@ -0,0 +1,39 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'time ls; nocorrect ls'
+
+expected_region_highlight=(
+ '1 4 reserved-word' # time
+ '6 7 command' # ls
+ '8 8 commandseparator' # ;
+ '10 18 reserved-word' # nocorrect
+ '20 21 command' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/time-and-nocorrect2.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/time-and-nocorrect2.zsh
new file mode 100644
index 00000000..5549ee92
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/time-and-nocorrect2.zsh
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2019 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER=$'time ls; nocorrect ls'
+alias time=':' nocorrect=':'
+
+expected_region_highlight=(
+ '1 4 alias' # time
+ '6 7 default' # ls
+ '8 8 commandseparator' # ;
+ '10 18 alias' # nocorrect
+ '20 21 default' # ls
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/unbackslash.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/unbackslash.zsh
new file mode 100644
index 00000000..c8dfbd4c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/unbackslash.zsh
@@ -0,0 +1,34 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='\sh'
+
+expected_region_highlight=(
+ "1 3 command" # \sh (runs 'sh', bypassing aliases)
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/unknown-command.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/unknown-command.zsh
new file mode 100644
index 00000000..e71faec5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/unknown-command.zsh
@@ -0,0 +1,34 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='azertyuiop'
+
+expected_region_highlight=(
+ "1 10 unknown-token" # azertyuiop
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/vanilla-newline.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/vanilla-newline.zsh
new file mode 100644
index 00000000..bd60ad4c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/vanilla-newline.zsh
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+PREBUFFER=$'echo foo; echo bar\n\n\n'
+BUFFER=' echo baz; echo qux'
+
+expected_region_highlight=(
+ "2 5 builtin" # echo
+ "7 9 default" # baz
+ "10 10 commandseparator" # semicolon
+ "12 15 builtin" # echo
+ "17 19 default" # qux
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/vi-linewise-mode.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/vi-linewise-mode.zsh
new file mode 100644
index 00000000..7003c49c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/main/test-data/vi-linewise-mode.zsh
@@ -0,0 +1,43 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# See issue #267 for the magic numbers
+BUFFER=$'foo foo\nbar bar'
+REGION_ACTIVE=2
+CURSOR=4
+MARK=12
+
+expected_region_highlight=(
+ "1 3 unknown-token" # foo
+ "5 7 default" # foo
+ "8 8 commandseparator" # \n
+ "9 11 unknown-token" # bar
+ "13 15 default" # bar
+ "1 15 standout" # foo foo\nbar bar
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/README.md
new file mode 120000
index 00000000..5ff00e64
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/README.md
@@ -0,0 +1 @@
+../../docs/highlighters/pattern.md \ No newline at end of file
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/pattern-highlighter.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/pattern-highlighter.zsh
new file mode 100644
index 00000000..e0422d08
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/pattern-highlighter.zsh
@@ -0,0 +1,60 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+
+# List of keyword and color pairs.
+typeset -gA ZSH_HIGHLIGHT_PATTERNS
+
+# Whether the pattern highlighter should be called or not.
+_zsh_highlight_highlighter_pattern_predicate()
+{
+ _zsh_highlight_buffer_modified
+}
+
+# Pattern syntax highlighting function.
+_zsh_highlight_highlighter_pattern_paint()
+{
+ setopt localoptions extendedglob
+ local pattern
+ for pattern in ${(k)ZSH_HIGHLIGHT_PATTERNS}; do
+ _zsh_highlight_pattern_highlighter_loop "$BUFFER" "$pattern"
+ done
+}
+
+_zsh_highlight_pattern_highlighter_loop()
+{
+ # This does *not* do its job syntactically, sorry.
+ local buf="$1" pat="$2"
+ local -a match mbegin mend
+ local MATCH; integer MBEGIN MEND
+ if [[ "$buf" == (#b)(*)(${~pat})* ]]; then
+ region_highlight+=("$((mbegin[2] - 1)) $mend[2] $ZSH_HIGHLIGHT_PATTERNS[$pat], memo=zsh-syntax-highlighting")
+ "$0" "$match[1]" "$pat"; return $?
+ fi
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/test-data/rm-rf.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/test-data/rm-rf.zsh
new file mode 100644
index 00000000..2f769294
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/pattern/test-data/rm-rf.zsh
@@ -0,0 +1,36 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+ZSH_HIGHLIGHT_PATTERNS+=('rm -rf *' 'fg=white,bold,bg=red')
+
+BUFFER='rm -rf /'
+
+expected_region_highlight=(
+ "1 8 fg=white,bold,bg=red" # rm -rf /
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/README.md
new file mode 120000
index 00000000..9f2522d5
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/README.md
@@ -0,0 +1 @@
+../../docs/highlighters/regexp.md \ No newline at end of file
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/regexp-highlighter.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/regexp-highlighter.zsh
new file mode 100644
index 00000000..0d43aacd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/regexp-highlighter.zsh
@@ -0,0 +1,62 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+
+# List of keyword and color pairs.
+typeset -gA ZSH_HIGHLIGHT_REGEXP
+
+# Whether the pattern highlighter should be called or not.
+_zsh_highlight_highlighter_regexp_predicate()
+{
+ _zsh_highlight_buffer_modified
+}
+
+# Pattern syntax highlighting function.
+_zsh_highlight_highlighter_regexp_paint()
+{
+ setopt localoptions extendedglob
+ local pattern
+ for pattern in ${(k)ZSH_HIGHLIGHT_REGEXP}; do
+ _zsh_highlight_regexp_highlighter_loop "$BUFFER" "$pattern"
+ done
+}
+
+_zsh_highlight_regexp_highlighter_loop()
+{
+ local buf="$1" pat="$2"
+ integer OFFSET=0
+ local MATCH; integer MBEGIN MEND
+ local -a match mbegin mend
+ while true; do
+ [[ "$buf" =~ "$pat" ]] || return;
+ region_highlight+=("$((MBEGIN - 1 + OFFSET)) $((MEND + OFFSET)) $ZSH_HIGHLIGHT_REGEXP[$pat], memo=zsh-syntax-highlighting")
+ buf="$buf[$(($MEND+1)),-1]"
+ OFFSET=$((MEND+OFFSET));
+ done
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/complex.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/complex.zsh
new file mode 100644
index 00000000..4e0089b9
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/complex.zsh
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+ZSH_HIGHLIGHT_REGEXP+=('[0-9\+\-]+' 'fg=white,bold,bg=red')
+
+BUFFER='echo 1+9-3 7+2'
+
+expected_region_highlight=(
+ "6 10 fg=white,bold,bg=red"
+ "12 14 fg=white,bold,bg=red"
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/subexpression.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/subexpression.zsh
new file mode 100644
index 00000000..308cb413
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/subexpression.zsh
@@ -0,0 +1,36 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2018 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+BUFFER='ls foo'
+ZSH_HIGHLIGHT_REGEXP=('(^| )(ls|cd)($| )' 'fg=green')
+
+expected_region_highlight=(
+ '1 3 fg=green' # "ls "
+)
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/word-boundary.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/word-boundary.zsh
new file mode 100644
index 00000000..1f4f6665
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/regexp/test-data/word-boundary.zsh
@@ -0,0 +1,42 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+if zmodload zsh/pcre 2>/dev/null; then
+ setopt RE_MATCH_PCRE
+
+ ZSH_HIGHLIGHT_REGEXP+=('\bsudo\b' 'fg=white,bold,bg=red')
+
+ BUFFER='sudo ls'
+
+ expected_region_highlight=(
+ "1 4 fg=white,bold,bg=red"
+ )
+else
+ skip_test='Test requires zsh/pcre'
+fi
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/root/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/root/README.md
new file mode 120000
index 00000000..ca6799d6
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/root/README.md
@@ -0,0 +1 @@
+../../docs/highlighters/root.md \ No newline at end of file
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/root/root-highlighter.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/root/root-highlighter.zsh
new file mode 100644
index 00000000..3718c449
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/highlighters/root/root-highlighter.zsh
@@ -0,0 +1,44 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2011 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+
+# Define default styles.
+: ${ZSH_HIGHLIGHT_STYLES[root]:=standout}
+
+# Whether the root highlighter should be called or not.
+_zsh_highlight_highlighter_root_predicate()
+{
+ _zsh_highlight_buffer_modified
+}
+
+# root highlighting function.
+_zsh_highlight_highlighter_root_paint()
+{
+ if (( EUID == 0 )) { _zsh_highlight_add_highlight 0 $#BUFFER root }
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1-smaller.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1-smaller.png
new file mode 100644
index 00000000..768294c3
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1-smaller.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1.png
new file mode 100644
index 00000000..ea378d3e
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2-smaller.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2-smaller.png
new file mode 100644
index 00000000..8b5b1f8f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2-smaller.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2.png
new file mode 100644
index 00000000..ddcbfad7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3-smaller.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3-smaller.png
new file mode 100644
index 00000000..d6aaa7bd
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3-smaller.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3.png
new file mode 100644
index 00000000..7a0af887
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after4-smaller.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after4-smaller.png
new file mode 100644
index 00000000..fc946cf0
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after4-smaller.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1-smaller.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1-smaller.png
new file mode 100644
index 00000000..b29551ea
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1-smaller.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1.png
new file mode 100644
index 00000000..80c6f54f
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2-smaller.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2-smaller.png
new file mode 100644
index 00000000..991a716d
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2-smaller.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2.png
new file mode 100644
index 00000000..48cfc327
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3-smaller.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3-smaller.png
new file mode 100644
index 00000000..e525c6d4
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3-smaller.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3.png
new file mode 100644
index 00000000..40c36015
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before4-smaller.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before4-smaller.png
new file mode 100644
index 00000000..2dbd0588
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before4-smaller.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview-smaller.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview-smaller.png
new file mode 100644
index 00000000..6fb84d18
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview-smaller.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview.png b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview.png
new file mode 100644
index 00000000..545cc511
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview.png
Binary files differ
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/release.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/release.md
new file mode 100644
index 00000000..f8565e81
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/release.md
@@ -0,0 +1,21 @@
+# Release procedure (for developers):
+
+- Ensure every `is-at-least` invocation passes a stable zsh release's version number as the first argument
+- For minor (A.B.0) releases:
+ - Check whether the release uses any not-yet-released zsh features
+- Check open issues and outstanding pull requests
+- Confirm `make test` passes
+ - check with multiple zsh versions
+ (easiest to check GitHub Actions: https://github.com/zsh-users/zsh-syntax-highlighting/actions)
+- Update changelog.md
+ `tig --abbrev=12 --abbrev-commit 0.4.1..upstream/master`
+- Make sure there are no local commits and that `git status` is clean;
+ Remove `-dev` suffix from `./.version`;
+ Commit that using `git commit -m "Tag version $(<.version)." .version`;
+ Tag it using `git tag -s -m "Tag version $(<.version)" $(<.version)`;
+ Increment `./.version` and restore the `-dev` suffix;
+ Commit that using `git commit -C b5c30ae52638e81a38fe5329081c5613d7bd6ca5 .version`.
+- Push with `git push && git push --tags`
+- Notify downstreams (OS packages)
+ - anitya should autodetect the tag
+- Update /topic on IRC
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/README.md b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/README.md
new file mode 100644
index 00000000..cb3d943c
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/README.md
@@ -0,0 +1,124 @@
+zsh-syntax-highlighting / tests
+===============================
+
+Utility scripts for testing zsh-syntax-highlighting highlighters.
+
+The tests harness expects the highlighter directory to contain a `test-data`
+directory with test data files.
+See the [main highlighter](../highlighters/main/test-data) for examples.
+
+Tests should set the following variables:
+
+1.
+Each test should define the string `$BUFFER` that is to be highlighted and the
+array parameter `$expected_region_highlight`.
+The value of that parameter is a list of strings of the form `"$i $j $style"`.
+or `"$i $j $style $todo"`.
+Each string specifies the highlighting that `$BUFFER[$i,$j]` should have;
+that is, `$i` and `$j` specify a range, 1-indexed, inclusive of both endpoints.
+`$style` is a key of `$ZSH_HIGHLIGHT_STYLES`.
+If `$todo` exists, the test point is marked as TODO (the failure of that test
+point will not fail the test), and `$todo` is used as the explanation.
+
+2.
+If a test sets `$skip_test` to a non-empty string, the test will be skipped
+with the provided string as the reason.
+
+3.
+If a test sets `$fail_test` to a non-empty string, the test will be skipped
+with the provided string as the reason.
+
+4.
+If a test sets `unsorted=1` the order of highlights in `$expected_region_highlight`
+need not match the order in `$region_highlight`.
+
+5.
+Normally, tests fail if `$expected_region_highlight` and `$region_highlight`
+have different numbers of elements. To mark this check as expected to fail,
+tests may set `$expected_mismatch` to an explanation string (like `$todo`);
+this is useful when the only difference between actual and expected is that actual
+has some additional, superfluous elements. This check is skipped if the
+`$todo` component is present in any regular test point.
+
+**Note**: `$region_highlight` uses the same `"$i $j $style"` syntax but
+interprets the indexes differently.
+
+**Note**: Tests are run with `setopt NOUNSET WARN_CREATE_GLOBAL`, so any
+variables the test creates must be declared local.
+
+**Isolation**: Each test is run in a separate subshell, so any variables,
+aliases, functions, etc., it defines will be visible to the tested code (that
+computes `$region_highlight`), but will not affect subsequent tests. The
+current working directory of tests is set to a newly-created empty directory,
+which is automatically cleaned up after the test exits. For example:
+
+```zsh
+setopt PATH_DIRS
+mkdir -p foo/bar
+touch foo/bar/testing-issue-228
+chmod +x foo/bar/testing-issue-228
+path+=( "$PWD"/foo )
+
+BUFFER='bar/testing-issue-228'
+
+expected_region_highlight=(
+ "1 21 command" # bar/testing-issue-228
+)
+```
+
+
+Writing new tests
+-----------------
+
+An experimental tool is available to generate test files:
+
+```zsh
+zsh -f tests/generate.zsh 'ls -x' acme newfile
+```
+
+This generates a `highlighters/acme/test-data/newfile.zsh` test file based on
+the current highlighting of the given `$BUFFER` (in this case, `ls -x`).
+
+_This tool is experimental._ Its interface may change. In particular it may
+grow ways to set `$PREBUFFER` to inject free-form code into the generated file.
+
+
+Highlighting test
+-----------------
+
+[`test-highlighting.zsh`](tests/test-highlighting.zsh) tests the correctness of
+the highlighting. Usage:
+
+```zsh
+zsh test-highlighting.zsh <HIGHLIGHTER NAME>
+```
+
+All tests may be run with
+
+```zsh
+make test
+```
+
+which will run all highlighting tests and report results in [TAP format][TAP].
+By default, the results of all tests will be printed; to show only "interesting"
+results (tests that failed but were expected to succeed, or vice-versa), run
+`make quiet-test` (or `make test QUIET=y`).
+
+[TAP]: http://testanything.org/
+
+
+Performance test
+----------------
+
+[`test-perfs.zsh`](tests/test-perfs.zsh) measures the time spent doing the
+highlighting. Usage:
+
+```zsh
+zsh test-perfs.zsh <HIGHLIGHTER NAME>
+```
+
+All tests may be run with
+
+```zsh
+make perf
+```
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/edit-failed-tests b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/edit-failed-tests
new file mode 100755
index 00000000..e3a76685
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/edit-failed-tests
@@ -0,0 +1,40 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+type perl sponge >/dev/null || { print -ru2 -- "$0: This script requires perl(1) and sponge(1) [from moreutils]"; exit 1; }
+
+local editor=( "${(@Q)${(z)${VISUAL:-${EDITOR:-vi}}}}" )
+() {
+ > "$2" perl -nE '$highlighter = $1 if /^Running test (\S*)/; say "highlighters/${highlighter}/test-data/$1.zsh" if /^## (\S*)/' "$1"
+ >>"$2" echo ""
+ >>"$2" cat <"$1"
+ "${editor[@]}" -- "$2"
+} =(${MAKE:-make} quiet-test) =(:)
+# TODO: tee(1) the quiet-test output to /dev/tty as it's happening, with colors.
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/generate.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/generate.zsh
new file mode 100755
index 00000000..56960202
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/generate.zsh
@@ -0,0 +1,117 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2016 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+emulate -LR zsh
+setopt localoptions extendedglob
+
+# Required for add-zle-hook-widget.
+zmodload zsh/zle
+
+# Argument parsing.
+if (( $# * $# - 7 * $# + 12 )) || [[ $1 == -* ]]; then
+ print -r -- >&2 "$0: usage: $0 BUFFER HIGHLIGHTER BASENAME [PREAMBLE]"
+ print -r -- >&2 ""
+ print -r -- >&2 "Generate highlighters/HIGHLIGHTER/test-data/BASENAME.zsh based on the"
+ print -r -- >&2 "current highlighting of BUFFER, using the setup code PREAMBLE."
+ exit 1
+fi
+buffer=$1
+ZSH_HIGHLIGHT_HIGHLIGHTERS=( $2 )
+fname=${0:A:h:h}/highlighters/$2/test-data/${3%.zsh}.zsh
+preamble=${4:-""}
+
+# Load the main script.
+. ${0:A:h:h}/zsh-syntax-highlighting.zsh
+
+# Overwrite _zsh_highlight_add_highlight so we get the key itself instead of the style
+_zsh_highlight_add_highlight()
+{
+ region_highlight+=("$1 $2 $3")
+}
+
+
+# Copyright block
+year="`LC_ALL=C date +%Y`"
+if ! { read -q "?Set copyright year to $year? " } always { echo "" }; then
+ year="YYYY"
+fi
+<$0 sed -n -e '1,/^$/p' | sed -e "s/2[0-9][0-9][0-9]/${year}/" > $fname
+# Assumes stdout is line-buffered
+git add -- $fname
+exec > >(tee -a $fname)
+
+# Preamble
+if [[ -n $preamble ]]; then
+ print -rl -- "$preamble" ""
+fi
+
+# Buffer
+print -n 'BUFFER='
+if [[ $buffer != (#s)[$'\t -~']#(#e) ]]; then
+ print -r -- ${(qqqq)buffer}
+else
+ print -r -- ${(qq)buffer}
+fi
+echo ""
+
+# Expectations
+print 'expected_region_highlight=('
+() {
+ local i
+ local PREBUFFER
+ local BUFFER
+
+ PREBUFFER=""
+ BUFFER="$buffer"
+ region_highlight=()
+ eval $(
+ exec 3>&1 >/dev/null
+ typeset -r __tests_tmpdir="$(mktemp -d)"
+ {
+ # Use a subshell to ensure $__tests_tmpdir, which is to be rm -rf'd, won't be modified.
+ (cd -- "$__tests_tmpdir" && eval $preamble && _zsh_highlight && typeset -p region_highlight >&3)
+ : # workaround zsh bug workers/45305 with respect to the $(…) subshell we're in
+ } always {
+ rm -rf -- ${__tests_tmpdir}
+ }
+ )
+
+ for ((i=1; i<=${#region_highlight}; i++)); do
+ local -a highlight_zone; highlight_zone=( ${(z)region_highlight[$i]} )
+ integer start=$highlight_zone[1] end=$highlight_zone[2]
+ if (( start < end )) # region_highlight ranges are half-open
+ then
+ (( --end )) # convert to closed range, like expected_region_highlight
+ (( ++start, ++end )) # region_highlight is 0-indexed; expected_region_highlight is 1-indexed
+ fi
+ printf " %s # %s\n" ${(qq):-"$start $end $highlight_zone[3]"} ${${(qqqq)BUFFER[start,end]}[3,-2]}
+ done
+}
+print ')'
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/tap-colorizer.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/tap-colorizer.zsh
new file mode 100755
index 00000000..f3dc84e7
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/tap-colorizer.zsh
@@ -0,0 +1,71 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015, 2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# This is a stdin-to-stdout filter that takes TAP output (such as 'make test')
+# on stdin and passes it, colorized, to stdout.
+
+emulate -LR zsh
+
+if [[ ! -t 1 ]] ; then
+ exec cat
+fi
+
+while read -r line;
+do
+ case $line in
+ # comment (filename header) or plan
+ (#* | <->..<->)
+ print -nP %F{blue}
+ ;;
+ # SKIP
+ (*# SKIP*)
+ print -nP %F{yellow}
+ ;;
+ # XPASS
+ (ok*# TODO*)
+ print -nP %F{red}
+ ;;
+ # XFAIL
+ (not ok*# TODO*)
+ print -nP %F{yellow}
+ ;;
+ # FAIL
+ (not ok*)
+ print -nP %F{red}
+ ;;
+ # PASS
+ (ok*)
+ print -nP %F{green}
+ ;;
+ esac
+ print -nr - "$line"
+ print -nP %f
+ echo "" # newline
+done
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/tap-filter b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/tap-filter
new file mode 100755
index 00000000..f9aa6041
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/tap-filter
@@ -0,0 +1,47 @@
+#!/usr/bin/env perl
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# vim: ft=perl sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# This is a stdin-to-stdout filter that takes TAP output (such as 'make test')
+# on stdin and deletes lines pertaining to expected results.
+#
+# More specifically, if any of the test points in a test file either failed but
+# was expected to pass, or passed but was expected to fail, then emit that test
+# file's output; else, elide that test file's output.
+
+use v5.10.0;
+use warnings;
+use strict;
+
+undef $/; # slurp mode
+print for
+ grep { /^ok.*# TODO/m or /^not ok(?!.*# TODO)/m or /^Bail out!/m }
+ # Split on plan lines and remove them from the output. (To keep them,
+ # use the lookahead syntax, «(?=…)», to make the match zero-length.)
+ split /^\d+\.\.\d+$/m,
+ <STDIN>;
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-highlighting.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-highlighting.zsh
new file mode 100755
index 00000000..8b564a8b
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-highlighting.zsh
@@ -0,0 +1,291 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2017 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+
+setopt NO_UNSET WARN_CREATE_GLOBAL
+
+# Required for add-zle-hook-widget.
+zmodload zsh/zle
+
+local -r root=${0:h:h}
+local -a anon_argv; anon_argv=("$@")
+
+(){
+set -- "${(@)anon_argv}"
+# Check an highlighter was given as argument.
+[[ -n "$1" ]] || {
+ echo >&2 "Bail out! You must provide the name of a valid highlighter as argument."
+ exit 2
+}
+
+# Check the highlighter is valid.
+[[ -f $root/highlighters/$1/$1-highlighter.zsh ]] || {
+ echo >&2 "Bail out! Could not find highlighter ${(qq)1}."
+ exit 2
+}
+
+# Check the highlighter has test data.
+[[ -d $root/highlighters/$1/test-data ]] || {
+ echo >&2 "Bail out! Highlighter ${(qq)1} has no test data."
+ exit 2
+}
+
+# Set up results_filter
+local results_filter
+if [[ ${QUIET-} == y ]]; then
+ if type -w perl >/dev/null; then
+ results_filter=$root/tests/tap-filter
+ else
+ echo >&2 "Bail out! quiet mode not supported: perl not found"; exit 2
+ fi
+else
+ results_filter=cat
+fi
+[[ -n $results_filter ]] || { echo >&2 "Bail out! BUG setting \$results_filter"; exit 2 }
+
+# Load the main script.
+# While here, test that it doesn't eat aliases.
+print > >($results_filter | $root/tests/tap-colorizer.zsh) -r -- "# global (driver) tests"
+print > >($results_filter | $root/tests/tap-colorizer.zsh) -r -- "1..1"
+alias -- +plus=plus
+alias -- _other=other
+local original_alias_dash_L_output="$(alias -L)"
+. $root/zsh-syntax-highlighting.zsh
+if [[ $original_alias_dash_L_output == $(alias -L) ]]; then
+ print -r -- "ok 1 # 'alias -- +foo=bar' is preserved"
+else
+ print -r -- "not ok 1 # 'alias -- +foo=bar' is preserved"
+ exit 1
+fi > >($results_filter | $root/tests/tap-colorizer.zsh)
+
+# Overwrite _zsh_highlight_add_highlight so we get the key itself instead of the style
+_zsh_highlight_add_highlight()
+{
+ region_highlight+=("$1 $2 $3")
+}
+
+# Activate the highlighter.
+ZSH_HIGHLIGHT_HIGHLIGHTERS=($1)
+
+# In zsh<5.3, 'typeset -p arrayvar' emits two lines, so we use this wrapper instead.
+typeset_p() {
+ for 1 ; do
+ if [[ ${(tP)1} == *array* ]]; then
+ print -r -- "$1=( ${(@qqqqP)1} )"
+ else
+ print -r -- "$1=${(qqqqP)1}"
+ fi
+ done
+}
+
+# Escape # as ♯ and newline as ↵ they are illegal in the 'description' part of TAP output
+# The string to escape is «"$@"»; the result is returned in $REPLY.
+tap_escape() {
+ local s="${(j. .)@}"
+ REPLY="${${s//'#'/♯}//$'\n'/↵}"
+}
+
+# Runs a highlighting test
+# $1: data file
+run_test_internal() {
+
+ local tests_tempdir="$1"; shift
+ local srcdir="$PWD"
+ builtin cd -q -- "$tests_tempdir" || { echo >&2 "Bail out! On ${(qq)1}: cd failed: $?"; return 1 }
+
+ # Load the data and prepare checking it.
+ local BUFFER CURSOR MARK PENDING PREBUFFER REGION_ACTIVE WIDGET REPLY skip_test fail_test unsorted=0
+ local expected_mismatch
+ local skip_mismatch
+ local -a expected_region_highlight region_highlight
+
+ local ARG="$1"
+ local RETURN=""
+ () {
+ setopt localoptions
+
+ # WARNING: The remainder of this anonymous function will run with the test's options in effect
+ if { ! . "$srcdir"/"$ARG" } || (( $#fail_test )); then
+ print -r -- "1..1"
+ print -r -- "## ${ARG:t:r}"
+ tap_escape $fail_test; fail_test=$REPLY
+ print -r -- "not ok 1 - failed setup: $fail_test"
+ return ${RETURN:=0}
+ fi
+
+ (( $#skip_test )) && {
+ print -r -- "1..0 # SKIP $skip_test"
+ print -r -- "## ${ARG:t:r}"
+ return ${RETURN:=0}
+ }
+
+ # Check the data declares $PREBUFFER or $BUFFER.
+ [[ -z $PREBUFFER && -z $BUFFER ]] && { echo >&2 "Bail out! On ${(qq)ARG}: Either 'PREBUFFER' or 'BUFFER' must be declared and non-blank"; return ${RETURN:=1}; }
+ [[ $PREBUFFER == (''|*$'\n') ]] || { echo >&2 "Bail out! On ${(qq)ARG}: PREBUFFER=${(qqqq)PREBUFFER} doesn't end with a newline"; return ${RETURN:=1}; }
+
+ # Set sane defaults for ZLE variables
+ : ${CURSOR=$#BUFFER} ${PENDING=0} ${WIDGET=z-sy-h-test-harness-test-widget}
+
+ # Process the data.
+ _zsh_highlight
+ }; [[ -z $RETURN ]] || return $RETURN
+ unset ARG
+
+ integer print_expected_and_actual=0
+
+ if (( unsorted )); then
+ region_highlight=("${(@n)region_highlight}")
+ expected_region_highlight=("${(@n)expected_region_highlight}")
+ fi
+
+ # Print the plan line, and some comments for human readers
+ echo "1..$(( $#expected_region_highlight + 1))"
+ echo "## ${1:t:r}" # note: tests/edit-failed-tests looks for the "##" emitted by this line
+ [[ -n $PREBUFFER ]] && printf '# %s\n' "$(typeset_p PREBUFFER)"
+ [[ -n $BUFFER ]] && printf '# %s\n' "$(typeset_p BUFFER)"
+
+ local i
+ for ((i=1; i<=$#expected_region_highlight; i++)); do
+ local -a expected_highlight_zone; expected_highlight_zone=( ${(z)expected_region_highlight[i]} )
+ integer exp_start=$expected_highlight_zone[1] exp_end=$expected_highlight_zone[2]
+ local todo=
+ if (( $+expected_highlight_zone[4] )); then
+ todo="# TODO $expected_highlight_zone[4]"
+ skip_mismatch="cardinality check disabled whilst regular test points are expected to fail"
+ fi
+ if ! (( $+region_highlight[i] )); then
+ print -r -- "not ok $i - unmatched expectation ($exp_start $exp_end $expected_highlight_zone[3])" \
+ "${skip_mismatch:+"# TODO ${(qqq)skip_mismatch}"}"
+ if [[ -z $skip_mismatch ]]; then (( ++print_expected_and_actual )); fi
+ continue
+ fi
+ local -a highlight_zone; highlight_zone=( ${(z)region_highlight[i]} )
+ integer start=$(( highlight_zone[1] + 1 )) end=$highlight_zone[2]
+ local desc="[$start,$end] «${BUFFER[$start,$end]}»"
+ tap_escape $desc; desc=$REPLY
+ if
+ [[ $start != $exp_start ]] ||
+ [[ $end != $exp_end ]] ||
+ [[ ${highlight_zone[3]%,} != ${expected_highlight_zone[3]} ]] # remove the comma that's before the memo field
+ then
+ print -r -- "not ok $i - $desc - expected ($exp_start $exp_end ${(qqq)expected_highlight_zone[3]}), observed ($start $end ${(qqq)highlight_zone[3]}). $todo"
+ if [[ -z $todo ]]; then (( ++print_expected_and_actual )); fi
+ else
+ print -r -- "ok $i - $desc${todo:+ - }$todo"
+ fi
+ unset expected_highlight_zone
+ unset exp_start exp_end
+ unset todo
+ unset highlight_zone
+ unset start end
+ unset desc
+ done
+
+ # If both $skip_mismatch and $expected_mismatch are set, that means the test
+ # has some XFail test points, _and_ explicitly sets $expected_mismatch as
+ # well. Explicit settings should have priority, so we ignore $skip_mismatch
+ # if $expected_mismatch is set.
+ if [[ -n $skip_mismatch && -z $expected_mismatch ]]; then
+ tap_escape $skip_mismatch; skip_mismatch=$REPLY
+ print "ok $i - cardinality check" "# SKIP $skip_mismatch"
+ else
+ local todo
+ if [[ -n $expected_mismatch ]]; then
+ tap_escape $expected_mismatch; expected_mismatch=$REPLY
+ todo="# TODO $expected_mismatch"
+ fi
+ if (( $#expected_region_highlight == $#region_highlight )); then
+ print -r -- "ok $i - cardinality check${todo:+ - }$todo"
+ else
+ local details
+ details+="have $#expected_region_highlight expectations and $#region_highlight region_highlight entries: "
+ details+="«$(typeset_p expected_region_highlight)» «$(typeset_p region_highlight)»"
+ tap_escape $details; details=$REPLY
+ print -r -- "not ok $i - cardinality check - $details${todo:+ - }$todo"
+ if [[ -z $todo ]]; then (( ++print_expected_and_actual )); fi
+ fi
+ fi
+ if (( print_expected_and_actual )); then
+ () {
+ local -a left_column right_column
+ left_column=( "expected_region_highlight" "${(qq)expected_region_highlight[@]}" )
+ right_column=( "region_highlight" "${(qq)region_highlight[@]}" )
+ integer difference=$(( $#right_column - $#left_column ))
+ repeat $difference do left_column+=(.); done
+ paste \
+ =(print -rC1 -- $left_column) \
+ =(print -rC1 -- $right_column) \
+ | if type column >/dev/null; then column -t -s $'\t'; else cat; fi \
+ | sed 's/^/# /'
+ }
+ fi
+}
+
+# Run a single test file. The exit status is 1 if the test harness had
+# an error and 0 otherwise. The exit status does not depend on whether
+# test points succeeded or failed.
+run_test() {
+ # Do not combine the declaration and initialization: «local x="$(false)"» does not set $?.
+ local __tests_tempdir
+ __tests_tempdir="$(mktemp -d)" && [[ -d $__tests_tempdir ]] || {
+ echo >&2 "Bail out! mktemp failed"; return 1
+ }
+ typeset -r __tests_tempdir # don't allow tests to override the variable that we will 'rm -rf' later on
+
+ {
+ # Use a subshell to isolate tests from each other.
+ # (So tests can alter global shell state using 'cd', 'hash', etc)
+ {
+ # These braces are so multios don't come into play.
+ { (run_test_internal "$__tests_tempdir" "$@") 3>&1 >&2 2>&3 } | grep \^
+ local ret=$pipestatus[1] stderr=$pipestatus[2]
+ if (( ! stderr )); then
+ # stdout will become stderr
+ echo "Bail out! On ${(qq)1}: output on stderr"; return 1
+ else
+ return $ret
+ fi
+ } 3>&1 >&2 2>&3
+ } always {
+ rm -rf -- "$__tests_tempdir"
+ }
+}
+
+# Process each test data file in test data directory.
+integer something_failed=0
+ZSH_HIGHLIGHT_STYLES=()
+local data_file
+for data_file in $root/highlighters/$1/test-data/*.zsh; do
+ run_test "$data_file" | tee >($results_filter | $root/tests/tap-colorizer.zsh) | grep -v '^not ok.*# TODO' | grep -Eq '^not ok|^ok.*# TODO' && (( something_failed=1 ))
+ (( $pipestatus[1] )) && exit 2
+done
+
+exit $something_failed
+}
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-perfs.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-perfs.zsh
new file mode 100755
index 00000000..aa139aad
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-perfs.zsh
@@ -0,0 +1,103 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+
+# Required for add-zle-hook-widget.
+zmodload zsh/zle
+
+# Check an highlighter was given as argument.
+[[ -n "$1" ]] || {
+ echo >&2 "Bail out! You must provide the name of a valid highlighter as argument."
+ exit 2
+}
+
+# Check the highlighter is valid.
+[[ -f ${0:h:h}/highlighters/$1/$1-highlighter.zsh ]] || {
+ echo >&2 "Bail out! Could not find highlighter ${(qq)1}."
+ exit 2
+}
+
+# Check the highlighter has test data.
+[[ -d ${0:h:h}/highlighters/$1/test-data ]] || {
+ echo >&2 "Bail out! Highlighter ${(qq)1} has no test data."
+ exit 2
+}
+
+# Load the main script.
+typeset -a region_highlight
+. ${0:h:h}/zsh-syntax-highlighting.zsh
+
+# Activate the highlighter.
+ZSH_HIGHLIGHT_HIGHLIGHTERS=($1)
+
+# Runs a highlighting test
+# $1: data file
+run_test_internal() {
+ local -a highlight_zone
+
+ local tests_tempdir="$1"; shift
+ local srcdir="$PWD"
+ builtin cd -q -- "$tests_tempdir" || { echo >&2 "Bail out! cd failed: $?"; return 1 }
+
+ # Load the data and prepare checking it.
+ PREBUFFER= BUFFER= ;
+ . "$srcdir"/"$1"
+
+ # Check the data declares $PREBUFFER or $BUFFER.
+ [[ -z $PREBUFFER && -z $BUFFER ]] && { echo >&2 "Bail out! Either 'PREBUFFER' or 'BUFFER' must be declared and non-blank"; return 1; }
+
+ # Set $? for _zsh_highlight
+ true && _zsh_highlight
+}
+
+run_test() {
+ # Do not combine the declaration and initialization: «local x="$(false)"» does not set $?.
+ local __tests_tempdir
+ __tests_tempdir="$(mktemp -d)" && [[ -d $__tests_tempdir ]] || {
+ echo >&2 "Bail out! mktemp failed"; return 1
+ }
+ typeset -r __tests_tempdir # don't allow tests to override the variable that we will 'rm -rf' later on
+
+ {
+ (run_test_internal "$__tests_tempdir" "$@")
+ } always {
+ rm -rf -- "$__tests_tempdir"
+ }
+}
+
+# Process each test data file in test data directory.
+local data_file
+TIMEFMT="%*Es"
+{ time (for data_file in ${0:h:h}/highlighters/$1/test-data/*.zsh; do
+ run_test "$data_file"
+ (( $pipestatus[1] )) && exit 2
+done) } 2>&1 || exit $?
+
+exit 0
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-zprof.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-zprof.zsh
new file mode 100755
index 00000000..ada16187
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/tests/test-zprof.zsh
@@ -0,0 +1,78 @@
+#!/usr/bin/env zsh
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2015 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# Load the main script.
+typeset -a region_highlight
+. ${0:h:h}/zsh-syntax-highlighting.zsh
+
+# Activate the highlighter.
+ZSH_HIGHLIGHT_HIGHLIGHTERS=(main)
+
+source_file=0.7.1:highlighters/$1/$1-highlighter.zsh
+
+# Runs a highlighting test
+# $1: data file
+run_test_internal() {
+ setopt interactivecomments
+
+ local -a highlight_zone
+
+ local tests_tempdir="$1"; shift
+ local srcdir="$PWD"
+ builtin cd -q -- "$tests_tempdir" || { echo >&2 "Bail out! cd failed: $?"; return 1 }
+
+ # Load the data and prepare checking it.
+ PREBUFFER=
+ BUFFER=$(cd -- "$srcdir" && git cat-file blob $source_file)
+ expected_region_highlight=()
+
+ zmodload zsh/zprof
+ zprof -c
+ # Set $? for _zsh_highlight
+ true && _zsh_highlight
+ zprof
+}
+
+run_test() {
+ # Do not combine the declaration and initialization: «local x="$(false)"» does not set $?.
+ local __tests_tempdir
+ __tests_tempdir="$(mktemp -d)" && [[ -d $__tests_tempdir ]] || {
+ echo >&2 "Bail out! mktemp failed"; return 1
+ }
+ typeset -r __tests_tempdir # don't allow tests to override the variable that we will 'rm -rf' later on
+
+ {
+ (run_test_internal "$__tests_tempdir" "$@")
+ } always {
+ rm -rf -- "$__tests_tempdir"
+ }
+}
+
+run_test
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.plugin.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.plugin.zsh
new file mode 100644
index 00000000..f2456aec
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.plugin.zsh
@@ -0,0 +1,2 @@
+0=${(%):-%N}
+source ${0:A:h}/zsh-syntax-highlighting.zsh
diff --git a/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
new file mode 100644
index 00000000..bec01898
--- /dev/null
+++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
@@ -0,0 +1,600 @@
+# -------------------------------------------------------------------------------------------------
+# Copyright (c) 2010-2020 zsh-syntax-highlighting contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted
+# provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions
+# and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
+# may be used to endorse or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# -------------------------------------------------------------------------------------------------
+# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
+# vim: ft=zsh sw=2 ts=2 et
+# -------------------------------------------------------------------------------------------------
+
+# First of all, ensure predictable parsing.
+typeset zsh_highlight__aliases="$(builtin alias -Lm '[^+]*')"
+# In zsh <= 5.2, aliases that begin with a plus sign ('alias -- +foo=42')
+# are emitted by `alias -L` without a '--' guard, so they don't round trip.
+#
+# Hence, we exclude them from unaliasing:
+builtin unalias -m '[^+]*'
+
+# Set $0 to the expected value, regardless of functionargzero.
+0=${(%):-%N}
+if true; then
+ # $0 is reliable
+ typeset -g ZSH_HIGHLIGHT_VERSION=$(<"${0:A:h}"/.version)
+ typeset -g ZSH_HIGHLIGHT_REVISION=$(<"${0:A:h}"/.revision-hash)
+ if [[ $ZSH_HIGHLIGHT_REVISION == \$Format:* ]]; then
+ # When running from a source tree without 'make install', $ZSH_HIGHLIGHT_REVISION
+ # would be set to '$Format:%H$' literally. That's an invalid value, and obtaining
+ # the valid value (via `git rev-parse HEAD`, as Makefile does) might be costly, so:
+ ZSH_HIGHLIGHT_REVISION=HEAD
+ fi
+fi
+
+# This function takes a single argument F and returns True iff F is an autoload stub.
+_zsh_highlight__function_is_autoload_stub_p() {
+ if zmodload -e zsh/parameter; then
+ #(( ${+functions[$1]} )) &&
+ [[ "$functions[$1]" == *"builtin autoload -X"* ]]
+ else
+ #[[ $(type -wa -- "$1") == *'function'* ]] &&
+ [[ "${${(@f)"$(which -- "$1")"}[2]}" == $'\t'$histchars[3]' undefined' ]]
+ fi
+ # Do nothing here: return the exit code of the if.
+}
+
+# Return True iff the argument denotes a function name.
+_zsh_highlight__is_function_p() {
+ if zmodload -e zsh/parameter; then
+ (( ${+functions[$1]} ))
+ else
+ [[ $(type -wa -- "$1") == *'function'* ]]
+ fi
+}
+
+# This function takes a single argument F and returns True iff F denotes the
+# name of a callable function. A function is callable if it is fully defined
+# or if it is marked for autoloading and autoloading it at the first call to it
+# will succeed. In particular, if F has been marked for autoloading
+# but is not available in $fpath, then calling this function on F will return False.
+#
+# See users/21671 http://www.zsh.org/cgi-bin/mla/redirect?USERNUMBER=21671
+_zsh_highlight__function_callable_p() {
+ if _zsh_highlight__is_function_p "$1" &&
+ ! _zsh_highlight__function_is_autoload_stub_p "$1"
+ then
+ # Already fully loaded.
+ return 0 # true
+ else
+ # "$1" is either an autoload stub, or not a function at all.
+ #
+ # Use a subshell to avoid affecting the calling shell.
+ #
+ # We expect 'autoload +X' to return non-zero if it fails to fully load
+ # the function.
+ ( autoload -U +X -- "$1" 2>/dev/null )
+ return $?
+ fi
+}
+
+# -------------------------------------------------------------------------------------------------
+# Core highlighting update system
+# -------------------------------------------------------------------------------------------------
+
+# Use workaround for bug in ZSH?
+# zsh-users/zsh@48cadf4 http://www.zsh.org/mla/workers//2017/msg00034.html
+autoload -Uz is-at-least
+if is-at-least 5.4; then
+ typeset -g zsh_highlight__pat_static_bug=false
+else
+ typeset -g zsh_highlight__pat_static_bug=true
+fi
+
+# Array declaring active highlighters names.
+typeset -ga ZSH_HIGHLIGHT_HIGHLIGHTERS
+
+# Update ZLE buffer syntax highlighting.
+#
+# Invokes each highlighter that needs updating.
+# This function is supposed to be called whenever the ZLE state changes.
+_zsh_highlight()
+{
+ # Store the previous command return code to restore it whatever happens.
+ local ret=$?
+ # Make it read-only. Can't combine this with the previous line when POSIX_BUILTINS may be set.
+ typeset -r ret
+
+ # $region_highlight should be predefined, either by zle or by the test suite's mock (non-special) array.
+ (( ${+region_highlight} )) || {
+ echo >&2 'zsh-syntax-highlighting: error: $region_highlight is not defined'
+ echo >&2 'zsh-syntax-highlighting: (Check whether zsh-syntax-highlighting was installed according to the instructions.)'
+ return $ret
+ }
+
+ # Probe the memo= feature, once.
+ (( ${+zsh_highlight__memo_feature} )) || {
+ region_highlight+=( " 0 0 fg=red, memo=zsh-syntax-highlighting" )
+ case ${region_highlight[-1]} in
+ ("0 0 fg=red")
+ # zsh 5.8 or earlier
+ integer -gr zsh_highlight__memo_feature=0
+ ;;
+ ("0 0 fg=red memo=zsh-syntax-highlighting")
+ # zsh 5.9 or later
+ integer -gr zsh_highlight__memo_feature=1
+ ;;
+ (" 0 0 fg=red, memo=zsh-syntax-highlighting") ;&
+ (*)
+ # We can get here in two ways:
+ #
+ # 1. When not running as a widget. In that case, $region_highlight is
+ # not a special variable (= one with custom getter/setter functions
+ # written in C) but an ordinary one, so the third case pattern matches
+ # and we fall through to this block. (The test suite uses this codepath.)
+ #
+ # 2. When running under a future version of zsh that will have changed
+ # the serialization of $region_highlight elements from their underlying
+ # C structs, so that none of the previous case patterns will match.
+ #
+ # In either case, fall back to a version check.
+ #
+ # The memo= feature was added to zsh in commit zsh-5.8-172-gdd6e702ee.
+ # The version number at the time was 5.8.0.2-dev (see Config/version.mk).
+ # Therefore, on zsh master 5.8.0.3 and newer the memo= feature is available.
+ # However, there's also the zsh 5.8.1 release, which doesn't have the
+ # memo= feature.
+ #
+ # On zsh master 5.8.0.2 between the aforementioned commit and the
+ # first Config/version.mk bump after it (zsh-5.8-607-g75c1edde5, the
+ # bump to 5.8.1.1-dev following the backport to master of the bump
+ # to 5.8.1), this condition will false negative.
+ if is-at-least 5.8.1.1 $ZSH_VERSION.0.0; then
+ integer -gr zsh_highlight__memo_feature=1
+ else
+ integer -gr zsh_highlight__memo_feature=0
+ fi
+ ;;
+ esac
+ region_highlight[-1]=()
+ }
+
+ # Reset region_highlight to build it from scratch
+ if (( zsh_highlight__memo_feature )); then
+ region_highlight=( "${(@)region_highlight:#*memo=zsh-syntax-highlighting*}" )
+ else
+ # Legacy codepath. Not very interoperable with other plugins (issue #418).
+ region_highlight=()
+ fi
+
+ # 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
+ # and doesn't have the pattern matching bug
+ if [[ $WIDGET == zle-isearch-update ]] && { $zsh_highlight__pat_static_bug || ! (( $+ISEARCHMATCH_ACTIVE )) }; then
+ return $ret
+ fi
+
+ # Before we 'emulate -L', save the user's options
+ local -A zsyh_user_options
+ if zmodload -e zsh/parameter; then
+ zsyh_user_options=("${(kv)options[@]}")
+ else
+ local canonical_options onoff option raw_options
+ raw_options=(${(f)"$(emulate -R zsh; set -o)"})
+ canonical_options=(${${${(M)raw_options:#*off}%% *}#no} ${${(M)raw_options:#*on}%% *})
+ for option in "${canonical_options[@]}"; do
+ [[ -o $option ]]
+ case $? in
+ (0) zsyh_user_options+=($option on);;
+ (1) zsyh_user_options+=($option off);;
+ (*) # Can't happen, surely?
+ echo "zsh-syntax-highlighting: warning: '[[ -o $option ]]' returned $?"
+ ;;
+ esac
+ done
+ fi
+ typeset -r zsyh_user_options
+
+ emulate -L zsh
+ setopt localoptions warncreateglobal nobashrematch
+ local REPLY # don't leak $REPLY into global scope
+
+ # 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).
+ (( KEYS_QUEUED_COUNT > 0 )) && return $ret
+ (( PENDING > 0 )) && return $ret
+
+ {
+ 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 ! type "_zsh_highlight_highlighter_${highlighter}_predicate" >&/dev/null; then
+ echo "zsh-syntax-highlighting: warning: disabling the ${(qq)highlighter} highlighter as it has not been loaded" >&2
+ # TODO: use ${(b)} rather than ${(q)} if supported
+ ZSH_HIGHLIGHT_HIGHLIGHTERS=( ${ZSH_HIGHLIGHT_HIGHLIGHTERS:#${highlighter}} )
+ elif "_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}_paint"
+ } always {
+ : ${(AP)cache_place::="${region_highlight[@]}"}
+ }
+
+ # Restore saved region_highlight
+ region_highlight=("${region_highlight_copy[@]}")
+
+ fi
+
+ # Use value form cache if any cached
+ region_highlight+=("${(@P)cache_place}")
+
+ done
+
+ # Re-apply zle_highlight settings
+
+ # region
+ () {
+ (( REGION_ACTIVE )) || return
+ integer min max
+ if (( MARK > CURSOR )) ; then
+ min=$CURSOR max=$MARK
+ else
+ min=$MARK max=$CURSOR
+ fi
+ if (( REGION_ACTIVE == 1 )); then
+ [[ $KEYMAP = vicmd ]] && (( max++ ))
+ elif (( REGION_ACTIVE == 2 )); then
+ local needle=$'\n'
+ # CURSOR and MARK are 0 indexed between letters like region_highlight
+ # Do not include the newline in the highlight
+ (( min = ${BUFFER[(Ib:min:)$needle]} ))
+ (( max = ${BUFFER[(ib:max:)$needle]} - 1 ))
+ fi
+ _zsh_highlight_apply_zle_highlight region standout "$min" "$max"
+ }
+
+ # yank / paste (zsh-5.1.1 and newer)
+ (( $+YANK_ACTIVE )) && (( YANK_ACTIVE )) && _zsh_highlight_apply_zle_highlight paste standout "$YANK_START" "$YANK_END"
+
+ # isearch
+ (( $+ISEARCHMATCH_ACTIVE )) && (( ISEARCHMATCH_ACTIVE )) && _zsh_highlight_apply_zle_highlight isearch underline "$ISEARCHMATCH_START" "$ISEARCHMATCH_END"
+
+ # suffix
+ (( $+SUFFIX_ACTIVE )) && (( SUFFIX_ACTIVE )) && _zsh_highlight_apply_zle_highlight suffix bold "$SUFFIX_START" "$SUFFIX_END"
+
+
+ return $ret
+
+
+ } always {
+ typeset -g _ZSH_HIGHLIGHT_PRIOR_BUFFER="$BUFFER"
+ typeset -gi _ZSH_HIGHLIGHT_PRIOR_CURSOR=$CURSOR
+ }
+}
+
+# Apply highlighting based on entries in the zle_highlight array.
+# This function takes four arguments:
+# 1. The exact entry (no patterns) in the zle_highlight array:
+# region, paste, isearch, or suffix
+# 2. The default highlighting that should be applied if the entry is unset
+# 3. and 4. Two integer values describing the beginning and end of the
+# range. The order does not matter.
+_zsh_highlight_apply_zle_highlight() {
+ local entry="$1" default="$2"
+ integer first="$3" second="$4"
+
+ # read the relevant entry from zle_highlight
+ #
+ # ### In zsh≥5.0.8 we'd use ${(b)entry}, but we support older zsh's, so we don't
+ # ### add (b). The only effect is on the failure mode for callers that violate
+ # ### the precondition.
+ local region="${zle_highlight[(r)${entry}:*]-}"
+
+ if [[ -z "$region" ]]; then
+ # entry not specified at all, use default value
+ region=$default
+ else
+ # strip prefix
+ region="${region#${entry}:}"
+
+ # no highlighting when set to the empty string or to 'none'
+ if [[ -z "$region" ]] || [[ "$region" == none ]]; then
+ return
+ fi
+ fi
+
+ integer start end
+ if (( first < second )); then
+ start=$first end=$second
+ else
+ start=$second end=$first
+ fi
+ region_highlight+=("$start $end $region, memo=zsh-syntax-highlighting")
+}
+
+
+# -------------------------------------------------------------------------------------------------
+# API/utility functions for highlighters
+# -------------------------------------------------------------------------------------------------
+
+# Array used by highlighters to declare user overridable styles.
+typeset -gA ZSH_HIGHLIGHT_STYLES
+
+# 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" ]]
+}
+
+# Whether the cursor has moved or not.
+#
+# 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))
+}
+
+# Add a highlight defined by ZSH_HIGHLIGHT_STYLES.
+#
+# Should be used by all highlighters aside from 'pattern' (cf. ZSH_HIGHLIGHT_PATTERN).
+# Overwritten in tests/test-highlighting.zsh when testing.
+_zsh_highlight_add_highlight()
+{
+ local -i start end
+ local highlight
+ start=$1
+ end=$2
+ shift 2
+ for highlight; do
+ if (( $+ZSH_HIGHLIGHT_STYLES[$highlight] )); then
+ region_highlight+=("$start $end $ZSH_HIGHLIGHT_STYLES[$highlight], memo=zsh-syntax-highlighting")
+ break
+ fi
+ done
+}
+
+# -------------------------------------------------------------------------------------------------
+# Setup functions
+# -------------------------------------------------------------------------------------------------
+
+# Helper for _zsh_highlight_bind_widgets
+# $1 is name of widget to call
+_zsh_highlight_call_widget()
+{
+ builtin zle "$@" &&
+ _zsh_highlight
+}
+
+# Decide whether to use the zle-line-pre-redraw codepath (colloquially known as
+# "feature/redrawhook", after the topic branch's name) or the legacy "bind all
+# widgets" codepath.
+#
+# We use the new codepath under two conditions:
+#
+# 1. If it's available, which we check by testing for add-zle-hook-widget's availability.
+#
+# 2. If zsh has the memo= feature, which is required for interoperability reasons.
+# See issues #579 and #735, and the issues referenced from them.
+#
+# We check this with a plain version number check, since a functional check,
+# as done by _zsh_highlight, can only be done from inside a widget
+# function — a catch-22.
+#
+# See _zsh_highlight for the magic version number.
+if is-at-least 5.8.1.1 $ZSH_VERSION.0.0 && _zsh_highlight__function_callable_p add-zle-hook-widget
+then
+ autoload -U add-zle-hook-widget
+ _zsh_highlight__zle-line-finish() {
+ # Reset $WIDGET since the 'main' highlighter depends on it.
+ #
+ # Since $WIDGET is declared by zle as read-only in this function's scope,
+ # a nested function is required in order to shadow its built-in value;
+ # see "User-defined widgets" in zshall.
+ () {
+ local -h -r WIDGET=zle-line-finish
+ _zsh_highlight
+ }
+ }
+ _zsh_highlight__zle-line-pre-redraw() {
+ # Set $? to 0 for _zsh_highlight. Without this, subsequent
+ # zle-line-pre-redraw hooks won't run, since add-zle-hook-widget happens to
+ # call us with $? == 1 in the common case.
+ true && _zsh_highlight "$@"
+ }
+ _zsh_highlight_bind_widgets(){}
+ if [[ -o zle ]]; then
+ add-zle-hook-widget zle-line-pre-redraw _zsh_highlight__zle-line-pre-redraw
+ add-zle-hook-widget zle-line-finish _zsh_highlight__zle-line-finish
+ fi
+else
+ # Rebind all ZLE widgets to make them invoke _zsh_highlights.
+ _zsh_highlight_bind_widgets()
+ {
+ setopt localoptions noksharrays
+ typeset -F SECONDS
+ local prefix=orig-s$SECONDS-r$RANDOM # unique each time, in case we're sourced more than once
+
+ # Load ZSH module zsh/zleparameter, needed to override user defined widgets.
+ zmodload zsh/zleparameter 2>/dev/null || {
+ print -r -- >&2 'zsh-syntax-highlighting: failed loading zsh/zleparameter.'
+ return 1
+ }
+
+ # Override ZLE widgets to make them invoke _zsh_highlight.
+ local -U widgets_to_bind
+ widgets_to_bind=(${${(k)widgets}:#(.*|run-help|which-command|beep|set-local-history|yank|yank-pop)})
+
+ # Always wrap special zle-line-finish widget. This is needed to decide if the
+ # current line ends and special highlighting logic needs to be applied.
+ # E.g. remove cursor imprint, don't highlight partial paths, ...
+ widgets_to_bind+=(zle-line-finish)
+
+ # Always wrap special zle-isearch-update widget to be notified of updates in isearch.
+ # This is needed because we need to disable highlighting in that case.
+ widgets_to_bind+=(zle-isearch-update)
+
+ local cur_widget
+ for cur_widget in $widgets_to_bind; do
+ case ${widgets[$cur_widget]:-""} in
+
+ # Already rebound event: do nothing.
+ user:_zsh_highlight_widget_*);;
+
+ # The "eval"'s are required to make $cur_widget a closure: the value of the parameter at function
+ # definition time is used.
+ #
+ # We can't use ${0/_zsh_highlight_widget_} because these widgets are always invoked with
+ # NO_function_argzero, regardless of the option's setting here.
+
+ # User defined widget: override and rebind old one with prefix "orig-".
+ user:*) zle -N $prefix-$cur_widget ${widgets[$cur_widget]#*:}
+ eval "_zsh_highlight_widget_${(q)prefix}-${(q)cur_widget}() { _zsh_highlight_call_widget ${(q)prefix}-${(q)cur_widget} -- \"\$@\" }"
+ zle -N $cur_widget _zsh_highlight_widget_$prefix-$cur_widget;;
+
+ # Completion widget: override and rebind old one with prefix "orig-".
+ completion:*) zle -C $prefix-$cur_widget ${${(s.:.)widgets[$cur_widget]}[2,3]}
+ eval "_zsh_highlight_widget_${(q)prefix}-${(q)cur_widget}() { _zsh_highlight_call_widget ${(q)prefix}-${(q)cur_widget} -- \"\$@\" }"
+ zle -N $cur_widget _zsh_highlight_widget_$prefix-$cur_widget;;
+
+ # Builtin widget: override and make it call the builtin ".widget".
+ builtin) eval "_zsh_highlight_widget_${(q)prefix}-${(q)cur_widget}() { _zsh_highlight_call_widget .${(q)cur_widget} -- \"\$@\" }"
+ zle -N $cur_widget _zsh_highlight_widget_$prefix-$cur_widget;;
+
+ # Incomplete or nonexistent widget: Bind to z-sy-h directly.
+ *)
+ if [[ $cur_widget == zle-* ]] && (( ! ${+widgets[$cur_widget]} )); then
+ _zsh_highlight_widget_${cur_widget}() { :; _zsh_highlight }
+ zle -N $cur_widget _zsh_highlight_widget_$cur_widget
+ else
+ # Default: unhandled case.
+ print -r -- >&2 "zsh-syntax-highlighting: unhandled ZLE widget ${(qq)cur_widget}"
+ print -r -- >&2 "zsh-syntax-highlighting: (This is sometimes caused by doing \`bindkey <keys> ${(q-)cur_widget}\` without creating the ${(qq)cur_widget} widget with \`zle -N\` or \`zle -C\`.)"
+ fi
+ esac
+ done
+ }
+fi
+
+# Load highlighters from directory.
+#
+# Arguments:
+# 1) Path to the highlighters directory.
+_zsh_highlight_load_highlighters()
+{
+ setopt localoptions noksharrays bareglobqual
+
+ # Check the directory exists.
+ [[ -d "$1" ]] || {
+ print -r -- >&2 "zsh-syntax-highlighting: highlighters directory ${(qq)1} not found."
+ 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"
+ if type "_zsh_highlight_highlighter_${highlighter}_paint" &> /dev/null &&
+ type "_zsh_highlight_highlighter_${highlighter}_predicate" &> /dev/null;
+ then
+ # New (0.5.0) function names
+ elif type "_zsh_highlight_${highlighter}_highlighter" &> /dev/null &&
+ type "_zsh_highlight_${highlighter}_highlighter_predicate" &> /dev/null;
+ then
+ # Old (0.4.x) function names
+ if false; then
+ # TODO: only show this warning for plugin authors/maintainers, not for end users
+ 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"
+ fi
+ # Make it work.
+ eval "_zsh_highlight_highlighter_${(q)highlighter}_paint() { _zsh_highlight_${(q)highlighter}_highlighter \"\$@\" }"
+ eval "_zsh_highlight_highlighter_${(q)highlighter}_predicate() { _zsh_highlight_${(q)highlighter}_highlighter_predicate \"\$@\" }"
+ else
+ 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"}."
+ fi
+ done
+}
+
+
+# -------------------------------------------------------------------------------------------------
+# Setup
+# -------------------------------------------------------------------------------------------------
+
+# Try binding widgets.
+_zsh_highlight_bind_widgets || {
+ print -r -- >&2 'zsh-syntax-highlighting: failed binding ZLE widgets, exiting.'
+ return 1
+}
+
+# Resolve highlighters directory location.
+_zsh_highlight_load_highlighters "${ZSH_HIGHLIGHT_HIGHLIGHTERS_DIR:-${${0:A}:h}/highlighters}" || {
+ print -r -- >&2 'zsh-syntax-highlighting: failed loading highlighters, exiting.'
+ return 1
+}
+
+# Reset scratch variables when commandline is done.
+_zsh_highlight_preexec_hook()
+{
+ typeset -g _ZSH_HIGHLIGHT_PRIOR_BUFFER=
+ typeset -gi _ZSH_HIGHLIGHT_PRIOR_CURSOR=
+}
+autoload -Uz add-zsh-hook
+add-zsh-hook preexec _zsh_highlight_preexec_hook 2>/dev/null || {
+ print -r -- >&2 'zsh-syntax-highlighting: failed loading add-zsh-hook.'
+ }
+
+# Load zsh/parameter module if available
+zmodload zsh/parameter 2>/dev/null || true
+
+# Initialize the array of active highlighters if needed.
+[[ $#ZSH_HIGHLIGHT_HIGHLIGHTERS -eq 0 ]] && ZSH_HIGHLIGHT_HIGHLIGHTERS=(main)
+
+if (( $+X_ZSH_HIGHLIGHT_DIRS_BLACKLIST )); then
+ print >&2 'zsh-syntax-highlighting: X_ZSH_HIGHLIGHT_DIRS_BLACKLIST is deprecated. Please use ZSH_HIGHLIGHT_DIRS_BLACKLIST.'
+ ZSH_HIGHLIGHT_DIRS_BLACKLIST=($X_ZSH_HIGHLIGHT_DIRS_BLACKLIST)
+ unset X_ZSH_HIGHLIGHT_DIRS_BLACKLIST
+fi
+
+# Restore the aliases we unned
+eval "$zsh_highlight__aliases"
+builtin unset zsh_highlight__aliases
+
+# Set $?.
+true