diff options
Diffstat (limited to 'dot-oh-my-zsh/custom/plugins')
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% +``` + + + +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 +``` + + + +*(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 +``` + + + +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% +``` + + + + + + + +#### 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% +``` + + + +> 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 +``` + + + +- 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)' +``` + + + + + +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. + + + +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]}" +``` + + + +- 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 + +* Phase 2. Filtering with fzf + + +- 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' +``` + + + +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}' "$@" +} +``` + + + +- 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> + + + +### Branches + +<kbd>CTRL-G</kbd><kbd>CTRL-B</kbd> + + + +### Commit hashes + +<kbd>CTRL-G</kbd><kbd>CTRL-H</kbd> + + + +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' +``` + + + +```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' +``` + + + +```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' +``` + + + +```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' +``` + + + +```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' +``` + + + +### 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"> [](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`) + +[](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 Binary files differnew file mode 100644 index 00000000..368c44ee --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/alias-expansion.png 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 Binary files differnew file mode 100644 index 00000000..fb4b8441 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/file-search.gif 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 Binary files differnew file mode 100644 index 00000000..d9e8572d --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-lines.png 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 Binary files differnew file mode 100644 index 00000000..5b9eb220 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-menu.png 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 Binary files differnew file mode 100644 index 00000000..c240303e --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/history-search.gif 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 Binary files differnew file mode 100644 index 00000000..b5775af6 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/multi-select.png 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 Binary files differnew file mode 100644 index 00000000..5769108e --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/recent-dirs.png 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 Binary files differnew file mode 100644 index 00000000..364f5c71 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/requoted.png 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 Binary files differnew file mode 100644 index 00000000..b02921f6 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-autocomplete/.img/unambiguous.png 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. + +[](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. + +[](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. + + + +### Multi-selection +Press <kbd>Ctrl</kbd><kbd>Space</kbd> in the completion menu or the history menu to insert more +than one item. + + + +### 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`. + + + +## 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 + +[](https://circleci.com/gh/zsh-users/zsh-autosuggestions) +[](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: [](images/before1.png) +<br/> +After: [](images/after1.png) + +Before: [](images/before2.png) +<br/> +After: [](images/after2.png) + +Before: [](images/before3.png) +<br/> +After: [](images/after3.png) + +Before: [](images/before4-smaller.png) +<br/> +After: [](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 Binary files differnew file mode 100644 index 00000000..768294c3 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1-smaller.png 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 Binary files differnew file mode 100644 index 00000000..ea378d3e --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after1.png 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 Binary files differnew file mode 100644 index 00000000..8b5b1f8f --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2-smaller.png 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 Binary files differnew file mode 100644 index 00000000..ddcbfad7 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after2.png 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 Binary files differnew file mode 100644 index 00000000..d6aaa7bd --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3-smaller.png 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 Binary files differnew file mode 100644 index 00000000..7a0af887 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after3.png 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 Binary files differnew file mode 100644 index 00000000..fc946cf0 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/after4-smaller.png 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 Binary files differnew file mode 100644 index 00000000..b29551ea --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1-smaller.png 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 Binary files differnew file mode 100644 index 00000000..80c6f54f --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before1.png 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 Binary files differnew file mode 100644 index 00000000..991a716d --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2-smaller.png 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 Binary files differnew file mode 100644 index 00000000..48cfc327 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before2.png 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 Binary files differnew file mode 100644 index 00000000..e525c6d4 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3-smaller.png 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 Binary files differnew file mode 100644 index 00000000..40c36015 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before3.png 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 Binary files differnew file mode 100644 index 00000000..2dbd0588 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/before4-smaller.png 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 Binary files differnew file mode 100644 index 00000000..6fb84d18 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview-smaller.png 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 Binary files differnew file mode 100644 index 00000000..545cc511 --- /dev/null +++ b/dot-oh-my-zsh/custom/plugins/zsh-syntax-highlighting/images/preview.png 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 |
