├── zephyr.plugin.zsh ├── plugins ├── macos │ ├── functions │ │ ├── _manp │ │ ├── cdf │ │ ├── ofd │ │ ├── pushdf │ │ ├── flushdns │ │ ├── peek │ │ ├── rmdsstore │ │ ├── showfiles │ │ ├── hidefiles │ │ ├── lmk │ │ ├── pfd │ │ ├── manp │ │ ├── pfs │ │ ├── mand │ │ └── trash │ ├── macos.plugin.zsh │ └── README.md ├── homebrew │ ├── README.md │ └── homebrew.plugin.zsh ├── prompt │ ├── themes │ │ ├── prezto.toml │ │ ├── hydro.toml │ │ └── zephyr.toml │ └── prompt.plugin.zsh ├── helper │ ├── README.md │ └── helper.plugin.zsh ├── confd │ └── confd.plugin.zsh ├── directory │ ├── directory.plugin.zsh │ └── README.md ├── color │ ├── README.md │ └── color.plugin.zsh ├── history │ └── history.plugin.zsh ├── utility │ └── utility.plugin.zsh ├── zfunctions │ ├── zfunctions.plugin.zsh │ └── README.md ├── environment │ └── environment.plugin.zsh ├── completion │ └── completion.plugin.zsh ├── compstyle │ └── compstyle.plugin.zsh └── editor │ └── editor.plugin.zsh ├── .gitignore ├── runcoms ├── zshenv.zsh ├── zshrc.zsh └── zstyles.zsh ├── .editorconfig ├── makefile ├── tests ├── test_color.md ├── test_zfunctions.md ├── runtests ├── test_utility.md ├── test_macos.md ├── test_helper.md ├── test_prompt.md ├── test_editor.md ├── test_environment.md ├── test_homebrew.md ├── test_directory.md ├── test_completion.md ├── test_history.md ├── test_confd.md └── __init__.zsh ├── LICENSE ├── zephyr.zsh ├── lib └── bootstrap.zsh ├── bin └── zephyr └── README.md /zephyr.plugin.zsh: -------------------------------------------------------------------------------- 1 | 0=${(%):-%N} 2 | source ${0:a:h}/zephyr.zsh 3 | -------------------------------------------------------------------------------- /plugins/macos/functions/_manp: -------------------------------------------------------------------------------- 1 | #compdef manp 2 | #autoload 3 | 4 | # completions for manp match man 5 | _man 6 | -------------------------------------------------------------------------------- /plugins/macos/functions/cdf: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? cdf - Change to the current Finder directory. 3 | cd "$(pfd)" 4 | -------------------------------------------------------------------------------- /plugins/macos/functions/ofd: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? ofd - Open the current directory in Finder 3 | open "$PWD" 4 | -------------------------------------------------------------------------------- /plugins/macos/functions/pushdf: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # pushdf - Push the current Finder directory to the dirstack. 3 | pushd "$(pfd)" 4 | -------------------------------------------------------------------------------- /plugins/macos/functions/flushdns: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? flushdns - Flush the DNS cache. 3 | dscacheutil -flushcache && sudo killall -HUP mDNSResponder 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ~* 2 | *.zwc 3 | *.zwc.old 4 | .external/ 5 | .prompts/ 6 | contribs/ 7 | prompts/*/ 8 | !prompts/functions 9 | .cache/ 10 | .foo/ 11 | -------------------------------------------------------------------------------- /plugins/macos/functions/peek: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? peek - Take a quick look at a file using an appropriate viewer 3 | (( $# > 0 )) && qlmanage -p $* &>/dev/null & 4 | -------------------------------------------------------------------------------- /plugins/macos/functions/rmdsstore: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? rmdsstore - Remove .DS_Store files recursively in a directory. 3 | find "${@:-.}" -type f -name .DS_Store -delete 4 | -------------------------------------------------------------------------------- /plugins/macos/functions/showfiles: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? showfiles - Show hidden dotfiles in Finder. 3 | defaults write com.apple.finder AppleShowAllFiles -bool true && killall Finder 4 | -------------------------------------------------------------------------------- /plugins/macos/functions/hidefiles: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? hidefiles - Hide hidden dotfiles in Finder. 3 | defaults write com.apple.finder AppleShowAllFiles -bool false && killall Finder 4 | -------------------------------------------------------------------------------- /runcoms/zshenv.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # .zshenv - Define Zsh environment variables. 4 | # 5 | 6 | # Set ZDOTDIR to move your Zsh config out of $HOME. 7 | export ZDOTDIR=${ZDOTDIR:-$HOME/.config/zsh} 8 | -------------------------------------------------------------------------------- /plugins/macos/functions/lmk: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? lmk - Have Siri let me know when a process is complete. 3 | ##? 4 | ##? Example: 5 | ##? sleep 2 && lmk 6 | if (( $# )); then 7 | say "$@" 8 | else 9 | say 'Process complete.' 10 | fi 11 | -------------------------------------------------------------------------------- /plugins/macos/functions/pfd: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? pfd - Print the frontmost Finder directory. 3 | #function pfd { 4 | osascript 2> /dev/null <&2 'manp: You must specify the manual page you want' 6 | return 1 7 | fi 8 | mandoc -T pdf "$(/usr/bin/man -w $@)" | open -fa Preview 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | indent_style = space 9 | indent_size = 2 10 | 11 | [*.md] 12 | indent_style = space 13 | trim_trailing_whitespace = false 14 | 15 | [.git*] 16 | indent_style = tab 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /runcoms/zshrc.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # .zshrc - Execute commands at the start of an interactive session. 4 | # 5 | 6 | # Source Zephyr. 7 | ZEPHYR_HOME=${ZDOTDIR:-$HOME}/.zephyr 8 | [[ -d "$ZEPHYR_HOME" ]] || 9 | git clone --recursive https://github.com/mattmc3/zephyr "$ZEPHYR_HOME" 10 | source $ZEPHYR_HOME/zepyhr.zsh 11 | 12 | # Customize to your needs... 13 | -------------------------------------------------------------------------------- /plugins/macos/functions/pfs: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? pfs - Print the current Finder selection 3 | #function pfs { 4 | osascript 2>&1 < /dev/null 11 | if test $? -ne 0; then 12 | echo >&2 "$0: Dash is not installed" 13 | return 2 14 | fi 15 | -------------------------------------------------------------------------------- /plugins/homebrew/README.md: -------------------------------------------------------------------------------- 1 | # homebrew 2 | 3 | > Zsh goodies for Homebrew users 4 | 5 | ## Description 6 | 7 | Sets `brew` environment variables from `brew shellenv`. 8 | 9 | ## Aliases 10 | 11 | | Function | Description | 12 | | ---------- | ------------------------------------- | 13 | | `brewdeps` | Show brewed formulae and dependencies | 14 | | `brewinfo` | Show descriptions of brew installs | 15 | | `brewup` | brew update/upgrade/cleanup | 16 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | ##? zephyr - A Zsh framework as nice as a cool summer breeze 2 | ##? 3 | ##? Usage: make 4 | ##? 5 | ##? Commands: 6 | 7 | .DEFAULT_GOAL := help 8 | all : build help test submodules 9 | .PHONY : all 10 | 11 | ##? build run build tasks 12 | build: 13 | ./bin/build_external 14 | 15 | ##? test run cli tests 16 | test: 17 | ./tests/runtests 18 | 19 | ##? submodules update all submodules 20 | submodules: 21 | git submodule update --recursive --remote 22 | 23 | ##? help show this message 24 | help: 25 | @grep "^##?" makefile | cut -c 5- 26 | -------------------------------------------------------------------------------- /plugins/macos/macos.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # macos: Aliases and functions for macOS users. 4 | # 5 | 6 | # References 7 | # - https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/macos 8 | # - https://github.com/sorin-ionescu/prezto/tree/master/modules/osx 9 | #endregion 10 | 11 | # Return if requirements are not met. 12 | [[ "$OSTYPE" == darwin* ]] || return 1 13 | ! zstyle -t ":zephyr:plugin:macos" skip || return 0 14 | 15 | # Load plugin functions. 16 | 0=${(%):-%N} 17 | fpath=(${0:a:h}/functions $fpath) 18 | autoload -Uz ${0:a:h}/functions/*(.:t) 19 | 20 | #region MARK LOADED 21 | zstyle ':zephyr:plugin:macos' loaded 'yes' 22 | #endregion 23 | -------------------------------------------------------------------------------- /tests/test_color.md: -------------------------------------------------------------------------------- 1 | # Color 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % test $+functions[colors] = 0 #=> --exit 0 15 | % printf '%s\n' ${(q)LESS_TERMCAP_md} 16 | '' 17 | % 18 | ``` 19 | 20 | Initialize plugin 21 | 22 | ```zsh 23 | % source $ZEPHYR_HOME/plugins/color/color.plugin.zsh 24 | % 25 | ``` 26 | 27 | Test plugin is initialized 28 | 29 | ```zsh 30 | % test $+functions[colors] = 0 #=> --exit 1 31 | % printf '%s\n' ${(q)LESS_TERMCAP_md} 32 | $'\033'\[01\;34m 33 | % 34 | ``` 35 | 36 | Teardown 37 | 38 | ```zsh 39 | % t_teardown 40 | % 41 | ``` 42 | -------------------------------------------------------------------------------- /tests/test_zfunctions.md: -------------------------------------------------------------------------------- 1 | # zfunctions 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % 8 | ``` 9 | 10 | Test plugin is not initialized 11 | 12 | ```zsh 13 | % test $+functions[autoload-dir] = 0 && echo "autoload-dir not defined" 14 | autoload-dir not defined 15 | % test $+functions[funced] = 0 #=> --exit 0 16 | % test $+functions[funcsave] = 0 #=> --exit 0 17 | % 18 | ``` 19 | 20 | Initialize plugin 21 | 22 | ```zsh 23 | % source $ZEPHYR_HOME/plugins/zfunctions/zfunctions.plugin.zsh 24 | % 25 | ``` 26 | 27 | Test plugin is initialized 28 | 29 | ```zsh 30 | % test $+functions[autoload-dir] = 1 #=> --exit 0 31 | % test $+functions[funced] = 1 #=> --exit 0 32 | % test $+functions[funcsave] = 1 #=> --exit 0 33 | % 34 | ``` 35 | -------------------------------------------------------------------------------- /plugins/macos/functions/trash: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? trash - Move files to macOS trash 3 | 4 | #function trash { 5 | 6 | emulate -L zsh 7 | setopt local_options extended_glob 8 | 9 | if (( $# == 0 )); then 10 | echo >&2 "Usage: trash " 11 | return 1 12 | fi 13 | 14 | if [[ $OSTYPE != darwin* ]]; then 15 | print -ru2 -- "trash: macOS not detected." 16 | return 1 17 | fi 18 | 19 | local file 20 | local -a files 21 | for file in $@; do 22 | if [[ -e $file ]]; then 23 | files+=("the POSIX file \"${file:a}\"") 24 | else 25 | print -ru2 -- "trash: No such file or directory '$file'." 26 | return 1 27 | fi 28 | done 29 | 30 | if (( $#files == 0 )); then 31 | print -ru2 -- 'usage: trash ' 32 | return 64 # match rm's return code 33 | fi 34 | 35 | osascript 2>&1 >/dev/null -e "tell app \"Finder\" to move { "${(pj., .)files}" } to trash" 36 | 37 | #} 38 | -------------------------------------------------------------------------------- /tests/runtests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 0=${(%):-%N} 3 | 4 | setopt extended_glob 5 | 6 | ZEPHYR_HOME=${0:a:h:h} 7 | cd $ZEPHYR_HOME 8 | 9 | local o_unit 10 | zparseopts -D -M -- -unit=o_unit || return 1 11 | 12 | testfiles=() 13 | if (( $# > 0 )); then 14 | testfiles=($@) 15 | elif (( $#o_unit )); then 16 | testfiles=($PWD/tests/*.md~test_real*.md) 17 | else 18 | testfiles=($PWD/tests/*.md) 19 | fi 20 | 21 | # foo example test command 22 | # env -i PATH=$PATH FPATH=$FPATH \ 23 | # zsh -f -- =clitest --list-run --progress dot --prompt '%' --color always $PWD/tests/foo.md 24 | 25 | env -i PATH=$PATH FPATH=$FPATH PAGER=cat ZEPHYR_HOME=$ZEPHYR_HOME TERM=xterm-256color \ 26 | zsh -f -- \ 27 | =clitest \ 28 | --list-run --progress dot --prompt '%' \ 29 | --color always \ 30 | --pre-flight 'git --version; print $PWD $VENDOR $OSTYPE =zsh $ZSH_VERSION $ZSH_PATCHLEVEL' \ 31 | -- $testfiles 32 | -------------------------------------------------------------------------------- /tests/test_utility.md: -------------------------------------------------------------------------------- 1 | # Utility 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:utility' loaded || echo "not loaded" 15 | not loaded 16 | % test $+functions[bracketed-paste-url-magic] = 0 #=> --exit 0 17 | % test $+functions[url-quote-magic] = 0 #=> --exit 0 18 | % test $+functions[sedi] = 0 #=> --exit 0 19 | % 20 | ``` 21 | 22 | Initialize plugin 23 | 24 | ```zsh 25 | % source $ZEPHYR_HOME/plugins/utility/utility.plugin.zsh 26 | % 27 | ``` 28 | 29 | Test plugin is initialized 30 | 31 | ```zsh 32 | % zstyle -t ':zephyr:plugin:utility' loaded || echo "not loaded" 33 | % test $+functions[bracketed-paste-url-magic] = 1 #=> --exit 0 34 | % test $+functions[url-quote-magic] = 1 #=> --exit 0 35 | % test $+functions[sedi] = 1 #=> --exit 0 36 | % 37 | ``` 38 | 39 | Teardown 40 | 41 | ```zsh 42 | % t_teardown 43 | % 44 | ``` 45 | -------------------------------------------------------------------------------- /tests/test_macos.md: -------------------------------------------------------------------------------- 1 | # macos 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:macos' loaded || echo "not loaded" 15 | not loaded 16 | % test $+functions[cdf] = 0 #=> --exit 0 17 | % test $+functions[trash] = 0 #=> --exit 0 18 | % set -o | grep 'on$' | awk '{print $1}' | sort 19 | nohashdirs 20 | norcs 21 | % 22 | ``` 23 | 24 | Initialize plugin 25 | 26 | ```zsh 27 | % source $ZEPHYR_HOME/plugins/macos/macos.plugin.zsh; setopt clobber 28 | % 29 | ``` 30 | 31 | Test plugin is initialized 32 | 33 | ```zsh 34 | % zstyle -t ':zephyr:plugin:macos' loaded || echo "not loaded" 35 | % test $+functions[cdf] = 1 #=> --exit 0 36 | % test $+functions[trash] = 1 #=> --exit 0 37 | % set -o | grep 'on$' | sort 38 | nohashdirs on 39 | norcs on 40 | % 41 | ``` 42 | 43 | Teardown 44 | 45 | ```zsh 46 | % t_teardown 47 | % 48 | ``` 49 | -------------------------------------------------------------------------------- /tests/test_helper.md: -------------------------------------------------------------------------------- 1 | # helper 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:helper' loaded || echo "not loaded" 15 | not loaded 16 | % test $+functions[is-autoloadable] = 0 #=> --exit 0 17 | % test $+functions[is-callable] = 0 #=> --exit 0 18 | % set -o | grep 'on$' | awk '{print $1}' | sort 19 | nohashdirs 20 | norcs 21 | % 22 | ``` 23 | 24 | Initialize plugin 25 | 26 | ```zsh 27 | % source $ZEPHYR_HOME/plugins/helper/helper.plugin.zsh; setopt clobber 28 | % 29 | ``` 30 | 31 | Test plugin is initialized 32 | 33 | ```zsh 34 | % zstyle -t ':zephyr:plugin:helper' loaded || echo "not loaded" 35 | % test $+functions[is-autoloadable] = 1 #=> --exit 0 36 | % test $+functions[is-callable] = 1 #=> --exit 0 37 | % set -o | grep 'on$' | sort 38 | nohashdirs on 39 | norcs on 40 | % 41 | ``` 42 | 43 | Teardown 44 | 45 | ```zsh 46 | % t_teardown 47 | % 48 | ``` 49 | -------------------------------------------------------------------------------- /tests/test_prompt.md: -------------------------------------------------------------------------------- 1 | # prompt 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:prompt' loaded || echo "not loaded" 15 | not loaded 16 | % test $+functions[run_promptinit] = 0 #=> --exit 0 17 | % test $+functions[hooks-add-hook] = 0 #=> --exit 0 18 | % set -o | grep 'on$' | awk '{print $1}' | sort 19 | nohashdirs 20 | norcs 21 | % 22 | ``` 23 | 24 | Initialize plugin 25 | 26 | ```zsh 27 | % source $ZEPHYR_HOME/plugins/prompt/prompt.plugin.zsh; setopt clobber 28 | % 29 | ``` 30 | 31 | Test plugin is initialized 32 | 33 | ```zsh 34 | % zstyle -t ':zephyr:plugin:prompt' loaded || echo "not loaded" 35 | % test $+functions[run_promptinit] = 1 #=> --exit 0 36 | % set -o | grep 'on$' | sort 37 | extendedglob on 38 | interactivecomments on 39 | nohashdirs on 40 | norcs on 41 | promptsubst on 42 | % 43 | ``` 44 | 45 | Teardown 46 | 47 | ```zsh 48 | % t_teardown 49 | % 50 | ``` 51 | -------------------------------------------------------------------------------- /tests/test_editor.md: -------------------------------------------------------------------------------- 1 | # editor 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:editor' loaded || echo "not loaded" 15 | not loaded 16 | % test $+functions[bindkey-all] = 0 #=> --exit 0 17 | % test -v key_info #=> --exit 1 18 | % set -o | grep 'on$' | awk '{print $1}' | sort 19 | nohashdirs 20 | norcs 21 | % 22 | ``` 23 | 24 | Initialize plugin 25 | 26 | ```zsh 27 | % source $ZEPHYR_HOME/plugins/editor/editor.plugin.zsh; setopt clobber 28 | % 29 | ``` 30 | 31 | Test plugin is initialized 32 | 33 | ```zsh 34 | % zstyle -t ':zephyr:plugin:editor' loaded || echo "not loaded" 35 | % test $+functions[bindkey-all] = 1 #=> --exit 0 36 | % test -v key_info #=> --exit 0 37 | % set -o | grep 'on$' | sort 38 | extendedglob on 39 | interactivecomments on 40 | nobeep on 41 | noflowcontrol on 42 | nohashdirs on 43 | norcs on 44 | % 45 | ``` 46 | 47 | Teardown 48 | 49 | ```zsh 50 | % t_teardown 51 | % 52 | ``` 53 | -------------------------------------------------------------------------------- /tests/test_environment.md: -------------------------------------------------------------------------------- 1 | # Environment 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:environment' loaded || echo "not loaded" 15 | not loaded 16 | % test -v EDITOR #=> --exit 1 17 | % test -v VISUAL #=> --exit 1 18 | % set -o | grep -v off | awk '{print $1}' | sort 19 | nohashdirs 20 | norcs 21 | % 22 | ``` 23 | 24 | Initialize plugin 25 | 26 | ```zsh 27 | % source $ZEPHYR_HOME/plugins/environment/environment.plugin.zsh 28 | % 29 | ``` 30 | 31 | Test plugin is initialized 32 | 33 | ```zsh 34 | % zstyle -t ':zephyr:plugin:environment' loaded || echo "not loaded" 35 | % test -v EDITOR #=> --exit 0 36 | % test -v VISUAL #=> --exit 0 37 | % set -o | grep 'on$' | awk '{print $1}' | sort 38 | autoresume 39 | combiningchars 40 | extendedglob 41 | interactivecomments 42 | longlistjobs 43 | nobeep 44 | nobgnice 45 | nocheckjobs 46 | nohashdirs 47 | nohup 48 | norcs 49 | rcquotes 50 | % 51 | ``` 52 | 53 | Teardown 54 | 55 | ```zsh 56 | % t_teardown 57 | % 58 | ``` 59 | -------------------------------------------------------------------------------- /tests/test_homebrew.md: -------------------------------------------------------------------------------- 1 | # homebrew 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:homebrew' loaded || echo "not loaded" 15 | not loaded 16 | % test $+aliases[brewup] = 0 #=> --exit 0 17 | % test $+aliases[brewinfo] = 0 #=> --exit 0 18 | % test $+aliases[brewdeps] = 0 #=> --exit 0 19 | % set -o | grep 'on$' | awk '{print $1}' | sort 20 | nohashdirs 21 | norcs 22 | % 23 | ``` 24 | 25 | Initialize plugin 26 | 27 | ```zsh 28 | % source $ZEPHYR_HOME/plugins/homebrew/homebrew.plugin.zsh; setopt clobber 29 | % 30 | ``` 31 | 32 | Test plugin is initialized 33 | 34 | ```zsh 35 | % zstyle -t ':zephyr:plugin:homebrew' loaded || echo "not loaded" 36 | % test $+aliases[brewup] = 1 #=> --exit 0 37 | % test $+aliases[brewinfo] = 1 #=> --exit 0 38 | % test $+aliases[brewdeps] = 1 #=> --exit 0 39 | % set -o | grep 'on$' | sort 40 | extendedglob on 41 | interactivecomments on 42 | nohashdirs on 43 | norcs on 44 | % 45 | ``` 46 | 47 | Teardown 48 | 49 | ```zsh 50 | % t_teardown 51 | % 52 | ``` 53 | -------------------------------------------------------------------------------- /tests/test_directory.md: -------------------------------------------------------------------------------- 1 | # directory 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:directory' loaded || echo "not loaded" 15 | not loaded 16 | % test $+functions[up] = 0 #=> --exit 0 17 | % test $+aliases[dirh] = 0 #=> --exit 0 18 | % set -o | grep -v off | awk '{print $1}' | sort 19 | nohashdirs 20 | norcs 21 | % 22 | ``` 23 | 24 | Initialize plugin 25 | 26 | ```zsh 27 | % source $ZEPHYR_HOME/plugins/directory/directory.plugin.zsh; setopt clobber 28 | % 29 | ``` 30 | 31 | Test plugin is initialized 32 | 33 | ```zsh 34 | % zstyle -t ':zephyr:plugin:directory' loaded || echo "not loaded" 35 | % test $+functions[up] = 1 #=> --exit 0 36 | % test $+aliases[dirh] = 1 #=> --exit 0 37 | % set -o | grep 'on$' | sort 38 | autopushd on 39 | extendedglob on 40 | globdots on 41 | nohashdirs on 42 | norcs on 43 | pushdminus on 44 | pushdsilent on 45 | pushdtohome on 46 | % 47 | ``` 48 | 49 | Teardown 50 | 51 | ```zsh 52 | % t_teardown 53 | % 54 | ``` 55 | -------------------------------------------------------------------------------- /tests/test_completion.md: -------------------------------------------------------------------------------- 1 | # completion 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:completion' loaded || echo "not loaded" 15 | not loaded 16 | % test $+functions[compinit] = 0 #=> --exit 0 17 | % test $+functions[compstyle_zephyr_setup] = 0 #=> --exit 0 18 | % set -o | grep 'on$' | awk '{print $1}' | sort 19 | nohashdirs 20 | norcs 21 | % 22 | ``` 23 | 24 | Initialize plugin 25 | 26 | ```zsh 27 | % source $ZEPHYR_HOME/plugins/completion/completion.plugin.zsh; setopt clobber 28 | % 29 | ``` 30 | 31 | Test plugin is initialized 32 | 33 | ```zsh 34 | % zstyle -t ':zephyr:plugin:completion' loaded || echo "not loaded" 35 | % test $+functions[compinit] = 1 #=> --exit 0 36 | % test $+functions[compstyle_zephyr_setup] = 1 #=> --exit 0 37 | % set -o | grep 'on$' | sort 38 | alwaystoend on 39 | completeinword on 40 | extendedglob on 41 | interactivecomments on 42 | nocaseglob on 43 | noflowcontrol on 44 | nohashdirs on 45 | norcs on 46 | pathdirs on 47 | % 48 | ``` 49 | 50 | Teardown 51 | 52 | ```zsh 53 | % t_teardown 54 | % 55 | ``` 56 | -------------------------------------------------------------------------------- /plugins/prompt/themes/prezto.toml: -------------------------------------------------------------------------------- 1 | # 2 | # prezto - mimic the default prezto prompt (sorin) 3 | # 4 | 5 | add_newline = false 6 | 7 | # A minimal left prompt 8 | format = """$python$directory$character""" 9 | 10 | # move the rest of the prompt to the right 11 | right_format = """$status$git_branch$git_status""" 12 | 13 | [character] 14 | success_symbol = "[❯](red)[❯](yellow)[❯](green)" 15 | error_symbol = "[❯](red)[❯](yellow)[❯](green)" 16 | vicmd_symbol = "[❮](green)[❮](yellow)[❮](red)" 17 | 18 | [git_branch] 19 | format = '[$branch]($style) ' 20 | style = 'bold green' 21 | 22 | [python] 23 | format = '[(\($virtualenv\) )]($style)' 24 | style = 'white' 25 | 26 | [git_status] 27 | format = '$all_status$ahead_behind ' 28 | ahead = '[⬆](bold purple) ' 29 | behind = '[⬇](bold purple) ' 30 | staged = '[✚](green) ' 31 | deleted = '[✖](red) ' 32 | renamed = '[➜](purple) ' 33 | stashed = '[✭](cyan) ' 34 | untracked = '[◼](white) ' 35 | modified = '[✱](blue) ' 36 | conflicted = '[═](yellow) ' 37 | diverged = '⇕ ' 38 | up_to_date = '' 39 | 40 | [directory] 41 | style = "blue" 42 | truncation_length = 1 43 | truncation_symbol = "" 44 | fish_style_pwd_dir_length = 1 45 | 46 | [cmd_duration] 47 | format = '[$duration]($style) ' 48 | 49 | [line_break] 50 | disabled = true 51 | 52 | [status] 53 | disabled = false 54 | symbol = '✘ ' 55 | -------------------------------------------------------------------------------- /tests/test_history.md: -------------------------------------------------------------------------------- 1 | # history 2 | 3 | Init 4 | 5 | ```zsh 6 | % source ./tests/__init__.zsh 7 | % t_setup 8 | % 9 | ``` 10 | 11 | Test plugin is not initialized 12 | 13 | ```zsh 14 | % zstyle -t ':zephyr:plugin:history' loaded || echo "not loaded" 15 | not loaded 16 | % test "$SAVEHIST" -le 1000 #=> --exit 0 17 | % test "$HISTSIZE" -le 2000 #=> --exit 0 18 | % set -o | grep 'on$' | awk '{print $1}' | sort 19 | nohashdirs 20 | norcs 21 | % 22 | ``` 23 | 24 | Initialize plugin 25 | 26 | ```zsh 27 | % source $ZEPHYR_HOME/plugins/history/history.plugin.zsh; setopt clobber 28 | % 29 | ``` 30 | 31 | Test plugin is initialized 32 | 33 | ```zsh 34 | % zstyle -t ':zephyr:plugin:history' loaded || echo "not loaded" 35 | % echo "$SAVEHIST" 36 | 100000 37 | % echo "$HISTSIZE" 38 | 20000 39 | % set -o | grep 'on$' | sort 40 | extendedglob on 41 | extendedhistory on 42 | histexpiredupsfirst on 43 | histfindnodups on 44 | histignorealldups on 45 | histignoredups on 46 | histignorespace on 47 | histreduceblanks on 48 | histsavenodups on 49 | histverify on 50 | incappendhistory on 51 | interactivecomments on 52 | nohashdirs on 53 | nohistbeep on 54 | norcs on 55 | % 56 | ``` 57 | 58 | Teardown 59 | 60 | ```zsh 61 | % t_teardown 62 | % 63 | ``` 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2009-2011 Robby Russell and contributors 4 | Copyright (c) 2011-2017 Sorin Ionescu and contributors 5 | Copyright (c) 2018-2019 Kaleb Elwert and contributors 6 | Copyright (c) 2022- Matt McElheny and contributors 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | -------------------------------------------------------------------------------- /zephyr.zsh: -------------------------------------------------------------------------------- 1 | # Zephyr - Nice as a summer breeze. 2 | 3 | # Bootstrap Zephyr. 4 | 0=${(%):-%N} 5 | ZEPHYR_HOME=${0:a:h} 6 | source $ZEPHYR_HOME/lib/bootstrap.zsh 7 | 8 | # Set which plugins to load. It doesn't really matter if we include plugins we don't 9 | # need (eg: running Linux, not macOS) because the plugins themselves check and exit 10 | # if requirements aren't met. 11 | zstyle -a ':zephyr:load' plugins '_zephyr_plugins' || 12 | _zephyr_plugins=( 13 | environment 14 | homebrew 15 | color 16 | compstyle 17 | completion 18 | directory 19 | editor 20 | helper 21 | history 22 | prompt 23 | utility 24 | zfunctions 25 | macos 26 | confd 27 | ) 28 | 29 | for _zephyr_plugin in $_zephyr_plugins; do 30 | # Allow overriding plugins. 31 | _initfiles=( 32 | ${ZSH_CUSTOM:-$__zsh_config_dir}/plugins/${_zephyr_plugin}/${_zephyr_plugin}.plugin.zsh(N) 33 | $ZEPHYR_HOME/plugins/${_zephyr_plugin}/${_zephyr_plugin}.plugin.zsh(N) 34 | ) 35 | if (( $#_initfiles )); then 36 | source "$_initfiles[1]" 37 | if [[ $? -eq 0 ]]; then 38 | zstyle ":zephyr:plugin:$_zephyr_plugin" loaded 'yes' 39 | else 40 | zstyle ":zephyr:plugin:$_zephyr_plugin" loaded 'no' 41 | fi 42 | else 43 | echo >&2 "zephyr: Plugin not found '$_zephyr_plugin'." 44 | fi 45 | done 46 | 47 | # Clean up. 48 | unset _zephyr_plugin{s,} _initfiles 49 | -------------------------------------------------------------------------------- /plugins/prompt/themes/hydro.toml: -------------------------------------------------------------------------------- 1 | # 2 | # hydro - mimic Fish's hydro prompt 3 | # 4 | 5 | add_newline = false 6 | 7 | # A minimal left prompt 8 | format = """$all$directory$git_branch${custom.git_status_dirty}$git_status$cmd_duration$status$character""" 9 | 10 | # no right prompt 11 | right_format = "" 12 | 13 | # Timeout for commands executed by starship (in milliseconds) 14 | command_timeout=2000 15 | 16 | [character] 17 | success_symbol = "[❱](purple)" 18 | error_symbol = "[❱](red)" 19 | vicmd_symbol = "[❰](cyan)" 20 | 21 | [python] 22 | format = '[(\($virtualenv\) )]($style)' 23 | style = 'white' 24 | 25 | [directory] 26 | style = "blue" 27 | truncation_length = 1 28 | truncation_symbol = "" 29 | fish_style_pwd_dir_length = 1 30 | 31 | # right prompt uses left space padding 32 | [git_branch] 33 | format = '[$branch]($style)' 34 | style = 'bold green' 35 | 36 | [git_status] 37 | format = "[($ahead_behind$stashed)]($style) " 38 | style = "cyan" 39 | stashed = "≡" 40 | ahead = "⇡${count}" 41 | behind = "⇣${count}" 42 | diverged = "⇕⇡${ahead_count}⇣${behind_count}" 43 | 44 | [custom.git_status_dirty] 45 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 46 | symbol = "•" 47 | style = "white" 48 | format="[$symbol]($style)" 49 | shell = ["zsh", "--no-rcs", "--no-globalrcs"] 50 | 51 | [cmd_duration] 52 | format = '[$duration]($style) ' 53 | 54 | [line_break] 55 | disabled = true 56 | 57 | [status] 58 | disabled = false 59 | pipestatus = true 60 | format = '[$symbol$int]($style)' 61 | symbol = '✘' 62 | pipestatus_format = '\[$pipestatus\]($style)' 63 | -------------------------------------------------------------------------------- /plugins/helper/README.md: -------------------------------------------------------------------------------- 1 | # Helper 2 | 3 | > Add common helper functions. 4 | 5 | ## Options 6 | 7 | This plugin sets no Zsh options. 8 | 9 | ## Functions 10 | 11 | This plugin adds the following functions: 12 | 13 | | function | description | 14 | | ------------------------ | ----------------------------------------------------------------------------------- | 15 | | `is-autoloadable ` | Checks if a function can be autoloaded by trying to load it in a subshell | 16 | | `is-callable ` | Checks if a name is a command, function, or alias. | 17 | | `is-true ` | Checks if a value is a string representation of `true` (eg: 1, yes, y, t, on, etc.) | 18 | | `is-macos` | Checks if the OS is macOS | 19 | | `is-linux` | Checks if the OS is Linux | 20 | | `is-bsd` | Checks if the OS is BSD | 21 | | `is-cygwin` | Checks if the OS is Cygwin | 22 | | `is-termux` | Checks if the OS is Android | 23 | 24 | ## Aliases 25 | 26 | This plugin sets no aliases. 27 | 28 | ## Variables 29 | 30 | This plugin sets no variables. 31 | 32 | ## Customizations 33 | 34 | This plugin does not have any zstyles for customization. 35 | -------------------------------------------------------------------------------- /plugins/confd/confd.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # conf.d: Use a Fish-like conf.d directory for sourcing configs. 4 | # 5 | 6 | 0=${(%):-%N} 7 | zstyle -t ':zephyr:lib:bootstrap' loaded || source ${0:a:h:h:h}/lib/bootstrap.zsh 8 | #endregion 9 | 10 | # Return if requirements are not met. 11 | ! zstyle -t ":zephyr:plugin:confd" skip || return 0 12 | 13 | function run_confd { 14 | # Find the conf.d directory. 15 | local confd user_confd 16 | zstyle -a ':zephyr:plugin:confd' directory 'user_confd' 17 | local -a confd_choices=( 18 | ${~user_confd} 19 | $__zsh_config_dir/conf.d(N) 20 | $__zsh_config_dir/zshrc.d(N) 21 | $__zsh_config_dir/rc.d(N) 22 | ${ZDOTDIR:-$HOME}/.zshrc.d(N) 23 | ) 24 | confd=$confd_choices[1] 25 | #echo "THE CONFD DIR IS: $confd" 26 | if [[ ! -e "$confd" ]]; then 27 | echo >&2 "confd: dir not found '${confd:-$__zsh_config_dir/conf.d}'." 28 | return 1 29 | fi 30 | 31 | # Sort and source all scripts in conf.d. 32 | local rc; local -a rcs=(${confd}/*.{z,}sh(N)) 33 | for rc in ${(o)rcs}; do 34 | # ignore files that begin with ~ 35 | [[ "${rc:t}" != '~'* ]] || continue 36 | source "$rc" 37 | done 38 | 39 | # We can run this early, so if we did we no longer need a post_zshrc hook. 40 | post_zshrc_hook=(${post_zshrc_hook:#run_confd}) 41 | } 42 | 43 | # Allow the user to bypass the confd deferral and run it immediately. Otherwise, we 44 | # hook run_confd to the custom post_zshrc event. 45 | if zstyle -t ':zephyr:plugin:confd' immediate; then 46 | run_confd || return 1 47 | else 48 | post_zshrc_hook+=(run_confd) 49 | fi 50 | 51 | #region MARK LOADED 52 | zstyle ':zephyr:plugin:confd' loaded 'yes' 53 | #endregion 54 | -------------------------------------------------------------------------------- /plugins/macos/README.md: -------------------------------------------------------------------------------- 1 | # macos 2 | 3 | > Zsh goodies for MacOS users 4 | 5 | ## Options 6 | 7 | This plugin sets no Zsh options. 8 | 9 | ## Functions 10 | 11 | This plugin adds the following functions: 12 | 13 | | function | description | 14 | | ----------- | --------------------------------------------------------------------- | 15 | | `cdf` | Change to the current Finder directory | 16 | | `flushdns` | Flush the DNS cache | 17 | | `hidefiles` | Hide hidden dotfiles in Finder | 18 | | `lmk` | Have Siri 'Let me know' when command completes (ex: `sleep 2 && lmk`) | 19 | | `mand` | Read man page with Dash.app | 20 | | `manp` | Read man page with Preview.app | 21 | | `ofd` | Open the current directory in Finder | 22 | | `peek` | Quick look at a file | 23 | | `pfd` | Print the frontmost Finder directory | 24 | | `pfs` | Print the current Finder selection | 25 | | `pushdf` | Push to the current Finder directory to the dirstack | 26 | | `rmdsstore` | Remove .DS_Store files recursively in a directory | 27 | | `showfiles` | Show hidden dotfiles in Finder | 28 | | `trash` | Move a file or folder to the macOS trashcan | 29 | 30 | ## Aliases 31 | 32 | This plugin sets no aliases. 33 | 34 | ## Variables 35 | 36 | This plugin sets no variables. 37 | 38 | ## Customizations 39 | 40 | This plugin does not have any zstyles for customization. 41 | -------------------------------------------------------------------------------- /plugins/directory/directory.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # directory: Set features related to Zsh directories and dirstack. 4 | # 5 | #endregion 6 | 7 | # Return if requirements are not met. 8 | [[ "$TERM" != 'dumb' ]] || return 1 9 | ! zstyle -t ":zephyr:plugin:directory" skip || return 0 10 | 11 | # Set Zsh options related to directories, globbing, and I/O. 12 | setopt auto_pushd # Make cd push the old directory onto the dirstack. 13 | setopt pushd_minus # Exchanges meanings of +/- when navigating the dirstack. 14 | setopt pushd_silent # Do not print the directory stack after pushd or popd. 15 | setopt pushd_to_home # Push to home directory when no argument is given. 16 | setopt multios # Write to multiple descriptors. 17 | setopt extended_glob # Use extended globbing syntax (#,~,^). 18 | setopt glob_dots # Don't hide dotfiles from glob patterns. 19 | setopt NO_clobber # Don't overwrite files with >. Use >| to bypass. 20 | setopt NO_rm_star_silent # Ask for confirmation for `rm *' or `rm path/*' 21 | 22 | # Set directory aliases. 23 | if ! zstyle -t ':zephyr:plugin:directory:alias' skip; then 24 | alias -- -='cd -' 25 | alias dirh='dirs -v' 26 | 27 | _dotdot=".." 28 | for _index in {1..9}; do 29 | alias "$_index"="cd -${_index}" # dirstack aliases (eg: "2"="cd -2") 30 | alias -g "..${_index}"="${_dotdot}" # backref aliases (eg: "..3"="../../..") 31 | _dotdot+="/.." 32 | done 33 | unset _dotdot _index 34 | fi 35 | 36 | # Quickly go up any number of directories. 37 | function up { 38 | local parents="${1:-1}" 39 | if [[ ! "$parents" -gt 0 ]]; then 40 | echo >&2 "usage: up []" 41 | return 1 42 | fi 43 | local dotdots=".." 44 | while (( --parents )); do 45 | dotdots+="/.." 46 | done 47 | cd "$dotdots" 48 | } 49 | 50 | #region MARK LOADED 51 | zstyle ':zephyr:plugin:directory' loaded 'yes' 52 | #endregion 53 | -------------------------------------------------------------------------------- /lib/bootstrap.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # bootstrap: Ensure Zephyr is properly boostrapped. 4 | # 5 | 6 | # Set ZEPHYR_HOME. 7 | 0=${(%):-%N} 8 | : ${ZEPHYR_HOME:=${0:a:h:h}} 9 | #endregion 10 | 11 | # Set critical Zsh options. 12 | setopt extended_glob interactive_comments 13 | 14 | # Set Zsh locations. 15 | typeset -gx __zsh_{config,cache,user_data}_dir 16 | : ${__zsh_config_dir:=${ZDOTDIR:-${XDG_CONFIG_HOME:-$HOME/.config}/zsh}} 17 | : ${__zsh_user_data_dir:=${XDG_DATA_HOME:-$HOME/.local/share}/zsh} 18 | : ${__zsh_cache_dir:=${XDG_CACHE_HOME:-$HOME/.cache}/zsh} 19 | mkdir -p $__zsh_config_dir $__zsh_user_data_dir $__zsh_cache_dir 20 | 21 | # There's not really a post_zshrc event, so we're going to fake one by adding a 22 | # function called run_post_zshrc to the precmd event. That function only runs once, 23 | # and then unregisters itself. If the user wants to (or needs to because it doesn't 24 | # play well with a plugin), they can run it themselves manually at the very end of 25 | # their .zshrc, and then it unregisters the precmd event. 26 | 27 | # Define a variable to hold actions run during the post_zshrc event. 28 | typeset -ga post_zshrc_hook 29 | 30 | # Add our new event. 31 | function run_post_zshrc { 32 | # Run anything attached to the post_zshrc hook 33 | local fn 34 | for fn in $post_zshrc_hook; do 35 | # Uncomment to debug: 36 | # echo "post_zshrc is about to run: ${=fn}" 37 | "${=fn}" 38 | done 39 | 40 | # Now delete the precmd hook and self-remove this function and its list var so 41 | # that it only runs once, and doesn't keep running on every future precmd event. 42 | add-zsh-hook -d precmd run_post_zshrc 43 | unfunction -- run_post_zshrc 44 | unset -- post_zshrc_hook 45 | } 46 | 47 | # Attach run_post_zshrc to built-in precmd. 48 | autoload -U add-zsh-hook 49 | add-zsh-hook precmd run_post_zshrc 50 | 51 | #region LOAD HELPERS 52 | zstyle -t ':zephyr:plugin:helper' loaded \ 53 | || source $ZEPHYR_HOME/plugins/helper/helper.plugin.zsh 54 | #endregion 55 | 56 | #region MARK LOADED 57 | zstyle ":zephyr:lib:bootstrap" loaded 'yes' 58 | #endregion 59 | -------------------------------------------------------------------------------- /plugins/helper/helper.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # helper: Common variables and functions used by Zephyr plugins. 4 | # 5 | #endregion 6 | 7 | # Make a directory from a variable name. 8 | function mkdirvar { 9 | emulate -L zsh 10 | local zdirvar 11 | for zdirvar in $@; do 12 | [[ -d "${(P)zdirvar}" ]] || mkdir -p "$(P){zdirvar}" 13 | done 14 | } 15 | 16 | # Cache the results of an eval command 17 | function cached-eval { 18 | emulate -L zsh; setopt local_options extended_glob 19 | (( $# >= 2 )) || return 1 20 | 21 | : ${__zsh_cache_dir:=${XDG_CACHE_HOME:-$HOME/.cache}/zsh} 22 | local cmdname=$1; shift 23 | local cachefile=$__zsh_cache_dir/cached-eval/${cmdname}.zsh 24 | local -a cached=($cachefile(Nmh-20)) 25 | # If the file has no size (is empty), or is older than 20 hours re-gen the cache. 26 | if [[ ! -s $cachefile ]] || (( ! ${#cached} )); then 27 | mkdir -p ${cachefile:h} 28 | "$@" >| $cachefile 29 | fi 30 | source $cachefile 31 | } 32 | 33 | # Check if a file can be autoloaded by trying to load it in a subshell. 34 | function is-autoloadable { 35 | ( unfunction "$1"; autoload -U +X "$1" ) &> /dev/null 36 | } 37 | 38 | # Check if a name is a command, function, or alias. 39 | function is-callable { 40 | (( $+commands[$1] || $+functions[$1] || $+aliases[$1] || $+builtins[$1] )) 41 | } 42 | 43 | # Check whether a string represents "true" (1, y, yes, t, true, o, on). 44 | function is-true { 45 | [[ -n "$1" && "$1:l" == (1|y(es|)|t(rue|)|o(n|)) ]] 46 | } 47 | 48 | # OS checks. 49 | function is-macos { [[ "$OSTYPE" == darwin* ]] } 50 | function is-linux { [[ "$OSTYPE" == linux* ]] } 51 | function is-bsd { [[ "$OSTYPE" == *bsd* ]] } 52 | function is-cygwin { [[ "$OSTYPE" == cygwin* ]] } 53 | function is-termux { [[ "$OSTYPE" == linux-android ]] } 54 | 55 | # Check term family. 56 | function is-term-family { 57 | [[ $TERM = $1 || $TERM = $1-* ]] 58 | } 59 | 60 | # Check if tmux. 61 | function is-tmux { 62 | is-term-family tmux || [[ -n "$TMUX" ]] 63 | } 64 | 65 | #region MARK LOADED 66 | zstyle ':zephyr:plugin:helper' loaded 'yes' 67 | #endregion 68 | -------------------------------------------------------------------------------- /runcoms/zstyles.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | # 3 | # .zstyles - Set zstyle options for Zephyr and other plugins/features. 4 | # 5 | 6 | # 7 | # General 8 | # 9 | 10 | # Set case-sensitivity for completion, history lookup, etc. 11 | # zstyle ':zephyr:*:*' case-sensitive 'yes' 12 | 13 | # Set the Zephyr plugins to load (browse plugins). 14 | # The order matters. 15 | zstyle ':zephyr:load' plugins \ 16 | 'environment' \ 17 | 'editor' \ 18 | 'history' \ 19 | 'directory' \ 20 | 'color' \ 21 | 'utility' \ 22 | 'completion' \ 23 | 'prompt' 24 | 25 | # 26 | # Completions 27 | # 28 | 29 | # Set the entries to ignore in static '/etc/hosts' for host completion. 30 | # zstyle ':zephyr:plugin:completion:*:hosts' etc-host-ignores \ 31 | # '0.0.0.0' '127.0.0.1' 32 | 33 | # Set the preferred completion style. 34 | # zstyle ':zephyr:plugin:completion' compstyle 'zephyr' 35 | 36 | # 37 | # Editor 38 | # 39 | 40 | # Set the key mapping style to 'emacs' or 'vi'. 41 | zstyle ':zephyr:plugin:editor' key-bindings 'emacs' 42 | 43 | # Auto convert .... to ../.. 44 | # zstyle ':zephyr:plugin:editor' dot-expansion 'yes' 45 | 46 | # Use ^z to return background processes to foreground. 47 | # zstyle ':zephyr:plugin:editor' symmetric-ctrl-z 'yes' 48 | 49 | # Expand aliases to their actual command like Fish abbreviations. 50 | # zstyle ':zephyr:plugin:editor' glob-alias 'yes' 51 | 52 | # Set the default (magic) command when hitting enter on an empty prompt. 53 | # zstyle ':zephyr:plugin:editor' magic-enter 'yes' 54 | # zstyle ':zephyr:plugin:editor:magic-enter' command 'ls -lh .' 55 | # zstyle ':zephyr:plugin:editor:magic-enter' git-command 'git status -u .' 56 | 57 | # 58 | # History 59 | # 60 | 61 | # Set the file to save the history in when an interactive shell exits. 62 | # zstyle ':zephyr:plugin:history' histfile "${ZDOTDIR:-$HOME}/.zsh_history" 63 | 64 | # Set the maximum number of events stored in the internal history list. 65 | # zstyle ':zephyr:plugin:history' histsize 10000 66 | 67 | # Set the maximum number of history events to save in the history file. 68 | # zstyle ':zephyr:plugin:history' savehist 10000 69 | 70 | # 71 | # Prompt 72 | # 73 | 74 | # Set the prompt theme to load. 75 | # starship themes: zephyr, hydro, prezto 76 | zstyle ':zephyr:plugin:prompt' theme starship zephyr 77 | -------------------------------------------------------------------------------- /plugins/prompt/themes/zephyr.toml: -------------------------------------------------------------------------------- 1 | # 2 | # zephyr.toml - Zephyr default prompt theme 3 | # 4 | 5 | add_newline = false 6 | 7 | # A minimal left prompt 8 | format = """$python$directory$character""" 9 | 10 | # move the rest of the prompt to the right 11 | #right_format = """$status$git_branch${custom.git_status_dirty}$git_status""" 12 | right_format = """$status$cmd_duration$git_branch${custom.git_status_dirty}$git_status""" 13 | 14 | palette="wombat" 15 | 16 | # Define custom colors 17 | [palettes.tokyo_night] 18 | black = '#15161e' 19 | blue = '#7aa2f7' 20 | cyan = '#7dcfff' 21 | green = '#9ece6a' 22 | purple = '#bb9af7' 23 | red = '#f7768e' 24 | white = '#a9b1d6' 25 | yellow = '#e0af68' 26 | 27 | [palettes.tokyo_night_256] 28 | black = '16' 29 | blue = '111' 30 | cyan = '117' 31 | green = '149' 32 | purple = '141' 33 | red = '210' 34 | white = '146' 35 | yellow = '179' 36 | 37 | [palettes.wombat] 38 | black = '#000000' 39 | blue = '#5da9f6' 40 | cyan = '#82fff7' 41 | green = '#b1e969' 42 | purple = '#e86aff' 43 | red = '#ff615a' 44 | white = '#dedacf' 45 | yellow = '#ebd99c' 46 | 47 | [palettes.wombat_256] 48 | black = '0' 49 | blue = '75' 50 | cyan = '123' 51 | green = '149' 52 | purple = '171' 53 | red = '203' 54 | white = '188' 55 | yellow = '223' 56 | 57 | [character] 58 | success_symbol = "[❯](purple)[❯](cyan)" 59 | error_symbol = "[❯](yellow)[❯](red)" 60 | vicmd_symbol = "[❮](purple)[❮](cyan)" 61 | 62 | [python] 63 | format = '[(\($virtualenv\) )]($style)' 64 | style = 'white' 65 | 66 | [directory] 67 | style = "blue" 68 | truncation_length = 1 69 | truncation_symbol = "" 70 | fish_style_pwd_dir_length = 1 71 | 72 | # right prompt uses left space padding 73 | [git_branch] 74 | format = ' [$branch]($style)' 75 | style = 'green' 76 | 77 | [git_status] 78 | format = '( [\[$ahead_behind$stashed\]]($style))' 79 | style = "cyan" 80 | stashed = "≡" 81 | ahead = "⇡${count}" 82 | behind = "⇣${count}" 83 | 84 | [custom.git_status_dirty] 85 | when = 'test -n "$(git status --porcelain 2>/dev/null)"' 86 | symbol = "•" 87 | style = "white" 88 | format="[$symbol]($style)" 89 | shell = ["sh"] 90 | 91 | [cmd_duration] 92 | format = ' [$duration]($style)' 93 | 94 | [line_break] 95 | disabled = true 96 | 97 | [status] 98 | disabled = false 99 | symbol = ' ✘' 100 | -------------------------------------------------------------------------------- /plugins/color/README.md: -------------------------------------------------------------------------------- 1 | # Color 2 | 3 | > Make the terminal more colorful 4 | 5 | ## Features 6 | 7 | This plugin adds the following features: 8 | 9 | | feature | description | 10 | | --------------------------- | ------------------------------------------------------- | 11 | | autoload `colors` | Includes Zsh built in [colors][colors] | 12 | | colorize man pages | Running man now shows docs in color | 13 | | colorize `ls` | Uses `dircolors` if found to set `LSCOLORS`/`LS_COLORS` | 14 | | add color flags to commands | Add colors for `grep`, `ls`, and `diff` commands | 15 | | colorize completions | Add zstyles for list-colors | 16 | 17 | ## Aliases 18 | 19 | This plugin adds/modifies the following aliases: 20 | 21 | | alias | description | 22 | | ---------- | ----------------------------------------- | 23 | | `diff` | Adds `--color` flag | 24 | | `grep` | Adds `--color=auto` flag | 25 | | `ls` | Adds `--color=auto` flag | 26 | | `colormap` | Show a colormap with terminal color codes | 27 | 28 | ## Variables 29 | 30 | This plugin sets the following variables: 31 | 32 | | variable | description | 33 | | ----------------- | ----------------------------- | 34 | | `LESS_TERMCAP_md` | start less bold style | 35 | | `LESS_TERMCAP_mb` | start less blink style | 36 | | `LESS_TERMCAP_so` | start less standout style | 37 | | `LESS_TERMCAP_us` | start less underline style | 38 | | `LESS_TERMCAP_se` | end less standout style | 39 | | `LESS_TERMCAP_ue` | end less underline style | 40 | | `LESS_TERMCAP_me` | end less bold/blink style | 41 | | `LS_COLORS` | ls colors for GNU systems | 42 | | `LSCOLORS` | ls colors for BSD systems | 43 | | `CLICOLOR` | Enable colors for BSD systems | 44 | 45 | ## Customizations 46 | 47 | This plugin allows for the following customizations: 48 | 49 | To cache the results of the `dircolors` call, you can set: 50 | 51 | `zstyle ':zephyr:plugin:color' 'use-cache' 'yes'` 52 | 53 | To always use caching to speed up expensive calls, you can set: 54 | 55 | `zstyle ':zephyr:plugin:*' 'use-cache' 'yes'` 56 | 57 | [colors]: https://zsh.sourceforge.io/Doc/Release/User-Contributions.html#index-colors 58 | -------------------------------------------------------------------------------- /plugins/color/color.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # color: Make the terminal more colorful. 4 | # 5 | #endregion 6 | 7 | # Return if requirements are not met. 8 | [[ "$TERM" != 'dumb' ]] || return 1 9 | ! zstyle -t ":zephyr:plugin:color" skip || return 0 10 | 11 | # Built-in zsh colors. 12 | autoload -Uz colors && colors 13 | 14 | # Colorize man pages. 15 | export LESS_TERMCAP_md=${LESS_TERMCAP_md:-$fg_bold[blue]} # start bold 16 | export LESS_TERMCAP_mb=${LESS_TERMCAP_mb:-$fg_bold[blue]} # start blink 17 | export LESS_TERMCAP_so=${LESS_TERMCAP_so:-$'\e[00;47;30m'} # start standout: white bg, black fg 18 | export LESS_TERMCAP_us=${LESS_TERMCAP_us:-$'\e[04;35m'} # start underline: underline magenta 19 | export LESS_TERMCAP_se=${LESS_TERMCAP_se:-$reset_color} # end standout 20 | export LESS_TERMCAP_ue=${LESS_TERMCAP_ue:-$reset_color} # end underline 21 | export LESS_TERMCAP_me=${LESS_TERMCAP_me:-$reset_color} # end bold/blink 22 | 23 | # Set LS_COLORS using (g)dircolors if found. 24 | if [[ -z "$LS_COLORS" ]]; then 25 | _dircolors_cmds=( 26 | $commands[dircolors](N) $commands[gdircolors](N) 27 | ) 28 | if (( $#_dircolors_cmds )); then 29 | if zstyle -t ':zephyr:plugin:color' 'use-cache'; then 30 | cached-eval "${_dircolors_cmds[1]:t}" "$_dircolors_cmds[1]" --sh 31 | else 32 | source <("$_dircolors_cmds[1]" --sh) 33 | fi 34 | fi 35 | unset _dircolors_cmds 36 | 37 | # Pick a reasonable default for LS_COLORS if it hasn't been set by this point. 38 | export LS_COLORS="${LS_COLORS:-di=34:ln=35:so=32:pi=33:ex=31:bd=1;36:cd=1;33:su=30;41:sg=30;46:tw=30;42:ow=30;43}" 39 | fi 40 | 41 | # Missing dircolors is a good indicator of a BSD system. Set LSCOLORS for macOS/BSD. 42 | if (( ! $+commands[dircolors] )); then 43 | # For BSD systems, set LSCOLORS. 44 | export CLICOLOR=${CLICOLOR:-1} 45 | export LSCOLORS="${LSCOLORS:-exfxcxdxbxGxDxabagacad}" 46 | fi 47 | 48 | # Set aliases. 49 | if ! zstyle -t ':zephyr:plugin:color:alias' skip; then 50 | # Print a simple colormap. 51 | alias colormap='for i in {0..255}; do print -Pn "%K{$i} %k%F{$i}${(l:3::0:)i}%f " ${${(M)$((i%6)):#3}:+"\n"}; done' 52 | 53 | # Set colors for grep. 54 | alias grep="${aliases[grep]:-grep} --color=auto" 55 | 56 | # Set colors for ls. 57 | alias ls="${aliases[ls]:-ls} --color=auto" 58 | if (( $+commands[gls] )); then 59 | alias gls="${aliases[gls]:-gls} --color=auto" 60 | fi 61 | 62 | # Set colors for diff. 63 | if command diff --color /dev/null{,} &>/dev/null; then 64 | alias diff="${aliases[diff]:-diff} --color" 65 | fi 66 | fi 67 | 68 | # Colorize completions. 69 | zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS} 70 | 71 | #region MARK LOADED 72 | zstyle ':zephyr:plugin:color' loaded 'yes' 73 | #endregion 74 | -------------------------------------------------------------------------------- /plugins/history/history.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # history: Set history options and define history aliases. 4 | # 5 | 6 | # References: 7 | # - https://github.com/sorin-ionescu/prezto/tree/master/modules/history 8 | # - https://github.com/ohmyzsh/ohmyzsh/blob/master/lib/history.zsh 9 | # - https://zsh.sourceforge.io/Doc/Release/Options.html#History 10 | 11 | 0=${(%):-%N} 12 | zstyle -t ':zephyr:lib:bootstrap' loaded || source ${0:a:h:h:h}/lib/bootstrap.zsh 13 | #endregion 14 | 15 | # Set Zsh options related to history. 16 | setopt bang_hist # Treat the '!' character specially during expansion. 17 | setopt extended_history # Write the history file in the ':start:elapsed;command' format. 18 | setopt hist_expire_dups_first # Expire a duplicate event first when trimming history. 19 | setopt hist_find_no_dups # Do not display a previously found event. 20 | setopt hist_ignore_all_dups # Delete an old recorded event if a new event is a duplicate. 21 | setopt hist_ignore_dups # Do not record an event that was just recorded again. 22 | setopt hist_ignore_space # Do not record an event starting with a space. 23 | setopt hist_reduce_blanks # Remove extra blanks from commands added to the history list. 24 | setopt hist_save_no_dups # Do not write a duplicate event to the history file. 25 | setopt hist_verify # Do not execute immediately upon history expansion. 26 | setopt inc_append_history # Write to the history file immediately, not when the shell exits. 27 | setopt NO_hist_beep # Don't beep when accessing non-existent history. 28 | setopt NO_share_history # Don't share history between all sessions. 29 | 30 | # Set the path to the default history file. 31 | if zstyle -s ':zephyr:plugin:history' histfile 'HISTFILE'; then 32 | # Make sure the user didn't store a HISTFILE with a leading '~'. 33 | HISTFILE="${~HISTFILE}" 34 | else 35 | if zstyle -T ':zephyr:plugin:history' use-xdg-basedirs; then 36 | HISTFILE="${__zsh_user_data_dir}/zsh_history" 37 | else 38 | HISTFILE="${ZDOTDIR:-$HOME}/.zsh_history" 39 | fi 40 | fi 41 | 42 | # Make sure the HISTFILE's directory exists. 43 | [[ -d "${HISTFILE:h}" ]] || mkdir -p "${HISTFILE:h}" 44 | 45 | # Set history file size. 46 | zstyle -s ':zephyr:plugin:history' savehist 'SAVEHIST' \ 47 | || SAVEHIST=100000 48 | 49 | # Set session history size. 50 | zstyle -s ':zephyr:plugin:history' histsize 'HISTSIZE' \ 51 | || HISTSIZE=20000 52 | 53 | # Set history aliases. 54 | if ! zstyle -t ':zephyr:plugin:history:alias' skip; then 55 | alias hist='fc -li' 56 | alias history-stat="history 0 | awk '{print \$2}' | sort | uniq -c | sort -n -r | head" 57 | fi 58 | 59 | #region MARK LOADED 60 | zstyle ':zephyr:plugin:history' loaded 'yes' 61 | #endregion 62 | -------------------------------------------------------------------------------- /plugins/directory/README.md: -------------------------------------------------------------------------------- 1 | # Directory 2 | 3 | > Set features related to Zsh directories and dirstack. 4 | 5 | ## Options 6 | 7 | This plugin sets the following Zsh options: 8 | 9 | | action | option | description | 10 | | -------- | ------------------------ | ------------------------------------------------------- | 11 | | setopt | [AUTO_PUSHD][16.2.1] | Make cd push the old directory onto the dirstack. | 12 | | setopt | [PUSHD_MINUS][16.2.1] | Exchanges meanings of +/- when navigating the dirstack. | 13 | | setopt | [PUSHD_SILENT][16.2.1] | Do not print the directory stack after pushd or popd. | 14 | | setopt | [PUSHD_TO_HOME][16.2.1] | Push to home directory when no argument is given. | 15 | | setopt | [EXTENDED_GLOB][16.2.3] | Use extended chars (#,~,^) in globbing patterns. | 16 | | setopt | [GLOB_DOTS][16.2.3] | Include dotfiles when globbing. | 17 | | unsetopt | [CLOBBER][16.2.6] | Don't overwrite files with >. Use >\| to bypass. | 18 | | unsetopt | [RM_STAR_SILENT][16.2.6] | Ask for confirmation for `rm *' or `rm path/\*' | 19 | | setopt | [MULTIOS][16.2.9] | Write to multiple descriptors. | 20 | 21 | ## Functions 22 | 23 | This plugin adds the following functions: 24 | 25 | | function | description | 26 | | ---------- | --------------------------------------- | 27 | | `up ` | Quickly go up any number of directories | 28 | 29 | ## Aliases 30 | 31 | This plugin adds/modifies the following aliases: 32 | 33 | | alias | description | 34 | | ------------- | ------------------------------------------------------------- | 35 | | `--` | `cd -`: dirstack navigation | 36 | | `dirh` | `dirs -v`: show the dirstack | 37 | | `..1` - `..9` | suffix alias to perform actions up the dir tree (eg `ls ..3`) | 38 | | `1` - `9` | `cd -9`: quickly navigate the dirstack | 39 | 40 | ## Variables 41 | 42 | This plugin sets no variables. 43 | 44 | ## Customizations 45 | 46 | To skip setting directory related aliases, you can set: 47 | 48 | `zstyle ':zephyr:plugin:directory:alias' 'skip' 'yes'` 49 | 50 | To always skip aliases, you can set: 51 | 52 | `zstyle ':zephyr:plugin:*:alias' 'skip' 'yes'` 53 | 54 | [16.2.1]: https://zsh.sourceforge.io/Doc/Release/Options.html#Changing-Directories 55 | [16.2.3]: https://zsh.sourceforge.io/Doc/Release/Options.html#Expansion-and-Globbing 56 | [16.2.6]: https://zsh.sourceforge.io/Doc/Release/Options.html#Input_002fOutput 57 | [16.2.9]: https://zsh.sourceforge.io/Doc/Release/Options.html#Scripts-and-Functions 58 | -------------------------------------------------------------------------------- /plugins/homebrew/homebrew.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # homebrew: Environment variables and functions for homebrew users. 4 | # 5 | 6 | # References: 7 | # - https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/brew 8 | # - https://github.com/sorin-ionescu/prezto/tree/master/modules/homebrew 9 | 10 | 0=${(%):-%N} 11 | zstyle -t ':zephyr:lib:bootstrap' loaded || source ${0:a:h:h:h}/lib/bootstrap.zsh 12 | #endregion 13 | 14 | # Return if requirements are not met. 15 | ! zstyle -t ":zephyr:plugin:homebrew" skip || return 0 16 | 17 | # Where is brew? 18 | # Setup homebrew if it exists on the system. 19 | typeset -aU _brewcmd=( 20 | $commands[brew] 21 | $HOME/.homebrew/bin/brew(N) 22 | $HOME/.linuxbrew/bin/brew(N) 23 | /opt/homebrew/bin/brew(N) 24 | /usr/local/bin/brew(N) 25 | # /home/linuxbrew/.linuxbrew/bin/brew(N) 26 | ) 27 | (( ${#_brewcmd} )) || return 1 28 | 29 | # brew shellenv 30 | if zstyle -t ':zephyr:plugin:homebrew' 'use-cache'; then 31 | cached-eval 'brew_shellenv' $_brewcmd[1] shellenv 32 | else 33 | source <($_brewcmd[1] shellenv) 34 | fi 35 | unset _brewcmd 36 | 37 | # Ensure user bins preceed homebrew in path. 38 | path=($prepath $path) 39 | 40 | # Default to no tracking. 41 | HOMEBREW_NO_ANALYTICS=${HOMEBREW_NO_ANALYTICS:-1} 42 | 43 | # Add brewed Zsh to fpath 44 | if [[ -d "$HOMEBREW_PREFIX/share/zsh/site-functions" ]]; then 45 | fpath+=("$HOMEBREW_PREFIX/share/zsh/site-functions") 46 | fi 47 | 48 | # Add keg-only completions to fpath 49 | zstyle -a ':zephyr:plugin:homebrew' 'keg-only-brews' '_kegonly' \ 50 | || _kegonly=(curl ruby sqlite) 51 | for _keg in $_kegonly; do 52 | fpath=($HOMEBREW_PREFIX/opt/${_keg}/share/zsh/site-functions(/N) $fpath) 53 | done 54 | unset _keg{,only} 55 | 56 | # Set aliases. 57 | if ! zstyle -t ':zephyr:plugin:homebrew:alias' skip; then 58 | alias brewup="brew update && brew upgrade && brew cleanup" 59 | alias brewinfo="brew leaves | xargs brew desc --eval-all" 60 | 61 | brewdeps() { 62 | emulate -L zsh; setopt local_options 63 | local bluify_deps=' 64 | BEGIN { blue = "\033[34m"; reset = "\033[0m" } 65 | { leaf = $1; $1 = ""; printf "%s%s%s%s\n", leaf, blue, $0, reset} 66 | ' 67 | brew leaves | xargs brew deps --installed --for-each | awk "$bluify_deps" 68 | } 69 | 70 | # Handle brew on multi-user Apple silicon. 71 | if [[ "$HOMEBREW_PREFIX" == /opt/homebrew ]]; then 72 | # Check for GNU coreutils stat 73 | if stat --version &>/dev/null; then 74 | _brew_owner="$(stat -c "%U" "$HOMEBREW_PREFIX" 2>/dev/null)" 75 | else 76 | _brew_owner="$(stat -f "%Su" "$HOMEBREW_PREFIX" 2>/dev/null)" 77 | fi 78 | if [[ -n "$_brew_owner" ]] && [[ "$(whoami)" != "$_brew_owner" ]]; then 79 | alias brew="sudo -Hu '$_brew_owner' brew" 80 | fi 81 | unset _brew_owner 82 | fi 83 | fi 84 | 85 | #region MARK LOADED 86 | zstyle ':zephyr:plugin:homebrew' loaded 'yes' 87 | #endregion 88 | -------------------------------------------------------------------------------- /plugins/utility/utility.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # utility: Misc Zsh shell options, utilities, and attempt at cross-platform conformity. 4 | # 5 | 6 | # References: 7 | # - https://github.com/sorin-ionescu/prezto/blob/master/modules/utility/init.zsh 8 | # - https://github.com/belak/zsh-utils/blob/main/utility/utility.plugin.zsh 9 | #endregion 10 | 11 | # Return if requirements are not met. 12 | [[ "$TERM" != 'dumb' ]] || return 1 13 | ! zstyle -t ":zephyr:plugin:utility" skip || return 0 14 | 15 | # Use built-in paste magic. 16 | autoload -Uz bracketed-paste-url-magic 17 | zle -N bracketed-paste bracketed-paste-url-magic 18 | autoload -Uz url-quote-magic 19 | zle -N self-insert url-quote-magic 20 | 21 | # Load more specific 'run-help' function from $fpath. 22 | (( $+aliases[run-help] )) && unalias run-help && autoload -Uz run-help 23 | alias help=run-help 24 | 25 | # Make ls more useful. 26 | if (( ! $+commands[dircolors] )) && [[ "$OSTYPE" != darwin* ]]; then 27 | # Group dirs first on non-BSD systems 28 | alias ls="${aliases[ls]:-ls} --group-directories-first" 29 | fi 30 | # Show human readable file sizes. 31 | alias ls="${aliases[ls]:-ls} -h" 32 | 33 | # Ensure python commands exist. 34 | if (( $+commands[python3] )) && ! (( $+commands[python] )); then 35 | alias python=python3 36 | fi 37 | if (( $+commands[pip3] )) && ! (( $+commands[pip] )); then 38 | alias pip=pip3 39 | fi 40 | 41 | # Ensure envsubst command exists. 42 | if ! (( $+commands[envsubst] )); then 43 | alias envsubst="python -c 'import os,sys;[sys.stdout.write(os.path.expandvars(l)) for l in sys.stdin]'" 44 | fi 45 | 46 | # Ensure hd (hex dump) command exists. 47 | if ! (( $+commands[hd] )) && (( $+commands[hexdump] )); then 48 | alias hd="hexdump -C" 49 | fi 50 | 51 | # Ensure open command exists. 52 | if ! (( $+commands[open] )); then 53 | if [[ "$OSTYPE" == cygwin* ]]; then 54 | alias open='cygstart' 55 | elif [[ "$OSTYPE" == linux-android ]]; then 56 | alias open='termux-open' 57 | elif (( $+commands[xdg-open] )); then 58 | alias open='xdg-open' 59 | fi 60 | fi 61 | 62 | # Ensure pbcopy/pbpaste commands exist. 63 | if ! (( $+commands[pbcopy] )); then 64 | if [[ "$OSTYPE" == cygwin* ]]; then 65 | alias pbcopy='tee > /dev/clipboard' 66 | alias pbpaste='cat /dev/clipboard' 67 | elif [[ "$OSTYPE" == linux-android ]]; then 68 | alias pbcopy='termux-clipboard-set' 69 | alias pbpaste='termux-clipboard-get' 70 | elif (( $+commands[wl-copy] && $+commands[wl-paste] )); then 71 | alias pbcopy='wl-copy' 72 | alias pbpaste='wl-paste' 73 | elif [[ -n $DISPLAY ]]; then 74 | if (( $+commands[xclip] )); then 75 | alias pbcopy='xclip -selection clipboard -in' 76 | alias pbpaste='xclip -selection clipboard -out' 77 | elif (( $+commands[xsel] )); then 78 | alias pbcopy='xsel --clipboard --input' 79 | alias pbpaste='xsel --clipboard --output' 80 | fi 81 | fi 82 | fi 83 | 84 | # Cross platform `sed -i` syntax. 85 | function sedi { 86 | # GNU/BSD 87 | sed --version &>/dev/null && sed -i -- "$@" || sed -i "" "$@" 88 | } 89 | 90 | #region MARK LOADED 91 | zstyle ':zephyr:plugin:utility' loaded 'yes' 92 | #endregion 93 | -------------------------------------------------------------------------------- /plugins/zfunctions/zfunctions.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # zfunctions: Autoload all function files from your $ZDOTDIR/functions directory. 4 | # 5 | 6 | 0=${(%):-%N} 7 | zstyle -t ':zephyr:lib:bootstrap' loaded || source ${0:a:h:h:h}/lib/bootstrap.zsh 8 | #endregion 9 | 10 | # Return if requirements are not met. 11 | ! zstyle -t ":zephyr:plugin:zfunctions" skip || return 0 12 | 13 | ##? autoload-dir - Autoload function files in directory 14 | function autoload-dir { 15 | local zdir 16 | local -a zautoloads 17 | for zdir in $@; do 18 | zdir="${zdir:A}" 19 | [[ -d "$zdir" ]] || continue 20 | fpath=("$zdir" $fpath) 21 | zautoloads=($zdir/*~_*(N.:t)) 22 | (( $#zautoloads > 0 )) && autoload -Uz $zautoloads 23 | done 24 | } 25 | 26 | ##? funcsave - Save a function 27 | function funcsave { 28 | emulate -L zsh; setopt local_options 29 | : ${ZFUNCDIR:=$__zsh_config_dir/functions} 30 | 31 | # check args 32 | if (( $# == 0 )); then 33 | echo >&2 "funcsave: Expected at least 1 args, got only 0." 34 | return 1 35 | elif ! typeset -f "$1" > /dev/null; then 36 | echo >&2 "funcsave: Unknown function '$1'." 37 | return 1 38 | elif [[ ! -d "$ZFUNCDIR" ]]; then 39 | echo >&2 "funcsave: Directory not found '$ZFUNCDIR'." 40 | return 1 41 | fi 42 | 43 | # make sure the function is loaded in case it's already lazy 44 | autoload +X "$1" > /dev/null 45 | 46 | # remove first/last lines (ie: 'function foo {' and '}') and de-indent one level 47 | type -f "$1" | awk 'NR>2 {print prev} {gsub(/^\t/, "", $0); prev=$0}' >| "$ZFUNCDIR/$1" 48 | } 49 | 50 | ##? funced - edit the function specified 51 | function funced { 52 | emulate -L zsh; setopt local_options 53 | : ${ZFUNCDIR:=$__zsh_config_dir/functions} 54 | 55 | # check args 56 | if (( $# == 0 )); then 57 | echo >&2 "funced: Expected at least 1 args, got only 0." 58 | return 1 59 | elif [[ ! -d "${ZFUNCDIR:A}" ]]; then 60 | echo >&2 "funced: Directory not found '$ZFUNCDIR'." 61 | return 1 62 | fi 63 | 64 | # new function definition: make a file template 65 | if [[ ! -f "$ZFUNCDIR/$1" ]]; then 66 | local -a funcstub 67 | funcstub=( 68 | "#\!/bin/zsh" 69 | "#function $1 {" 70 | "" 71 | "#}" 72 | "#$1 \"\$@\"" 73 | ) 74 | printf '%s\n' "${funcstub[@]}" > "$ZFUNCDIR/$1" 75 | autoload -Uz "$ZFUNCDIR/$1" 76 | fi 77 | 78 | # open the function file 79 | if [[ -n "$VISUAL" ]]; then 80 | $VISUAL "$ZFUNCDIR/$1" 81 | else 82 | ${EDITOR:-vim} "$ZFUNCDIR/$1" 83 | fi 84 | } 85 | 86 | ##? funcfresh - Reload an autoload function 87 | function funcfresh { 88 | if (( $# == 0 )); then 89 | echo >&2 "funcfresh: Expecting function argument." 90 | return 1 91 | elif ! (( $+functions[$1] )); then 92 | echo >&2 "funcfresh: Function not found '$1'." 93 | return 1 94 | fi 95 | unfunction $1 96 | autoload -Uz $1 97 | } 98 | 99 | # Set ZFUNCDIR. 100 | if [[ -z "$ZFUNCDIR" ]]; then 101 | zstyle -s ':zephyr:plugin:zfunctions' directory 'ZFUNCDIR' \ 102 | || ZFUNCDIR="$__zsh_config_dir/functions" 103 | ZFUNCDIR="${~ZFUNCDIR}" 104 | fi 105 | 106 | # Autoload ZFUNCDIR. 107 | if [[ -d "${ZFUNCDIR:A}" ]]; then 108 | autoload-dir ${ZFUNCDIR:A} ${ZFUNCDIR:A}/*(N) 109 | fi 110 | 111 | #region MARK LOADED 112 | zstyle ":zephyr:plugin:zfunctions" loaded 'yes' 113 | #endregion 114 | -------------------------------------------------------------------------------- /plugins/prompt/prompt.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # prompt: Set zsh prompt. 4 | # 5 | 6 | 0=${(%):-%N} 7 | zstyle -t ':zephyr:lib:bootstrap' loaded || source ${0:a:h:h:h}/lib/bootstrap.zsh 8 | #endregion 9 | 10 | # Support skipping this plugin - useful if loading everything through zephyr.zsh. 11 | ! zstyle -t ":zephyr:plugin:prompt" skip || return 0 12 | 13 | # Prompt options 14 | setopt prompt_subst # Expand parameters in prompt variables. 15 | #setopt transient_rprompt # Remove right prompt artifacts from prior commands. 16 | 17 | # Set 2 space indent for each new level in a multi-line script. This can then be 18 | # overridden by a prompt or plugin, but is a better default than Zsh's. 19 | PS2='${${${(%):-%_}//[^ ]}// / } ' 20 | 21 | # Wrap powerlevel10k prompt to support themes directory 22 | function prompt_p10k_setup { 23 | if [[ -n "$1" ]]; then 24 | local -a configs=($__zsh_config_dir/themes/$1.p10k.zsh(N)) 25 | (( $#configs )) && source $configs[1] 26 | fi 27 | prompt_powerlevel10k_setup 28 | } 29 | 30 | # Make starship work with built-in prompt system. 31 | function prompt_starship_setup { 32 | # When loaded through the prompt command, these prompt_* options will be enabled 33 | prompt_opts=(cr percent sp subst) 34 | 35 | # Set the starship config based on the argument if provided. 36 | if [[ -n "$1" ]]; then 37 | local -a configs=( 38 | "$__zsh_config_dir/themes/${1}.toml"(N) 39 | "${XDG_CONFIG_HOME:-$HOME/.config}/starship/${1}.toml"(N) 40 | "$ZEPHYR_HOME/plugins/prompt/themes/${1}.toml"(N) 41 | ) 42 | (( $#configs )) && export STARSHIP_CONFIG=$configs[1] 43 | fi 44 | 45 | # Initialize starship. 46 | if zstyle -t ':zephyr:plugin:prompt' 'use-cache'; then 47 | cached-eval 'starship-init-zsh' starship init zsh 48 | else 49 | source <(starship init zsh) 50 | fi 51 | } 52 | 53 | # Wrap promptinit. 54 | function promptinit { 55 | # Initialize real built-in prompt system. 56 | unfunction promptinit 57 | autoload -Uz promptinit && promptinit 58 | 59 | # Hook P10k into Zsh's prompt system. 60 | (( $+functions[prompt_powerlevel10k_setup] )) \ 61 | && prompt_themes+=( p10k ) \ 62 | || unfunction prompt_p10k_setup 63 | 64 | # Hook starship into Zsh's prompt system. 65 | (( $+commands[starship] )) \ 66 | && prompt_themes+=( starship ) \ 67 | || unfunction prompt_starship_setup 68 | 69 | # Keep prompt array sorted. 70 | prompt_themes=( "${(@on)prompt_themes}" ) 71 | 72 | # We can run promptinit early, and if we did we no longer need a post_zshrc hook. 73 | post_zshrc_hook=(${post_zshrc_hook:#run_promptinit}) 74 | } 75 | 76 | function run_promptinit { 77 | # Initialize the built-in prompt system. 78 | autoload -Uz promptinit && promptinit 79 | 80 | # Set the prompt if specified. 81 | local -a prompt_argv 82 | zstyle -a ':zephyr:plugin:prompt' theme 'prompt_argv' \ 83 | || prompt_argv=(starship zephyr) 84 | if [[ $TERM == (dumb|linux|*bsd*) ]]; then 85 | prompt 'off' 86 | elif (( $#prompt_argv > 0 )); then 87 | prompt "$prompt_argv[@]" 88 | fi 89 | } 90 | 91 | # Allow the user to bypass the promptinit deferral and run it immediately. 92 | # Otherwise, we hook run_promptinit to the custom post_zshrc event. 93 | if zstyle -t ':zephyr:plugin:prompt' immediate; then 94 | run_promptinit || return 1 95 | else 96 | post_zshrc_hook+=(run_promptinit) 97 | fi 98 | 99 | #region MARK LOADED 100 | zstyle ":zephyr:plugin:prompt" loaded 'yes' 101 | #endregion 102 | -------------------------------------------------------------------------------- /tests/test_confd.md: -------------------------------------------------------------------------------- 1 | # confd 2 | 3 | This README is validated using the excellent [clitest] testing framework. 4 | 5 | ## setup 6 | 7 | Here we need to handle test setup. 8 | 9 | ```zsh 10 | % source ./tests/__init__.zsh 11 | % t_setup 12 | % zstyle ':zephyr:plugin:confd' immediate 'yes' 13 | % 14 | ``` 15 | 16 | ## Test missing dir behavior 17 | 18 | If the .zshrc.d directory doesn't exist, then fail with a message: 19 | 20 | ```zsh 21 | % test -d $HOME/.zshrc.d || echo "$HOME/.zshrc.d does not exist" | substenv 22 | $HOME/.zshrc.d does not exist 23 | % source $PWD/plugins/confd/confd.plugin.zsh #=> --exit 1 24 | % 25 | ``` 26 | 27 | ## Test empty dir behavior 28 | 29 | ```zsh 30 | % mkdir -p $HOME/.zshrc.d 31 | % test -d $HOME/.zshrc.d && echo "$HOME/.zshrc.d now exists, but is empty" | substenv 32 | $HOME/.zshrc.d now exists, but is empty 33 | % source $PWD/plugins/confd/confd.plugin.zsh 2>&1 | substenv 34 | % echo ${#sourced_files} 35 | 0 36 | % 37 | ``` 38 | 39 | Cleanup: 40 | 41 | ```zsh 42 | % t_reset 43 | % 44 | ``` 45 | 46 | ## Test directory selection 47 | 48 | Test selection of dirs from `$HOME`. 49 | 50 | Setup: 51 | 52 | ```zsh 53 | % zstyle ':zephyr:plugin:confd' directory $HOME/.myrc.d 54 | % ZDOTDIR=$HOME/.zsh 55 | % rcdirs=($HOME/.myrc.d $HOME/.zshrc.d) 56 | % rcdirs+=($ZDOTDIR/rc.d $ZDOTDIR/conf.d $ZDOTDIR/zshrc.d $ZDOTDIR/.zshrc.d) 57 | % mkdir -p $rcdirs 58 | % for rcd in $rcdirs; touch $rcd/rcfile.zsh 59 | % 60 | ``` 61 | 62 | If we set the `zstyle` it always overrides everything: 63 | 64 | ```zsh 65 | % alias source="t_mock_source" # from now on, use '.' to source for real 66 | % . $PWD/plugins/confd/confd.plugin.zsh | substenv 67 | mock sourcing file... $HOME/.myrc.d/rcfile.zsh 68 | % rm -rf -- $HOME/.myrc.d 69 | % # Now that the zstyle dir is missing, it should fail if the var is still set 70 | % . $PWD/plugins/confd/confd.plugin.zsh #=> --exit 1 71 | % zstyle -e ':zephyr:plugin:confd' directory 72 | % 73 | ``` 74 | 75 | Next, `$ZDOTDIR`, should override `$HOME` in this order: 76 | 77 | - `$ZDOTDIR/zshrc.d` 78 | - `$ZDOTDIR/conf.d` 79 | - `$ZDOTDIR/rc.d` 80 | - `$ZDOTDIR/.zshrc.d` 81 | 82 | ```zsh 83 | % confd_plugin=$PWD/plugins/confd/confd.plugin.zsh 84 | % . $confd_plugin | substenv ZDOTDIR 85 | mock sourcing file... $ZDOTDIR/conf.d/rcfile.zsh 86 | % rm -rf -- $HOME/.zsh/conf.d 87 | % . $confd_plugin | substenv ZDOTDIR 88 | mock sourcing file... $ZDOTDIR/zshrc.d/rcfile.zsh 89 | % rm -rf -- $HOME/.zsh/zshrc.d 90 | % . $confd_plugin | substenv ZDOTDIR 91 | mock sourcing file... $ZDOTDIR/rc.d/rcfile.zsh 92 | % rm -rf -- $HOME/.zsh/rc.d 93 | % . $confd_plugin | substenv ZDOTDIR 94 | mock sourcing file... $ZDOTDIR/.zshrc.d/rcfile.zsh 95 | % rm -rf -- $HOME/.zsh/.zshrc.d 96 | % unset ZDOTDIR 97 | % 98 | ``` 99 | 100 | Finally, `$HOME/.zshrc.d` is the default: 101 | 102 | ```zsh 103 | % . $PWD/plugins/confd/confd.plugin.zsh | substenv HOME 104 | mock sourcing file... $HOME/.zshrc.d/rcfile.zsh 105 | % rm -rf -- $HOME/.zshrc.d 106 | % 107 | ``` 108 | 109 | Cleanup: 110 | 111 | ```zsh 112 | % t_reset 113 | % 114 | ``` 115 | 116 | ## Test normal operation 117 | 118 | Setup: 119 | 120 | ```zsh 121 | % t_setup_rc_files 122 | % 123 | ``` 124 | 125 | Run: 126 | 127 | ```zsh 128 | % alias source="t_mock_source" # mock sourcing again 129 | % . $PWD/plugins/confd/confd.plugin.zsh | substenv 130 | mock sourcing file... $HOME/.zshrc.d/a.zsh 131 | mock sourcing file... $HOME/.zshrc.d/b.sh 132 | mock sourcing file... $HOME/.zshrc.d/b.zsh 133 | mock sourcing file... $HOME/.zshrc.d/c.sh 134 | mock sourcing file... $HOME/.zshrc.d/sym.zsh 135 | % unalias source 136 | % source $PWD/plugins/confd/confd.plugin.zsh | substenv 137 | sourced file: $HOME/.zshrc.d/a.zsh 138 | sourced file: $HOME/.zshrc.d/b.sh 139 | sourced file: $HOME/.zshrc.d/b.zsh 140 | sourced file: $HOME/.zshrc.d/c.sh 141 | sourced file: $HOME/foo.zsh 142 | % 143 | ``` 144 | 145 | ## Teardown 146 | 147 | Here we need to handle test teardown. 148 | 149 | ```zsh 150 | % t_teardown 151 | % 152 | ``` 153 | 154 | [clitest]: https://github.com/aureliojargas/clitest 155 | -------------------------------------------------------------------------------- /plugins/environment/environment.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # environment: Ensure common environment variables are set. 4 | # 5 | 6 | # References: 7 | # - https://github.com/sorin-ionescu/prezto/blob/master/modules/environment/init.zsh 8 | # - https://github.com/sorin-ionescu/prezto/blob/master/runcoms/zprofile 9 | 10 | 0=${(%):-%N} 11 | zstyle -t ':zephyr:lib:bootstrap' loaded || source ${0:a:h:h:h}/lib/bootstrap.zsh 12 | #endregion 13 | 14 | # Return if requirements are not met. 15 | ! zstyle -t ":zephyr:plugin:environment" skip || return 0 16 | 17 | # Set Zsh options related to globbing. 18 | setopt extended_glob # Use more awesome globbing features. 19 | setopt NO_rm_star_silent # Ask for confirmation for `rm *' or `rm path/*' 20 | 21 | # Set general Zsh options. 22 | setopt combining_chars # Combine 0-len chars with the base character (eg: accents). 23 | setopt interactive_comments # Enable comments in interactive shell. 24 | setopt rc_quotes # Allow 'Hitchhikers''s Guide' instead of 'Hitchhikers'\''s Guide'. 25 | setopt NO_mail_warning # Don't print a warning message if a mail file has been accessed. 26 | setopt NO_beep # Don't beep on error in line editor. 27 | 28 | # Set Zsh options related to job control. 29 | setopt auto_resume # Attempt to resume existing job before creating a new process. 30 | setopt long_list_jobs # List jobs in the long format by default. 31 | setopt notify # Report status of background jobs immediately. 32 | setopt NO_bg_nice # Don't run all background jobs at a lower priority. 33 | setopt NO_check_jobs # Don't report on jobs when shell exit. 34 | setopt NO_hup # Don't kill jobs on shell exit. 35 | 36 | # Set XDG base dirs. 37 | # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 38 | if zstyle -T ':zephyr:plugin:environment' use-xdg-basedirs; then 39 | export XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config} 40 | export XDG_CACHE_HOME=${XDG_CACHE_HOME:-$HOME/.cache} 41 | export XDG_DATA_HOME=${XDG_DATA_HOME:-$HOME/.local/share} 42 | export XDG_STATE_HOME=${XDG_STATE_HOME:-$HOME/.local/state} 43 | mkdir -p $XDG_CONFIG_HOME $XDG_CACHE_HOME $XDG_DATA_HOME $XDG_STATE_HOME 44 | fi 45 | 46 | # Editors 47 | export EDITOR=${EDITOR:-nano} 48 | export VISUAL=${VISUAL:-nano} 49 | export PAGER=${PAGER:-less} 50 | 51 | # Set browser. 52 | if [[ "$OSTYPE" == darwin* ]]; then 53 | export BROWSER=${BROWSER:-open} 54 | fi 55 | 56 | # Set language. 57 | export LANG=${LANG:-en_US.UTF-8} 58 | 59 | # Set the default Less options. 60 | # Mouse-wheel scrolling can be disabled with -X (disable screen clearing). 61 | # Add -X to disable it. 62 | if [[ -z "$LESS" ]]; then 63 | export LESS='-g -i -M -R -S -w -z-4' 64 | fi 65 | 66 | # Set the Less input preprocessor. 67 | # Try both `lesspipe` and `lesspipe.sh` as either might exist on a system. 68 | if [[ -z "$LESSOPEN" ]] && (( $#commands[(i)lesspipe(|.sh)] )); then 69 | export LESSOPEN="| /usr/bin/env $commands[(i)lesspipe(|.sh)] %s 2>&-" 70 | fi 71 | 72 | # Reduce key delay 73 | export KEYTIMEOUT=${KEYTIMEOUT:-1} 74 | 75 | # Make Apple Terminal behave. 76 | if [[ "$OSTYPE" == darwin* ]]; then 77 | export SHELL_SESSIONS_DISABLE=${SHELL_SESSIONS_DISABLE:-1} 78 | fi 79 | 80 | # Use `< file` to quickly view the contents of any file. 81 | [[ -z "$READNULLCMD" ]] || READNULLCMD=$PAGER 82 | 83 | # Ensure path arrays do not contain duplicates. 84 | typeset -gU cdpath fpath mailpath path 85 | 86 | # Add /usr/local/bin to path. 87 | path=(/usr/local/{,s}bin(N) $path) 88 | 89 | # Set the list of directories that Zsh searches for programs. 90 | if [[ ! -v prepath ]]; then 91 | typeset -ga prepath 92 | # If path ever gets out of order, you can use `path=($prepath $path)` to reset it. 93 | zstyle -a ':zephyr:plugin:environment' 'prepath' 'prepath' \ 94 | || prepath=( 95 | $HOME/{,s}bin(N) 96 | $HOME/.local/{,s}bin(N) 97 | ) 98 | fi 99 | path=( 100 | $prepath 101 | /opt/{homebrew,local}/{,s}bin(N) 102 | /usr/local/{,s}bin(N) 103 | $path 104 | ) 105 | 106 | #region MARK LOADED 107 | zstyle ':zephyr:plugin:environment' loaded 'yes' 108 | #endregion 109 | -------------------------------------------------------------------------------- /bin/zephyr: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ##? usage: zephyr 3 | # To check, run: shellcheck -e SC3043 -e SC2016 ./zephyr 4 | 5 | # Zsh can be POSIX too... with help. 6 | [ -n "$ZSH_VERSION" ] && setopt POSIX_ARGZERO 7 | 8 | # THIS_SCRIPT="$(realpath "$0")" 9 | ZEPHYR_HOME="$(realpath "$0"/../..)" 10 | 11 | # POSIX test for function existance. 12 | is_function() { 13 | [ "$#" -eq 1 ] || return 1 14 | type "$1" | sed "s/$1//" | grep -qwi function 15 | } 16 | 17 | ##? commands: 18 | ##? help Display this help 19 | zephyr_help() { 20 | # echo "$0" 21 | grep "^##?" "$0" | cut -c 5- 22 | } 23 | 24 | contains() {( 25 | while getopts "i" opt; do 26 | case "$opt" in 27 | i) o_index=1 ;; 28 | *) return 1 ;; 29 | esac 30 | done 31 | shift $(( OPTIND - 1 )) 32 | 33 | if [ "$#" -eq 0 ]; then 34 | echo >&2 "contains: key not specified" 35 | return 1 36 | fi 37 | 38 | key="$1"; shift 39 | index=0 40 | for val in "$@"; do 41 | index=$(( index + 1 )) 42 | if [ "$val" = "$key" ]; then 43 | [ -n "$o_index" ] && echo $index 44 | return 0 45 | fi 46 | done 47 | return 1 48 | )} 49 | 50 | print_start_region() { 51 | echo "#region $1" 52 | echo "#" 53 | } 54 | 55 | print_end_region() { 56 | echo "#" 57 | echo "#endregion" 58 | } 59 | 60 | ##? bulid1 Build the .zephyr1 file 61 | zephyr_build1() { 62 | local filter_regions squish_newlines anon_func_wrapper noop 63 | local tmpfile zephyr1_file plugin plugin_file 64 | tmpfile=$ZEPHYR_HOME/lib/.zephyr1.tmp 65 | zephyr1_file="$ZEPHYR_HOME/lib/.zephyr1" 66 | 67 | noop='{print $0}' 68 | 69 | filter_regions=' 70 | BEGIN { skip=0 } 71 | /^\#region/ { skip=1; next } 72 | /^\#endregion/ { skip=0; next } 73 | skip==0 { print } 74 | ' 75 | 76 | squish_newlines=' 77 | BEGIN { nl=0 } 78 | NF==0 { nl+=1 } 79 | NF>0 { nl=0 } 80 | nl<2 { print } 81 | ' 82 | 83 | anon_func_wrapper=' 84 | BEGIN { print ""; print "() {" } 85 | NF==0 { print $0; next } 86 | { print " " $0 } 87 | END { print "}"; print "" } 88 | ' 89 | 90 | { 91 | echo "#!/bin/zsh" 92 | echo "# .zshrc1" 93 | echo "# > First things first - start your .zshrc off right with Zephyr lite" 94 | echo "# Project Home: https://github.com/mattmc3/zephyr" 95 | echo 96 | 97 | print_start_region "bootstrap" 98 | awk "$filter_regions" "$ZEPHYR_HOME/lib/bootstrap.zsh" 99 | print_end_region 100 | print_start_region "helper" 101 | awk "$filter_regions" "$ZEPHYR_HOME/plugins/helper/helper.plugin.zsh" 102 | print_end_region 103 | } > "$tmpfile" 104 | 105 | for plugin in \ 106 | environment homebrew history directory color editor utility zfunctions \ 107 | prompt compstyle completion confd 108 | do 109 | plugin_file="$ZEPHYR_HOME/plugins/${plugin}/${plugin}.plugin.zsh" 110 | { 111 | print_start_region "$plugin" 112 | outfilter=$noop 113 | if contains "$plugin" color compstyle directory editor history homebrew utility zfunctions; then 114 | outfilter="$anon_func_wrapper" 115 | fi 116 | awk "$filter_regions" "$plugin_file" | tac | sed -e '/./,$!d' | tac | sed -e '/./,$!d' | awk "$outfilter" 117 | print_end_region 118 | } >> "$tmpfile" 119 | done 120 | 121 | { 122 | awk "$squish_newlines" "$tmpfile" 123 | echo 124 | echo "# vim: ft=zsh sw=2 ts=2 et" 125 | } > "$zephyr1_file" 126 | 127 | # Cleanup 128 | rm -f -- "$tmpfile" 129 | } 130 | 131 | # main zephyr command 132 | zephyr() { 133 | local subcmd 134 | if [ "$#" -eq 0 ]; then 135 | echo >&2 "zephyr: expecting a subcommand." 136 | echo 137 | zephyr_help 138 | return 1 139 | fi 140 | 141 | subcmd="$1" 142 | if [ "$subcmd" = "-h" ] || [ "$subcmd" = "--help" ]; then 143 | # Support -h/--help flags 144 | subcmd="help" 145 | else 146 | # Make kebab-case-subcommands work. 147 | subcmd=$(printf '%s' "$subcmd" | tr '-' '_') 148 | fi 149 | 150 | # Call the subcommand if it exists. 151 | if is_function "zephyr_${subcmd}"; then 152 | shift 153 | "zephyr_${subcmd}" "$@" 154 | else 155 | echo >&2 "zephyr: subcommand not found '$subcmd'." 156 | return 1 157 | fi 158 | } 159 | zephyr "$@" 160 | 161 | # vim: set sw=2 sts=2 ts=8 et: 162 | -------------------------------------------------------------------------------- /tests/__init__.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | ##? substenv - substitutes string parts with environment variables 3 | function substenv { 4 | local -a args=($@) 5 | (( $#args )) || args=(HOME) 6 | local -a sedargs=() 7 | local argv 8 | for argv in $args; do 9 | sedargs+=('-e' "s|${(P)argv}|\$${argv}|g") 10 | done 11 | sed -E "${sedargs[@]}" 12 | } 13 | 14 | function collect-input { 15 | local -a input=() 16 | if (( $# > 0 )); then 17 | input=("${(s.\n.)${@}}") 18 | elif [[ ! -t 0 ]]; then 19 | local data 20 | while IFS= read -r data || [[ -n "$data" ]]; do 21 | input+=("$data") 22 | done 23 | fi 24 | printf '%s\n' "${input[@]}" 25 | } 26 | 27 | function string-escape { 28 | local -a input=("${(@f)$(collect-input "$@")}") 29 | print -lr ${(qqqq)input[@]} | sed -e 's/\\033/\\e\\/g' -e 's/ /\\ /g' | tr -d "$'" 30 | } 31 | 32 | function t_setup { 33 | 0=${(%):-%x} 34 | 35 | # save zstyles, and clear them all for the test session 36 | typeset -ga T_PREV_ZSTYLES=( ${(@f)"$(zstyle -L ':zephyr:*')"} ) 37 | source <(zstyle -L ':zephyr:*' | awk '{print "zstyle -d",$2}') 38 | 39 | # Set everything to run immediately 40 | zstyle ':zephyr:plugin:*' immediate 'yes' 41 | 42 | # works with BSD and GNU gmktemp 43 | typeset -gx T_TEMPDIR=${$(mktemp -d -t t_zephyr.XXXXXXXX):A} 44 | typeset -gx OLD_HOME=$HOME 45 | typeset -gx HOME=$T_TEMPDIR 46 | mkdir -p $T_TEMPDIR/.zsh 47 | 48 | # save fpath, aliases, funcs, environment 49 | typeset -g T_PREV_FPATH=( $fpath ) 50 | typeset -ga T_PREV_ALIASES=( ${(k)aliases} ) 51 | typeset -ga T_PREV_FUNCS=( ${(k)functions} ) 52 | typeset -gA T_PREV_ZOPTS=( $(set -o) ) 53 | typeset -ga T_PREV_PARAMS=( $(typeset -px | awk -F '=' '{print $1}' | awk '{print $NF}') ) 54 | 55 | zsh -df -c "set -o" >| $T_TEMPDIR/zsh_default.opts 56 | } 57 | 58 | function t_teardown { 59 | # emulate -L zsh 60 | # setopt local_options 61 | 62 | # reset current session 63 | ZDOTDIR=$OLD_ZDOTDIR 64 | 65 | # reset Zsh opts 66 | local -A zopts=( $(set -o) ) 67 | local zopt zoptval 68 | for zopt zoptval in ${(kv)zopts}; do 69 | if [[ $T_PREV_ZOPTS[$zopt] != $zoptval ]]; then 70 | [[ $zoptval == on ]] && unsetopt $zopt || setopt $zopt 71 | fi 72 | done 73 | 74 | local aliasname 75 | for aliasname in ${(k)aliases}; do 76 | (( $T_PREV_ALIASES[(Ie)$aliasname] )) || unalias -- $aliasname 77 | done 78 | local funcname 79 | for funcname in ${(k)functions}; do 80 | (( $T_PREV_FUNCS[(Ie)$funcname] )) || unfunction -- $funcname 81 | done 82 | local paramname params=( $(typeset -px | awk -F '=' '{print $1}' | awk '{print $NF}') ) 83 | for paramname in $params; do 84 | (( $T_PREV_PARAMS[(Ie)$paramname] )) || unset $paramname 85 | done 86 | local -a globalvars=( 87 | post_zshrc 88 | post_zshrc_hook 89 | completion_styles 90 | completion_style 91 | key_info 92 | __zephyr_compdef_queue 93 | ) 94 | for varname in $globalvars; do 95 | unset $varname &>/dev/null 96 | done 97 | 98 | # restore original fpath 99 | fpath=( $T_PREV_FPATH ) 100 | 101 | # restore original zstyles 102 | source <(zstyle -L ':zephyr:*' | awk '{print "zstyle -d",$2}') 103 | source <(printf '%s\n' $T_PREV_ZSTYLES) 104 | 105 | # remove tempdir 106 | if [[ -d "$T_TEMPDIR" ]] && [[ ${T_TEMPDIR:A} =~ '/(var|tmp)/*' ]]; then 107 | rm -rf $T_TEMPDIR 108 | else 109 | echo "WARNING: \$T_TEMPDIR not found: '$T_TEMPDIR'" 110 | fi 111 | typeset -gx HOME=$OLD_HOME 112 | 113 | unset T_TEMPDIR OLD_HOME T_PREV_{ALIASES,FPATH,FUNCS,PARAMS,ZOPTS} 114 | } 115 | 116 | function t_reset { 117 | t_teardown 118 | t_setup 119 | } 120 | 121 | function t_mock_source { 122 | if (( $# == 0 )); then 123 | echo >&2 "mock source: not enough arguments" 124 | return 1 125 | fi 126 | local srcfile 127 | for srcfile in $@; do 128 | # if the file lives in $ZDOTDIR, don't really source it 129 | if [[ "$srcfile" =~ "$T_TEMPDIR/"* ]] then 130 | if [[ -r "$srcfile" ]]; then 131 | echo "mock sourcing file... $srcfile" 132 | else 133 | echo >&2 "mock source: no such file or directory: $srcfile" 134 | return 1 135 | fi 136 | else 137 | . "$srcfile" 138 | fi 139 | done 140 | } 141 | 142 | function t_setup_rc_files { 143 | local files=( 144 | # zsh files 145 | a.zsh 146 | b.zsh 147 | 148 | # sh files 149 | b.sh 150 | c.sh 151 | 152 | # skip files 153 | '.hidden.zsh' 154 | '~skipme.zsh' 155 | 'wrongshell.bash' 156 | ) 157 | 158 | local f fp 159 | for f in $files; do 160 | fp=${1:-$T_TEMPDIR/.zshrc.d}/${f} 161 | [[ -d "${fp:h}" ]] || mkdir -p ${fp:h} 162 | echo "echo 'sourced file:' '${fp}'" >| ${fp} 163 | done 164 | echo "echo 'sourced file:' '$T_TEMPDIR/foo.zsh'" >| $T_TEMPDIR/foo.zsh 165 | ln -s $T_TEMPDIR/foo.zsh ${1:-$T_TEMPDIR/.zshrc.d}/sym.zsh 166 | } 167 | -------------------------------------------------------------------------------- /plugins/zfunctions/README.md: -------------------------------------------------------------------------------- 1 | # zfunctions plugin 2 | 3 | Use a `$ZDOTDIR/functions` directory to store lazy-loaded zsh function files. 4 | 5 | This plugin is similar in concept to the [fish] functions directory. 6 | 7 | ## Description 8 | 9 | This plugin will enable a directory for you to store function files, and adds that directory to your zsh 'fpath' variable. 10 | Any file placed in this directory should contain the innards of a single function definition. 11 | These files will then be "lazy-loaded" by zsh into a function of the same name upon their first call. 12 | The lazy-loading functionality is a built-in feature of zsh called [function autoloading][zsh-autoload]. 13 | 14 | Your functions path by default is: `${ZDOTDIR:-$HOME/.config/zsh}/functions`. 15 | However, you can optionally override the path by setting the `$ZFUNCDIR` value: 16 | 17 | ```zsh 18 | ZFUNCDIR=/path/to/my/lazy/zfunctions 19 | ``` 20 | 21 | ## Features 22 | 23 | The following functions are defined by this plugin: 24 | 25 | | Functions | Arguments | Description | 26 | |:----------|:--------------|:-------------------------------------------------------| 27 | | funced | \ | edit the function specified | 28 | | funcsave | \ | save a function to your configured functions directory | 29 | 30 | **Note:** 31 | Additionally, the built-in zsh `functions` command will list all the zsh functions that are defined. 32 | The built-in `function` keyword will allow you to define a new function. 33 | 34 | ## Example 35 | 36 | First, make sure you have loaded the zfunctions plugin and started a new zsh session. 37 | You can verify that zfunctions is enabled by running the following: 38 | 39 | ```zsh 40 | $ (( $+functions[funcsave] )) && echo "zfunctions loaded" || echo "zfunctions not loaded" 41 | zfuncions loaded 42 | ``` 43 | 44 | Next, let's set a $ZFUNCDIR variable for our examples 45 | ```zsh 46 | ZFUNCDIR=${ZDOTDIR:-$HOME/.config/zsh}/functions 47 | ``` 48 | 49 | Now, let's make a quick function to test with called 'foo'. 50 | 51 | The 'foo' function should always print "bar" and sometimes also print "baz". 52 | 53 | From a zsh prompt, define this function: 54 | 55 | ```zsh 56 | # 'foo' with comments and custom formatting 57 | function foo() { 58 | # print bar 59 | echo "bar" 60 | # and sometimes baz 61 | if [[ $[${RANDOM}%2] -eq 0 ]]; then 62 | echo "baz" 63 | fi 64 | } 65 | ``` 66 | 67 | Next, we can save the function. 68 | 69 | ```zsh 70 | funcsave foo 71 | ``` 72 | 73 | Now you should have a function file called "foo" in `$ZFUNCDIR`. Let's verify: 74 | 75 | ```zsh 76 | cat $ZFUNCDIR/foo 77 | ``` 78 | 79 | Notice that the function was reformatted and also that only the function *internals* are saved to the "foo" file, not the function name definition 80 | (ie: the "`function foo() {`" part is purposely missing). 81 | 82 | ```zsh 83 | # contents of $ZFUNCDIR/foo 84 | echo "bar" 85 | if [[ $[${RANDOM}%2] -eq 0 ]] 86 | then 87 | echo "baz" 88 | fi 89 | ``` 90 | 91 | Run `zsh` to start a new zsh session to show how lazy loading works. 92 | 93 | ```zsh 94 | zsh 95 | ``` 96 | 97 | Now, check out the function definition for `foo` by using the `functions` 98 | built-in (notice the trailing "s" on the word function**s**): 99 | 100 | ```zsh 101 | functions foo 102 | ``` 103 | 104 | You should see this: 105 | 106 | ```zsh 107 | foo () { 108 | # undefined 109 | builtin autoload -XUz ~/.config/zsh/functions 110 | } 111 | ``` 112 | 113 | Now execute the `foo` function once (or do it a few times for fun): 114 | 115 | ```zsh 116 | # outputs bar, and sometimes baz 117 | $ foo 118 | bar 119 | $ foo 120 | bar 121 | baz 122 | $ foo 123 | bar 124 | ``` 125 | 126 | Now go back and run `functions foo` again and check out the results... 127 | The function definition is now filled in from the `foo` file in your `$ZFUNCDIR`. 128 | 129 | ```zsh 130 | foo() { 131 | echo "bar" 132 | if [[ $[${RANDOM}%2] -eq 0 ]] 133 | then 134 | echo "baz" 135 | fi 136 | } 137 | ``` 138 | 139 | You can edit the 'foo' function by using `funced`: 140 | 141 | ```zsh 142 | # edit the foo function 143 | funced foo 144 | 145 | # or, make a new one entirely 146 | funced bar 147 | ``` 148 | 149 | That's it! Note that you do not need to use `funcsave` or `funced` if you don't prefer to. 150 | Adding files to `$ZFUNCDIR` yourself is also an option. Just remember that your function 151 | files should be named without a file extension (ie: foo, not foo.zsh), and should not 152 | contain the function declaration part (ie: `function foo() {`). 153 | 154 | Here's a great first function to create called "up". 155 | Start by typing `funced up` and add this to the file: 156 | 157 | ```zsh 158 | ### $ZFUNCDIR/up 159 | # goes up any number of directories 160 | if [[ "$#" < 1 ]] ; then 161 | cd .. 162 | else 163 | local rpt=$(printf "%${1}s") 164 | local cdstr=${rpt// /..\/} 165 | cd $cdstr 166 | fi 167 | ``` 168 | 169 | Have fun building your zsh function library! 170 | 171 | [omz]: https://github.com/ohmyzsh/ohmyzsh 172 | [fish]: https://fishshell.com 173 | [zsh-autoload]: http://zsh.sourceforge.net/Doc/Release/Functions.html#Autoloading-Functions 174 | -------------------------------------------------------------------------------- /plugins/completion/completion.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # completion: Set up zsh completions. 4 | # 5 | 6 | # References: 7 | # - https://github.com/sorin-ionescu/prezto/blob/master/modules/completion/init.zsh#L31-L44 8 | # - https://github.com/sorin-ionescu/prezto/blob/master/runcoms/zlogin#L9-L15 9 | # - http://zsh.sourceforge.net/Doc/Release/Completion-System.html#Use-of-compinit 10 | # - https://gist.github.com/ctechols/ca1035271ad134841284#gistcomment-2894219 11 | # - https://htr3n.github.io/2018/07/faster-zsh/ 12 | 13 | 0=${(%):-%N} 14 | zstyle -t ':zephyr:lib:bootstrap' loaded || source ${0:a:h:h:h}/lib/bootstrap.zsh 15 | zstyle -t ':zephyr:plugin:compstyle' loaded || source $ZEPHYR_HOME/plugins/compstyle/compstyle.plugin.zsh 16 | #endregion 17 | 18 | # Return if requirements are not met. 19 | [[ "$TERM" != 'dumb' ]] || return 1 20 | ! zstyle -t ":zephyr:plugin:completion" skip || return 0 21 | 22 | # Set completion options. 23 | setopt always_to_end # Move cursor to the end of a completed word. 24 | setopt auto_list # Automatically list choices on ambiguous completion. 25 | setopt auto_menu # Show completion menu on a successive tab press. 26 | setopt auto_param_slash # If completed parameter is a directory, add a trailing slash. 27 | setopt complete_in_word # Complete from both ends of a word. 28 | setopt path_dirs # Perform path search even on command names with slashes. 29 | setopt NO_flow_control # Disable start/stop characters in shell editor. 30 | setopt NO_menu_complete # Do not autoselect the first completion entry. 31 | 32 | # Allow Fish-like user contributed completions. 33 | fpath=($__zsh_config_dir/completions(-/FN) $fpath) 34 | 35 | function run_compinit { 36 | emulate -L zsh 37 | setopt local_options extended_glob 38 | 39 | # Use ZSH_COMPDUMP for the completion file. 40 | typeset -g ZSH_COMPDUMP 41 | if [[ -z "$ZSH_COMPDUMP" ]]; then 42 | if zstyle -T ':zephyr:plugin:completion' use-xdg-basedirs; then 43 | ZSH_COMPDUMP=$__zsh_cache_dir/zcompdump 44 | else 45 | ZSH_COMPDUMP=$HOME/.zcompdump 46 | fi 47 | fi 48 | 49 | # Make sure ZSH_COMPDUMP's directory exists and doesnt' have a leading tilde. 50 | ZSH_COMPDUMP="${~ZSH_COMPDUMP}" 51 | [[ -d $ZSH_COMPDUMP:h ]] || mkdir -p $ZSH_COMPDUMP:h 52 | 53 | # `run_compinit -f` forces a cache reset. 54 | if [[ "$1" == (-f|--force) ]]; then 55 | shift 56 | [[ -r "$ZSH_COMPDUMP" ]] && rm -rf -- "$ZSH_COMPDUMP" 57 | fi 58 | 59 | # compinit flags: https://zsh.sourceforge.io/Doc/Release/Completion-System.html#Use-of-compinit 60 | # -C : Omit the check for new completion functions 61 | # -i : Ignore insecure directories in fpath 62 | # -u : Allow insecure directories in fpath 63 | # -d : Specify zcompdump file 64 | local -a compinit_flags=(-i) 65 | if zstyle -t ':zephyr:plugin:completion' 'disable-compfix'; then 66 | compinit_flags=(-u) 67 | fi 68 | compinit_flags+=(-d "$ZSH_COMPDUMP") 69 | 70 | # Initialize completions 71 | autoload -Uz compinit 72 | if zstyle -t ':zephyr:plugin:completion' 'use-cache'; then 73 | # Load and initialize the completion system ignoring insecure directories with a 74 | # cache time of 20 hours, so it should almost always regenerate the first time a 75 | # shell is opened each day. 76 | local zcompdump_cache=($ZSH_COMPDUMP(Nmh-20)) 77 | if (( $#zcompdump_cache )); then 78 | compinit -C $compinit_flags 79 | else 80 | compinit $compinit_flags 81 | touch "$ZSH_COMPDUMP" # Ensure timestamp updates to reset the cache timeout. 82 | fi 83 | else 84 | compinit $compinit_flags 85 | fi 86 | 87 | # Compile ZSH_COMPDUMP, if modified, in background to increase startup speed. 88 | { 89 | if [[ -s "$ZSH_COMPDUMP" && (! -s "${ZSH_COMPDUMP}.zwc" || "$ZSH_COMPDUMP" -nt "${ZSH_COMPDUMP}.zwc") ]]; then 90 | if command mkdir "${ZSH_COMPDUMP}.zwc.lock" 2>/dev/null; then 91 | zcompile "$ZSH_COMPDUMP" 92 | command rmdir "${ZSH_COMPDUMP}.zwc.lock" 2>/dev/null 93 | fi 94 | fi 95 | } &! 96 | } 97 | 98 | # Let's talk about compinit for a second... 99 | # compinit works by finding _completion files in your fpath. That means fpath needs to 100 | # be fully populated prior to calling it. But sometimes you need to call compdef before 101 | # fpath is done being populated (eg: plugins do this). compinit has big chicken-and-egg 102 | # problems. This code handles all those completion use-cases by wrapping compinit, 103 | # queueing any calls to compdef, and hooking the real call to compinit to Zephyr's 104 | # custom post_zshrc event. 105 | 106 | # Define compinit placeholder functions (compdef) so we can queue up calls. 107 | # That way when the real compinit is called, we can execute the queue. 108 | typeset -gHa __compdef_queue=() 109 | function compdef { 110 | (( $# )) || return 111 | local compdef_args=("${@[@]}") 112 | __compdef_queue+=("$(typeset -p compdef_args)") 113 | } 114 | 115 | # Wrap compinit temporarily so that when the real compinit call happens, the 116 | # queue of compdef calls is processed. 117 | function compinit { 118 | unfunction compinit compdef &>/dev/null 119 | autoload -Uz compinit && compinit "$@" 120 | 121 | # Apply all the queued compdefs. 122 | local typedef_compdef_args 123 | for typedef_compdef_args in $__compdef_queue; do 124 | eval $typedef_compdef_args 125 | compdef "$compdef_args[@]" 126 | done 127 | unset __compdef_queue 128 | 129 | # We can run compinit early, and if we did we no longer need a post_zshrc hook. 130 | post_zshrc_hook=(${post_zshrc_hook:#run_compinit}) 131 | } 132 | 133 | # Set the completion style 134 | zstyle -s ':zephyr:plugin:completion' compstyle 'zcompstyle' || zcompstyle=zephyr 135 | if (( $+functions[compstyle_${zcompstyle}_setup] )); then 136 | compstyle_${zcompstyle}_setup 137 | elif [[ "$zcompstyle" != none ]]; then 138 | compstyleinit 139 | compstyle ${zcompstyle} 140 | fi 141 | unset zcompstyle 142 | 143 | # Allow the user to bypass the compinit deferral and run it immediately. Otherwise, we 144 | # hook run_compinit to the custom post_zshrc event. 145 | if zstyle -t ':zephyr:plugin:completion' immediate; then 146 | run_compinit || return 1 147 | else 148 | post_zshrc_hook+=(run_compinit) 149 | fi 150 | 151 | #region MARK LOADED 152 | zstyle ':zephyr:plugin:completion' loaded 'yes' 153 | #endregion 154 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :wind_face: Zephyr 2 | 3 | > A Zsh framework as nice as a cool summer breeze 4 | 5 | Zsh is a wonderful shell, but out-of-the-box it needs a boost. That's where Zephyr comes 6 | in. 7 | 8 | Zephyr combines some of the best parts from [Prezto][prezto] and other Zsh frameworks, 9 | removes bloat and dependencies, and prioritizes speed and simplicity. 10 | 11 | Zephyr can be thought of as a fast, lightweight set of independent Zsh features, and is 12 | designed to be one of the first things you load to build your ideal Zsh config. 13 | 14 | Combine Zephyr with a [plugin manager][antidote] and some [awesome 15 | plugins](https://github.com/unixorn/awesome-zsh-plugins) and you'll have a powerful Zsh 16 | setup that rivals anything out there. 17 | 18 | ## Project goals 19 | 20 | Zephyr allows you to take an _a la carte_ approach to building your ideal Zsh 21 | configuration. Other Zsh frameworks are meant to be used wholesale and are not truly 22 | modular. Zephyr is different - each of its plugins works independently, and are designed 23 | to pair well with a modern Zsh plugin manager like [antidote]. Zephyr can be used in 24 | whole or in part, and plays nice with other popular plugins. Zephyr brings together core 25 | Zsh functionality that typically is not available elsewhere as standalone plugins - 26 | while favoring a build-your-own composable Zsh config. 27 | 28 | ## Prompt 29 | 30 | Zephyr comes with an (optional) [Starship][starship] prompt config. 31 | 32 | ![Zephyr Prompt][terminal-img] 33 | 34 | ## Install 35 | 36 | ### Using a Plugin manager 37 | 38 | If your plugin manager supports using sub-plugins, you can load Zephyr that way as well. 39 | 40 | [Antidote][antidote] is one such plugin manager. You can load only the parts of Zephyr you need like so: 41 | 42 | ```shell 43 | # .zsh_plugins.txt 44 | # pick only the plugins you want and remove the rest 45 | mattmc3/zephyr path:plugins/color 46 | mattmc3/zephyr path:plugins/completion 47 | mattmc3/zephyr path:plugins/compstyle 48 | mattmc3/zephyr path:plugins/confd 49 | mattmc3/zephyr path:plugins/directory 50 | mattmc3/zephyr path:plugins/editor 51 | mattmc3/zephyr path:plugins/environment 52 | mattmc3/zephyr path:plugins/history 53 | mattmc3/zephyr path:plugins/homebrew 54 | mattmc3/zephyr path:plugins/macos 55 | mattmc3/zephyr path:plugins/prompt 56 | mattmc3/zephyr path:plugins/utility 57 | mattmc3/zephyr path:plugins/zfunctions 58 | ``` 59 | 60 | ### Manually 61 | 62 | Add the following snippet to your `.zshrc`: 63 | 64 | ```zsh 65 | # Clone Zephyr. 66 | [[ -d ${ZDOTDIR:-~}/.zephyr ]] || 67 | git clone --depth=1 https://github.com/mattmc3/zephyr ${ZDOTDIR:-~}/.zephyr 68 | 69 | # Use zstyle to specify which plugins you want. Order matters. 70 | zephyr_plugins=( 71 | zfunctions 72 | directory 73 | editor 74 | history 75 | ) 76 | zstyle ':zephyr:load' plugins $zephyr_plugins 77 | 78 | # Source Zephyr. 79 | source ${ZDOTDIR:-~}/.zephyr/zephyr.zsh 80 | ``` 81 | 82 | ## Plugins 83 | 84 | - **color** - Make terminal things more colorful 85 | - **completion** - Load and initialize the built-in zsh completion system 86 | - **compstyle** - Load and initialize a completion style system 87 | - **confd** - Source a Fish-like `conf.d` directory 88 | - **directory** - Set options and aliases related to the dirstack and filesystem 89 | - **editor** - Override and fill in the gaps of the default keybinds 90 | - **environment** - Define common environment variables 91 | - **history** - Load and initialize the built-in zsh history system 92 | - **homebrew** - Functionality for users of Homebrew 93 | - **macos** - Functionality for macOS users 94 | - **prompt** - Load and initialize the built-in zsh prompt system 95 | - **utility** - Common shell utilities, aimed at making cross platform work less painful 96 | - **zfunctions** - Lazy load a Fish-like functions directory 97 | 98 | ## Customization 99 | 100 | Zephyr uses Zsh's zstyles to let you easily customize your config. Unlike environment variables which pollute your environment, zstyles make it easy to handle more robust configuration. 101 | 102 | **Reminder:** `zstyle` settings need to be set prior to loading Zepyr. 103 | 104 | The customizations are detailed below. 105 | 106 | ### Common 107 | 108 | To selectively load plugins when sourcing zephyr.plugin.zsh directly, use the `zstyle ':zephyr:load' plugins ...` array. Order matters. 109 | 110 | ```zsh 111 | zstyle ':zephyr:load' plugins \ 112 | environment \ 113 | homebrew \ 114 | color \ 115 | compstyle \ 116 | completion \ 117 | directory \ 118 | editor \ 119 | helper \ 120 | history \ 121 | prompt \ 122 | utility \ 123 | zfunctions \ 124 | macos \ 125 | confd 126 | ``` 127 | 128 | To use your home directory instead of using [XDG Base Directories][xdg-base-dirs]: 129 | 130 | ```zsh 131 | zstyle ':zephyr:plugin:*' use-xdg-basedirs no 132 | ``` 133 | 134 | ### conf.d 135 | 136 | Change the confd directory used for conf.d: 137 | 138 | ```zsh 139 | ':zephyr:plugin:confd' directory ${HOME:-$ZDOTDIR}/.zshrc.d 140 | ``` 141 | 142 | ### editor 143 | 144 | Disable editor features with 'no'. Features are enabled by default: 145 | 146 | ```zsh 147 | zstyle ':zephyr:plugin:editor' 'prepend-sudo' yes 148 | zstyle ':zephyr:plugin:editor' 'glob-alias' no 149 | zstyle ':zephyr:plugin:editor' 'magic-enter' no 150 | zstyle ':zephyr:plugin:editor' 'pound-toggle' yes 151 | zstyle ':zephyr:plugin:editor' 'symmetric-ctrl-z' no 152 | ``` 153 | 154 | ### zfunctions 155 | 156 | Change the zfunctions directory: 157 | 158 | ```zsh 159 | ':zephyr:plugin:zfunctions' directory ${HOME:-$ZDOTDIR}/.zfuncs 160 | ``` 161 | 162 | ## Why don't you include... 163 | 164 | _Q: Why don't you include programming language plugins (eg: Python, Ruby)?_ \ 165 | **A:** These kinds of plugins can be very opinionated, and are in need of lots of upkeep 166 | from maintainers that use those languages. Language plugins are already available via 167 | Oh-My-Zsh and Prezto, and can always be installed with [a plugin manager that supports 168 | subplugins][antidote]. 169 | 170 | _Q: Why don't you also include popular plugins the way Prezto does (eg: 171 | zsh-autosuggestions, zsh-history-substring-search)?_ \ 172 | **A:** These kinds of utilities are already 173 | available as standalone plugins. Zephyr aims to include only core Zsh functionality that 174 | you can't already easily get via a [plugin manager][antidote], with a few exceptions for 175 | convenience. I have experimented with including submodules similar to Prezto, but was 176 | not happy with the result. Simpler is better. 177 | 178 | ## Credits 179 | 180 | Zephyr is a derivative work of the following great projects: 181 | 182 | - [Prezto][prezto] - [MIT License][prezto-license] 183 | - [zsh-utils][zsh-utils] - [MIT License][zsh-utils-license] 184 | - [Oh-My-Zsh][ohmyzsh] - [MIT License][ohmyzsh-license] 185 | 186 | [antidote]: https://antidote.sh 187 | [ohmyzsh]: https://github.com/ohmyzsh/ohmyzsh 188 | [ohmyzsh-license]: https://github.com/ohmyzsh/ohmyzsh/blob/master/LICENSE.txt 189 | [prezto]: https://github.com/sorin-ionescu/prezto 190 | [prezto-license]: https://github.com/sorin-ionescu/prezto/blob/master/LICENSE 191 | [zsh-utils]: https://github.com/belak/zsh-utils 192 | [zsh-utils-license]: https://github.com/belak/zsh-utils/blob/main/LICENSE 193 | [terminal-img]: https://raw.githubusercontent.com/mattmc3/zephyr/resources/img/terminal.png 194 | [starship]: https://starship.rs 195 | [xdg-base-dirs]: https://specifications.freedesktop.org/basedir-spec/latest/ 196 | -------------------------------------------------------------------------------- /plugins/compstyle/compstyle.plugin.zsh: -------------------------------------------------------------------------------- 1 | #region HEADER 2 | # 3 | # completion: Set up system for Zsh completion styles similar to prompt system. 4 | # 5 | 6 | # References: 7 | # - https://github.com/zsh-users/zsh/blob/master/Functions/Prompts/promptinit 8 | 9 | 0=${(%):-%N} 10 | zstyle -t ':zephyr:lib:bootstrap' loaded || source ${0:a:h:h:h}/lib/bootstrap.zsh 11 | zstyle -t ':zephyr:plugin:compstyle' loaded && return 1 12 | #endregion 13 | 14 | # Return if requirements are not met. 15 | [[ "$TERM" != 'dumb' ]] || return 1 16 | ! zstyle -t ":zephyr:plugin:compstyle" skip || return 0 17 | 18 | function compstyle_zephyr_help { 19 | echo "A composite of the grml, prezto, and ohmyzsh completions." 20 | echo "You can invoke it with the following command:" 21 | echo 22 | echo " compstyle zephyr" 23 | echo 24 | echo "More information available at: https://github.com/mattmc3/zephyr" 25 | } 26 | 27 | function compstyle_zephyr_setup { 28 | # Pre-reqs. 29 | : ${__zsh_cache_dir:=${XDG_CACHE_HOME:-$HOME/.cache}/zsh} 30 | [[ -d $__zsh_cache_dir ]] || mkdir -p $__zsh_cache_dir 31 | 32 | # Standard style used by default for 'list-colors' 33 | LS_COLORS=${LS_COLORS:-'di=34:ln=35:so=32:pi=33:ex=31:bd=36;01:cd=33;01:su=31;40;07:sg=36;40;07:tw=32;40;07:ow=33;40;07:'} 34 | 35 | # Defaults. 36 | zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS} 37 | zstyle ':completion:*:default' list-prompt '%S%M matches%s' 38 | 39 | # Use caching to make completion for commands such as dpkg and apt usable. 40 | zstyle ':completion::complete:*' use-cache on 41 | zstyle ':completion::complete:*' cache-path "$__zsh_cache_dir/zcompcache" 42 | 43 | # Case-insensitive (all), partial-word, and then substring completion. 44 | if zstyle -t ':zephyr:plugin:compstyle:*' case-sensitive; then 45 | zstyle ':completion:*' matcher-list 'r:|=*' 'l:|=* r:|=*' 46 | setopt case_glob 47 | else 48 | zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|=*' 'l:|=* r:|=*' 49 | unsetopt case_glob 50 | fi 51 | 52 | # Group matches and describe. 53 | zstyle ':completion:*:*:*:*:*' menu select 54 | zstyle ':completion:*:matches' group 'yes' 55 | zstyle ':completion:*:options' description 'yes' 56 | zstyle ':completion:*:options' auto-description '%d' 57 | zstyle ':completion:*:corrections' format ' %F{red}-- %d (errors: %e) --%f' 58 | zstyle ':completion:*:descriptions' format ' %F{purple}-- %d --%f' 59 | zstyle ':completion:*:messages' format ' %F{green} -- %d --%f' 60 | zstyle ':completion:*:warnings' format ' %F{yellow}-- no matches found --%f' 61 | zstyle ':completion:*' format ' %F{blue}-- %d --%f' 62 | zstyle ':completion:*' group-name '' 63 | zstyle ':completion:*' verbose yes 64 | 65 | # Fuzzy match mistyped completions. 66 | zstyle ':completion:*' completer _complete _match _approximate 67 | zstyle ':completion:*:match:*' original only 68 | zstyle ':completion:*:approximate:*' max-errors 1 numeric 69 | 70 | # Increase the number of errors based on the length of the typed word. But make 71 | # sure to cap (at 7) the max-errors to avoid hanging. 72 | zstyle -e ':completion:*:approximate:*' max-errors 'reply=($((($#PREFIX+$#SUFFIX)/3>7?7:($#PREFIX+$#SUFFIX)/3))numeric)' 73 | 74 | # Don't complete unavailable commands. 75 | zstyle ':completion:*:functions' ignored-patterns '(_*|pre(cmd|exec))' 76 | 77 | # Array completion element sorting. 78 | zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters 79 | 80 | # Directories 81 | zstyle ':completion:*:*:cd:*' tag-order local-directories directory-stack path-directories 82 | zstyle ':completion:*:*:cd:*:directory-stack' menu yes select 83 | zstyle ':completion:*:-tilde-:*' group-order 'named-directories' 'path-directories' 'users' 'expand' 84 | zstyle ':completion:*' squeeze-slashes true 85 | zstyle ':completion:*' special-dirs .. 86 | 87 | # History 88 | zstyle ':completion:*:history-words' stop yes 89 | zstyle ':completion:*:history-words' remove-all-dups yes 90 | zstyle ':completion:*:history-words' list false 91 | zstyle ':completion:*:history-words' menu yes 92 | 93 | # Environment Variables 94 | zstyle ':completion::*:(-command-|export):*' fake-parameters ${${${_comps[(I)-value-*]#*,}%%,*}:#-*-} 95 | 96 | # Populate hostname completion. But allow ignoring custom entries from static 97 | # */etc/hosts* which might be uninteresting. 98 | zstyle -a ':zephyr:plugin:compstyle:*:hosts' etc-host-ignores '_etc_host_ignores' 99 | 100 | zstyle -e ':completion:*:hosts' hosts 'reply=( 101 | ${=${=${=${${(f)"$(cat {/etc/ssh/ssh_,~/.ssh/}known_hosts(|2)(N) 2> /dev/null)"}%%[#| ]*}//\]:[0-9]*/ }//,/ }//\[/ } 102 | ${=${(f)"$(cat /etc/hosts(|)(N) <<(ypcat hosts 2> /dev/null))"}%%(\#${_etc_host_ignores:+|${(j:|:)~_etc_host_ignores}})*} 103 | ${=${${${${(@M)${(f)"$(cat ~/.ssh/config 2> /dev/null)"}:#Host *}#Host }:#*\**}:#*\?*}} 104 | )' 105 | 106 | # Don't complete uninteresting users... 107 | zstyle ':completion:*:*:*:users' ignored-patterns \ 108 | adm amanda apache avahi beaglidx bin cacti canna clamav daemon \ 109 | dbus distcache dovecot fax ftp games gdm gkrellmd gopher \ 110 | hacluster haldaemon halt hsqldb ident junkbust ldap lp mail \ 111 | mailman mailnull mldonkey mysql nagios \ 112 | named netdump news nfsnobody nobody nscd ntp nut nx openvpn \ 113 | operator pcap postfix postgres privoxy pulse pvm quagga radvd \ 114 | rpc rpcuser rpm shutdown squid sshd sync uucp vcsa xfs '_*' 115 | 116 | # ... unless we really want to. 117 | zstyle '*' single-ignored show 118 | 119 | # Ignore multiple entries. 120 | zstyle ':completion:*:(rm|kill|diff):*' ignore-line other 121 | zstyle ':completion:*:rm:*' file-patterns '*:all-files' 122 | 123 | # Kill 124 | zstyle ':completion:*:*:*:*:processes' command 'ps -u $LOGNAME -o pid,user,command -w' 125 | zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#) ([0-9a-z-]#)*=01;36=0=01' 126 | zstyle ':completion:*:*:kill:*' menu yes select 127 | zstyle ':completion:*:*:kill:*' force-list always 128 | zstyle ':completion:*:*:kill:*' insert-ids single 129 | 130 | # Man 131 | zstyle ':completion:*:manuals' separate-sections true 132 | zstyle ':completion:*:manuals.(^1*)' insert-sections true 133 | zstyle ':completion:*:man:*' menu yes select 134 | 135 | # Media Players 136 | zstyle ':completion:*:*:mpg123:*' file-patterns '*.(mp3|MP3):mp3\ files *(-/):directories' 137 | zstyle ':completion:*:*:mpg321:*' file-patterns '*.(mp3|MP3):mp3\ files *(-/):directories' 138 | zstyle ':completion:*:*:ogg123:*' file-patterns '*.(ogg|OGG|flac):ogg\ files *(-/):directories' 139 | zstyle ':completion:*:*:mocp:*' file-patterns '*.(wav|WAV|mp3|MP3|ogg|OGG|flac):ogg\ files *(-/):directories' 140 | 141 | # Mutt 142 | if [[ -s "$HOME/.mutt/aliases" ]]; then 143 | zstyle ':completion:*:*:mutt:*' menu yes select 144 | zstyle ':completion:*:mutt:*' users ${${${(f)"$(<"$HOME/.mutt/aliases")"}#alias[[:space:]]}%%[[:space:]]*} 145 | fi 146 | 147 | # SSH/SCP/RSYNC 148 | zstyle ':completion:*:(ssh|scp|rsync):*' tag-order 'hosts:-host:host hosts:-domain:domain hosts:-ipaddr:ip\ address *' 149 | zstyle ':completion:*:(scp|rsync):*' group-order users files all-files hosts-domain hosts-host hosts-ipaddr 150 | zstyle ':completion:*:ssh:*' group-order users hosts-domain hosts-host users hosts-ipaddr 151 | zstyle ':completion:*:(ssh|scp|rsync):*:hosts-host' ignored-patterns '*(.|:)*' loopback ip6-loopback localhost ip6-localhost broadcasthost 152 | zstyle ':completion:*:(ssh|scp|rsync):*:hosts-domain' ignored-patterns '<->.<->.<->.<->' '^[-[:alnum:]]##(.[-[:alnum:]]##)##' '*@*' 153 | zstyle ':completion:*:(ssh|scp|rsync):*:hosts-ipaddr' ignored-patterns '^(<->.<->.<->.<->|(|::)([[:xdigit:].]##:(#c,2))##(|%*))' '127.0.0.<->' '255.255.255.255' '::1' 'fe80::*' 154 | } 155 | 156 | # Load with `autoload -Uz compstyleinit; compstyleinit'. 157 | # Type `compstyle -h' for help. 158 | function compstyleinit { 159 | typeset -gaU completion_styles 160 | typeset -ga completion_style 161 | completion_styles=(zephyr) 162 | 163 | function compstyleinit { 164 | emulate -L zsh; setopt extendedglob 165 | 166 | local name setupfn 167 | local -a match 168 | 169 | # Autoload all compstyle_*_setup functions in fpath. 170 | for setupfn in $^fpath/compstyle_*_setup(N); do 171 | if [[ $setupfn == */compstyle_(#b)(*)_setup ]]; then 172 | name="$match[1]" 173 | if [[ -r "$setupfn" ]]; then 174 | completion_styles=($completion_styles $name) 175 | autoload -Uz compstyle_${name}_setup 176 | else 177 | print "Cannot read '$setupfn' file containing completion styles." 178 | fi 179 | else 180 | print "Unexpect compstyle setup function '$setupfn'." 181 | fi 182 | done 183 | } 184 | 185 | function _compstyle_usage { 186 | emulate -L zsh; setopt extended_glob 187 | local -a usage=( 188 | 'Usage: compstyle [-l] [-h [